From: doug@foxtrot.ccmrc.ucsb.edu (Douglas Scott)
Subject: Gdb 4.6 bug report
Organization: GNUs Not Usenet
Distribution: gnu
Date: Wed, 22 Jul 1992 23:51:03 GMT

System:  Sun 4/330 Running SunOS 4.1
Compiler: gcc/g++ 2.2.2
Gdb version: 4.6, compiled with GCC_MANGLE_BUG flag
Problems:
1)  Gdb will not print value returned from overloaded operator [](int), claiming  
structure has no such component (see log).

2)  Gdb dumps core when attempting to print return value of a virtual function called  
from a reference to an object (see log).

Here is a log of two problems, followed by the code.  I
apologize for the length of the code, but it is an extract
from a 14,000 line program, and I couldnt take the time to
strip any more out of it.  If it is too long for you to deal
with, let me know, and I will try to extract the problem
part out. 


---
Douglas Scott                              (805)893-8352
Center for Computer Music Research and Composition
University of California, Santa Barbara
Internet: (NeXTMail ok)   <doug@foxtrot.ccmrc.ucsb.edu>

######################################################
(gdb) run
Starting program: /home/doug/C++/a.out 


Breakpoint 2, Request::retrieveValues (this=0xf7fffbb8, v=@0xf7fffb78)
    at testit.c:520
520                             v[valsReturned] = *(valueList->value());
(gdb) ptype v
type = class ValueArray {
  private:
    void *array;
    int length_;
    int offset;

  public:
    ValueArray(QueryValue *, int);
    struct QueryValue & operator[](int) const;
    int length(void) const;
} &
(gdb) print v[valsReturned]
Structure has no component named operator[].

######################################################
gdb a.out
GDB is free software and you are welcome to distribute copies of it
 under certain conditions; type "show copying" to see the conditions.
There is absolutely no warranty for GDB; type "show warranty" for details.
GDB 4.6, Copyright 1992 Free Software Foundation, Inc...
(gdb) break 291
Breakpoint 1 at 0x2a48: file testit.c, line 291.
(gdb) run
Starting program: /home/doug/C++/a.out 


Breakpoint 1, QueryValue::operator= (this=0xf7fffb88, rhs=@0x36040)
    at testit.c:291
291             set(rhs.value());
Warning: the current language does not match this frame.
(gdb) print rhs
$1 = (struct QueryValue &) @0x36040: {
    <QueryLabel> = {
      label_ = 0x36060, 

      _vptr$QueryLabel = 0x32340 <IntValue virtual table>
    }, 

    members of QueryValue: 

    checkFun = 0x3d64 <posNumsOnly(char)>, 

    legalValue = 0x3e24 <checkDouble(char *)>
  }
(gdb) ptype rhs
type = class QueryValue : public QueryLabel {
  protected:
    int (*checkFun)();
    int (*legalValue)();

  public:
    virtual ~QueryValue(void);
    QueryValue(const char *, int (*)(char), int (*)(const char *));
  protected:
    QueryValue(void);
  public:
    virtual char * value(void) const;
    virtual int intValue(void) const;
    virtual double doubleValue(void) const;
    virtual int set(const char *);
    int (*)() charCheckFunction(void);
  protected:
    void operator=(const QueryValue &);
  private:
    virtual int size(void);
} &
(gdb) print rhs.value()
Segmentation fault (core dumped)

tango> gdb ./gdb ~doug/C++/core
GDB is free software and you are welcome to distribute copies of it
 under certain conditions; type "show copying" to see the conditions.
There is absolutely no warranty for GDB; type "show warranty" for details.
GDB 4.6, Copyright 1992 Free Software Foundation, Inc...
Core was generated by `gdb'.
Program terminated with signal 11, Segmentation fault.
#0  0x13f88 in unpack_field_as_long (type=0x136518, valaddr=0xf4630 "", 

    fieldno=-16) at values.c:1222
1222      memcpy (&val, valaddr + bitpos / 8, sizeof (val));
Setting up the environment for debugging gdb.
Breakpoint 1 at 0x33bd4: file utils.c, line 274.
Breakpoint 2 at 0x4774: file main.c, line 1658.
(top-gdb) bt
#0  0x13f88 in unpack_field_as_long (type=0x136518, valaddr=0xf4630 "", 

    fieldno=-16) at values.c:1222
#1  0x137d8 in value_primitive_field (arg1=0xf4608, offset=170831022, 

    fieldno=-1, arg_type=0x136518) at values.c:863
#2  0x138a8 in value_field (arg1=0xf4608, fieldno=-1) at values.c:898
#3  0x13a04 in value_virtual_fn_field (arg1=0xf4608, f=0x136740, j=1271064, 

    type=0x136518) at values.c:971
#4  0x181d8 in search_struct_method (name=0xf44b0 "value", arg1=0xf4608, 

    args=0xf7fff6f4, offset=0, static_memfuncp=0xf7fff768, type=0x136518)
    at valops.c:1095
#5  0x18690 in value_struct_elt (argp=0xf7fff76c, args=0xf7fff6f4, 

    name=0xf44b0 "value", static_memfuncp=0xf7fff768, err=0x14928 "structure")
    at valops.c:1222
#6  0x15224 in evaluate_subexp (expect_type=0x0, exp=0xf4488, pos=0xf7fff7e4, 

    noside=EVAL_NORMAL) at eval.c:385
#7  0x148b4 in evaluate_expression (exp=0xf4488) at eval.c:142
#8  0x1fec4 in print_command_1 (exp=0xe600e "rhs.value()", inspect=0, 

    voidprint=1) at printcmd.c:752
#9  0x20020 in print_command (exp=0xe600e "rhs.value()", from_tty=1)
    at printcmd.c:803
#10 0x3930 in execute_command (p=0xe600e "rhs.value()", from_tty=1)
    at main.c:915
#11 0x3ae4 in command_loop () at main.c:976
#12 0x3734 in main (argc=2, argv=0xf7fffc54) at main.c:853


////////////////////////// source for gdb test //////////////////////////
#include <String.h>

typedef int (*CharCheckFun)(const char);
typedef int (*LegalValueFun)(const char *);

enum Response {
        Cancel = 0, Yes = 1, No = 2
};

class String;

struct QueryLabelInfo {
	char *label;
};

struct QueryButtonInfo {
	char *label;		// label for button
	Response response;	// behavior for this button (yes, no, cancel)
};

enum ValueType { None, VString, VInt, VDouble };

struct QueryValueInfo {
	ValueType type;
	char *label;
	char *defaultVal;
	CharCheckFun check;
	LegalValueFun legal;
};

struct QueryInfo {
	QueryLabelInfo *labelInfo;
	char *valueListLabel;
	QueryValueInfo *valueInfo;
	QueryButtonInfo *buttonInfo;
};

// base class for all query items, and also used for plain labels

class QueryLabel {
public:
	QueryLabel(const char *);
	virtual ~QueryLabel();
	const char* label();
private:
	String *label_;
};

// class for response buttons (confirm, cancel, etc.)

class QueryButton : public QueryLabel {
public:
	QueryButton(const char *, Response resp=Yes);
	virtual ~QueryButton();
	virtual Response response() { return response_; }
	virtual int set(Response r) { response_ = r; return 1; }
private:
	Response response_;
};

class ValueArray;

// class for querying string, int, or double values

class QueryValue : public QueryLabel {
public:
	QueryValue(const char *, CharCheckFun ccf, LegalValueFun lvf);
	virtual ~QueryValue();
	virtual const char* value() const = 0;
	virtual const int intValue()  const = 0;
	virtual const double doubleValue() const = 0;
	virtual int set(const char *) = 0;
	CharCheckFun charCheckFunction() { return checkFun; }
	void operator = (const QueryValue& rhs);
protected:
	QueryValue();
	CharCheckFun checkFun;
	LegalValueFun legalValue;
private:
	friend ValueArray;
	virtual int size() { return sizeof(*this); }
};

class StringValue : public QueryValue {
public:
	StringValue(const char *, const char *, CharCheckFun ccf, LegalValueFun lvf);
	StringValue(const char *value=0);
	virtual ~StringValue();
	virtual const char* value() const;
	virtual const int intValue() const;
	virtual const double doubleValue() const;
	virtual int set(const char *);
private:
	friend ValueArray;
	virtual int size() { return sizeof(*this); }
	String *string;
};

class IntValue : public QueryValue {
public:
	IntValue(const char *, const int, CharCheckFun ccf, LegalValueFun lvf);
	IntValue(int value=0);
	virtual ~IntValue();
	virtual const char* value() const;
	virtual const int intValue() const;
	virtual const double doubleValue() const;
	virtual int set(const char *);
private:
	friend ValueArray;
	virtual int size() { return sizeof(*this); }
	int value_;
};

class DoubleValue : public QueryValue {
public:
	DoubleValue(const char *, const double, CharCheckFun ccf, LegalValueFun  
lvf);
	DoubleValue(double value=0.0);
	virtual ~DoubleValue();
	virtual const char* value() const;
	virtual const int intValue() const;
	virtual const double doubleValue() const;
	virtual int set(const char *);
private:
	friend ValueArray;
	virtual int size() { return sizeof(*this); }
	double value_;
};

// this allows me to create a virtual array, i.e., it fixes the problem with
// the array index not adding the correct offset for the derived virtual class

class ValueArray {
public:
	ValueArray(QueryValue *qa, int len) : array(qa), length_(len) {
		offset = qa->size();
	}
	QueryValue & operator [] (int index) const {
		// check index and return reference to the base class
		index = index < length_ ? index : length_ - 1;
		return *((QueryValue *)(array + offset * index));
	}
	int length() const { return length_; }
private:
	void *array;	// raw pointer to beginning of array
	int length_;
	int offset;	// the proper size of each array element
};

class QueryLabel;

struct QueryLink {
	QueryLink(QueryLabel *q);
	virtual ~QueryLink();
	QueryLabel *element;
	QueryLink *next;
};

class String;

// linked list container/manipulator for QueryLabel and its derived classes

class QueryList {
public:
	QueryList(const char *lbl);
	virtual ~QueryList();
	void append(QueryLabel *);
	void start() { current = head; }
	int more() { return current != 0; }
	void next() { current = current->next; }
	const char *label();
	QueryLabel *value() { return current->element; }
private:
	QueryLink *tail();
private:
	String *listLabel;
	QueryLink *current;
	QueryLink *head;
};

class QueryButton;

class ButtonList : public QueryList {
public:
	ButtonList(const char *lbl=0) : (lbl ? lbl : "") {}
	virtual ~ButtonList() {}
	QueryButton *value() { return (QueryButton *) QueryList::value(); }
};

class QueryValue;

class ValueList : public QueryList {
public:
	ValueList(const char *lbl=0) : (lbl ? lbl : "") {}
	virtual ~ValueList() {}
	QueryValue *value() { return (QueryValue *) QueryList::value(); }
};

enum RequestType { AlertType, ConfirmerType, ChoiceType, InputType };

class DialogConstructor;
class ValueArray;

class Request {
	friend DialogConstructor;
public:
	Request() { init(); }
	Request(QueryInfo *);
	virtual ~Request();
	
	int hasLabels() { return labelList != 0; }
	int hasValues() { return valueList != 0; }
	int useBell() { return bell; }
	virtual RequestType type() { return InputType; } 
	// default
	void appendLabel(const char *);
	void appendValue(const char *, const char *value, CharCheckFun, 

		LegalValueFun);
	void appendValue(const char *, int value, CharCheckFun, 

		LegalValueFun);
	void appendValue(const char *, double value, CharCheckFun,
		LegalValueFun);
	void appendValue(ValueType, const char *, const char *,
		CharCheckFun ccf, LegalValueFun lvf);
	void appendButton(const char *, Response);
	void retrieveValues(ValueArray &v);
protected:
	virtual void createLabelList(QueryLabelInfo *);
	virtual void createValueList(const char *, QueryValueInfo *);
	virtual void createButtonList(QueryButtonInfo *);
	void setBell(int b) { bell = b; }
protected:
	QueryList *labelList;
	ValueList *valueList;
	ButtonList *buttonList;
private:
	void init();
private:
	int bell;	// flag for bell ring
};

QueryLabel::QueryLabel(const char* lbl) {
	 label_ = new String(lbl);
}

QueryLabel::~QueryLabel() {
	 delete label_;
}

const char*
QueryLabel::label() { return *label_; }

/////////

QueryButton::QueryButton(const char *lbl, Response r) : (lbl), response_(r) {}

QueryButton::~QueryButton() {}

/////////

// default functions for QueryValue

static int anychar(const char c) { return 1; }
static int anyvalue(const char *v) { return 1; }

QueryValue::QueryValue(const char* lbl, CharCheckFun ccf, LegalValueFun lvf)
	: (lbl), checkFun(ccf), legalValue(lvf) {}

QueryValue::QueryValue() : (""), checkFun(anychar), legalValue(anyvalue) {}

QueryValue::~QueryValue() {}

void
QueryValue::operator = (const QueryValue& rhs) {
	// this allows any of the derived classes to be assigned to any other
	// via use of character strings passed between virtual functions
	set(rhs.value());
}

/////////

StringValue::StringValue(const char *lbl, const char *s, CharCheckFun ccf,
		LegalValueFun lvf) : (lbl, ccf, lvf) {
	 string = new String(s ? s : "");
}

StringValue::StringValue(const char *value) {
	 string = new String(value ? value : "");
}

StringValue::~StringValue() {
	 delete string;
}

int
StringValue::set(const char *s) {
	register int good = 0;
	if(good = legalValue(s)) {
		*string = (s && strlen(s)) ? s : "0";
	}
	return good;
}

const char *
StringValue::value() const {
	return *string;
}

int
StringValue::intValue() const {
	return atoi(strlen(*string) > 0 ? *string : "0");
}

double
StringValue::doubleValue() const {
	return atof(strlen(*string) > 0 ? *string : "0");
}

IntValue::IntValue(const char *lbl, const int i, CharCheckFun ccf,
		LegalValueFun lvf) : (lbl, ccf, lvf), value_(i) {}

IntValue::IntValue(int value) : value_(value) {}

IntValue::~IntValue() {}

const char *
IntValue::value() const {
	static char string[64];
	sprintf(string, "%d", value_);
	return string;
}

int
IntValue::intValue() const {
	return value_;
}

double
IntValue::doubleValue() const {
	return value_;
}

int
IntValue::set(const char *s) {
	register int good = 0;
	if(good = legalValue(s)) {
		value_ = (s && strlen(s)) ? atoi(s) : 0;
	}
	return good;
}
	
DoubleValue::DoubleValue(const char *lbl, const double d, CharCheckFun ccf,
		LegalValueFun lvf) : (lbl, ccf, lvf), value_(d) {}
	
DoubleValue::DoubleValue(double value) : value_(value) {}

DoubleValue::~DoubleValue() {}

const char *
DoubleValue::value() const {
	static char string[128];
	sprintf(string, "%f", value_);
	return string;
}

int
DoubleValue::intValue() const {
	return int(value_);
}

double
DoubleValue::doubleValue() const {
	return value_;
}

int
DoubleValue::set(const char *s) {
	register int good = 0;
	if(good = legalValue(s)) {
		value_ = (s && strlen(s)) ? atof(s) : 0;
	}
	return good;
}

QueryLink::QueryLink(QueryLabel *q) {
	element = q;
	next = 0;
}

QueryLink::~QueryLink() { delete element; }


QueryList::QueryList(const char *label) {
	listLabel = new String(label);
	head = 0;
}

QueryList::~QueryList() {
	delete listLabel;
	start();
	while(current) {
		register QueryLink *next = current->next;
		delete current;
		current = next;
	}
}

QueryLink *
QueryList::tail() {
	start();
	while(current && current->next)
		current = current->next;
	return current;
}
	
void
QueryList::append(QueryLabel *q) {
	register QueryLink *link = new QueryLink(q);
	if(!head)
		head = link;
	else
		tail()->next = link;
	current = link;
}

const char *
QueryList::label() { return *listLabel; }

////////

Request::Request(QueryInfo *qinfo) {
	init();
	if(qinfo->labelInfo)
		createLabelList(qinfo->labelInfo);
	if(qinfo->valueInfo)
		createValueList(qinfo->valueListLabel, qinfo->valueInfo);
	if(qinfo->buttonInfo)
		createButtonList(qinfo->buttonInfo);
}

void
Request::init() {
	labelList = 0;
	valueList = 0;
	buttonList = 0;
	bell = 0;
}

Request::~Request() {
	delete labelList;
	delete valueList;
	delete buttonList;
}

void
Request::appendLabel(const char *lbl) {
	if(!labelList) labelList = new QueryList("");
	labelList->append(new QueryLabel(lbl));
}

void
Request::appendButton(const char *lbl, Response response) {
	if(!buttonList) buttonList = new ButtonList;
	buttonList->append(new QueryButton(lbl, response));
}

void
Request::appendValue(const char *label, const char *value, CharCheckFun ccf,
		LegalValueFun lvf) {
	if(!valueList) valueList = new ValueList;
	valueList->append(new StringValue(label, value, ccf, lvf));
}

void
Request::appendValue(const char *label, int value, CharCheckFun ccf,
		LegalValueFun lvf) {
	if(!valueList) valueList = new ValueList;
	valueList->append(new IntValue(label, value, ccf, lvf));
}

void
Request::appendValue(const char *label, double value, CharCheckFun ccf,
		LegalValueFun lvf) {
	if(!valueList) valueList = new ValueList;
	valueList->append(new DoubleValue(label, value, ccf, lvf));
}

void
Request::appendValue(ValueType type, const char *label, const char *defval,
		CharCheckFun ccf, LegalValueFun lvf) {
	if(!valueList) valueList = new ValueList;
	valueList->append(
	    type == VString ? new StringValue(label, defval, ccf, lvf)
	    : type == VInt ?  new IntValue(label, atoi(defval), ccf, lvf)
	    : 		      new DoubleValue(label, atof(defval), ccf, lvf)
	);
}

void
Request::retrieveValues(ValueArray &v) {
	int valsReturned = 0, nvals = v.length();
	if(hasValues()) {
		for(valueList->start();
				valueList->more() && valsReturned != nvals; 

				valueList->next(), ++valsReturned) {
			v[valsReturned] = *(valueList->value());
		}
	}
}
	
void
Request::createLabelList(QueryLabelInfo *qlist) {
	for(QueryLabelInfo *i = qlist; i->label != 0; i++) {
		appendLabel(i->label);
	}
}

void
Request::createButtonList(QueryButtonInfo *qbilist) {
	for(QueryButtonInfo *i = qbilist; i->label != None; i++) {
		appendButton(i->label, i->response);
	}
}

void
Request::createValueList(const char *vlistlabel, QueryValueInfo *qvilist) {
	valueList = new ValueList(vlistlabel);
	for(QueryValueInfo *i = qvilist; i->type != None; i++) {
		appendValue(i->type, i->label, i->defaultVal, i->check,
			i->legal);
	}
}

// here are the char test functions for checking user input

int
posIntsOnly(char c) {	// control chars and integers only
	return (iscntrl(c) || isdigit(c));
}

int
intsOnly(char c) {
	return (c == '-' || posIntsOnly(c));
}

int
posNumsOnly(char c) {	// control chars, '.',  and integers only
	return (c == '.' || posIntsOnly(c));
}

int
numsOnly(char c) {
	return (c == '.' || intsOnly(c));
}

int
checkDouble(char *s) {
	return 1;
}

static QueryButtonInfo defaultInputButtonInfo[] = {
        { "confirm", Yes },
        { "cancel", Cancel },
        { 0 }
};

main() {
	static QueryLabelInfo labels[] = {
		{ "Set Endpoints for Horizontal Display: " }, { 0 }
	};
	static QueryInfo info[] = {
		labels, "", 0, defaultInputButtonInfo
	};
	int start = 0;
	int end = 50;
	// create and load a Request object with default values
	Request request(info);
	request.appendValue("Minimum Samp: ", start, posNumsOnly, checkDouble);
	request.appendValue("Maximum Samp: ", end, posNumsOnly, checkDouble);
	
	// normally at this point, the request object would be passed to a
	// dialog creation and display object that queries the user for input
	
	const int nvals = 2;
	IntValue vr[nvals];
	
	// now get the newly set values and load them into vr[]
	// (in this case they are still set to the default values)
	
	request.retrieveValues(ValueArray(vr, nvals));
	printf("Values retrieved are %d and %d\n",
		vr[0].intValue(), vr[1].intValue());
}

Newsgroups: gnu.gdb.bug