[gnu.g++.bug] Destructor Bug.

gordon%stats.ucl.ac.uk@NSS.CS.UCL.AC.UK ("Gordon Joly & Paul Otto @ UCL") (03/22/89)

------- Forwarded Message

The test program given in the shell archive below fails when run on
a SUN-3/75 [and SUN-3/160] running SunOS 3.4, using version 1.34.0
[and 1.34.1] of g++.

See the included READ_ME for a summary of what the program is intended
to test for - it will exit with a status of 1 and an error message when
it goes wrong.  (See the "log" included in the archive below.)  (By the
way, this prog has been slightly modified since you last saw it, so
that it exits when it notices an error.)

config.g++ sun3
Linked `config.h' to `xm-m68k.h'.
Linked `tm.h' to `tm-sun3+.h'.
Linked `md' to `m68k.md'.
Linked `aux-output.c' to `output-m68k.c'.
Links are now set up for use with a sun3.

- -------------------------------- cut here ----------------------------------
# This is a shell archive, shar, format file.
# To unarchive, feed this text into /bin/sh in the directory
# you wish the files to be in.

echo x - Makefile 1>&2
sed 's/^X//' > Makefile << 'End of Makefile'
X# to create & run "constructor/destructor" test for C++
X#
X# To run test, just utter "make" in this directory.
X#
X
X# filenames for errors
XEBC=errors-prob_bitwise_copying
XESEQ=errors-sequencing
X
XCC=g++				# use C++ compiler
XCFLAGS= -g
X
Xtests:	testing_prog check.awk
X	testing_prog 2> $(EBC) > calling_sequence
X	if [ -s $(EBC) ]; then cat $(EBC); exit 1; else rm $(EBC); fi
X	# calling seq check is only valid if previous check was OK
X	awk -f check.awk calling_sequence > $(ESEQ)
X	if [ -s $(ESEQ) ]; then cat $(ESEQ); exit 1; else rm $(ESEQ); fi
X	# rm calling_sequence
X	echo " - Passed test OK"
X	
Xtesting_prog: x.h x.o testing_prog.o
X	$(CC) $(CFLAGS) -o testing_prog testing_prog.o x.o
X
Xtesting_prog.o: x.h testing_prog.cc
X	$(CC) $(CFLAGS) -c testing_prog.cc 2> /dev/null	# ignore warning msgs
X
Xx.o:	x.h x.cc
X	$(CC) $(CFLAGS) -c x.cc
X
Xclean:
X	rm -f *.o core calling_sequence $(EBC) $(ESEQ)
X
Xclobber:	clean
X	rm -f testing_prog
End of Makefile
chmod u=,g=---,o= Makefile
echo x - NB 1>&2
sed 's/^X//' > NB << 'End of NB'
Xcheck that calling_sequence has suitable contents?  ie isn't null?
End of NB
chmod u=,g=---,o= NB
echo x - READ_ME 1>&2
sed 's/^X//' > READ_ME << 'End of READ_ME'
XSome simple tests which are intended to check for constructor/destructor
Xbugs.
X			G. P. Otto 16/11/87
X
XNB These tests are NOT exhaustive - they are merely designed to detect
Xbugs which are known to occur in some C++ compilers.
X
XIMPORTANT: At present, some of the code in the test prog is surrounded
Xwith "#ifndef pyr", because it uses features which are "not implemented"
Xon our current Pyramid C++ compiler.  If we get a new one, ought to try
Xcommenting these lines out!
X
X
XOVERVIEW OF TESTS:
X-----------------
X
XA simple class (x) is defined which has a full set of constructors,
Xinitializers etc defined (see page 180 of Stroustup's book), so that bitwise
Xcopying of objects is "completely avoided" (p 180 op cit), and so that
Xthe destructor should always be called before something goes out of
Xscope/ the program ends.
XThis class does two things:
X	(i) it prints a message on standard error every time a class
X		routine is called, printing "this" for the call;
X	(ii) it uses the class to store the value of "this" when an
X		instance/variable of the class is created, and
X		prints an error if any instance is later found to have
X		moved.
X
XThen there is a calling program (testing_prog.c) which uses this class
Xin a few ways known to be troublesome.  If bitwise copying occurs, then
Xan error should be detected & printed.  (The Makefile will put a copy
Xin "errors-prob_bitwise_copying".)
X
XA separate program (check.awk) is used to check the output of the
Xprogram to ensure that destructors are called exactly once for each
Xconstructor, & so forth.  (See the comments at the beginning of
Xcheck.awk.)  Any errors are put into "errors-sequencing".
X
XThis test could be tidied up considerably, but I'm not doing it now ...
End of READ_ME
chmod u=,g=---,o= READ_ME
echo x - check.awk 1>&2
sed 's/^X//' > check.awk << 'End of check.awk'
X# Check output from ctor/dtor test prog.
X#
X# Input is assumed to be a sequence of lines of the form:
X#	<routine-name> called; "this" = <address>
X#	
X# An error is reported if, for any given address, the routine calls do not
X# occur as in the following BNF:
X#		{ ctor-call other-call* dtor-call }*
X# (Constructor call includes initializers.)
X#
X# NB This awk script is relatively fragile - it does not validate its
X# input, or do any other such checks for errors in the testing programs
X# themselves.
X#						GPO 16/11/87
X#	Minor mod (to tidy up prog slightly)	GPO 24/11/87
X
X	{	if (($1 == "x::x()") || ($1 == "x::x(x&)")){	# ctor
X			if (status[$5] == "defined"){
X				print "ERROR: multiple use of address " $5 " on line " NR
X			} else {
X				status[$5] = "defined"
X			}
X		} else if ($1 == "x::~x()"){			# dtor
X			if (status[$5] != "defined"){
X				print "ERROR: dtor called for unit'ed address " $5 " on line " NR
X			} else {
X				status[$5] = "undefined"
X			}
X		} else {					# other
X			if (status[$5] != "defined"){
X				print "ERROR: routine using unit'ed address " $5 " on line " NR
X			}
X		}
X	}
XEND	{	for (a in status){	# check that all dtors have been called
X			if (status[a] == "defined"){
X				print "ERROR: address " a " has not been dtor'ed by end of prog"
X			}
X		}
X	}
End of check.awk
chmod u=,g=---,o= check.awk
echo x - log 1>&2
sed 's/^X//' > log << 'End of log'
XScript started on Wed Mar 22 07:47:51 1989
Xio% g++ -v
Xg++ version 1.34.0
Xio% make
Xg++                              -g -c x.cc
Xg++                              -g -c testing_prog.cc 2> /dev/null     # ignore warning msgs
Xg++                              -g -o testing_prog testing_prog.o x.o
Xtesting_prog 2> errors-prob_bitwise_copying > calling_sequence
X*** Error code 1
Xmake: Fatal error: Command failed for target `tests'
Xio% cat errors-prob_bitwise_copying
XERROR: address mismatch in call of x::~x(); class instance thought address was 0, but it was actually 251657348
Xio% ^D
Xscript done on Wed Mar 22 07:50:01 1989
End of log
chmod u=,g=---,o= log
echo x - testing_prog.cc 1>&2
sed 's/^X//' > testing_prog.cc << 'End of testing_prog.cc'
X#include "x.h"
X
X// first some routines to play with ...
X
Xx
Xf(x arg1, x arg2)
X{
X	x local1, local2, local3;
X
X	return local2;
X}
X
Xint
Xintf(x arg1, x arg2)
X{
X	x local1, local2, local3;
X
X	return 0;
X}
X
Xx
Xg()
X{
X	x local1, local2, local3;
X
X	return local2;
X}
X
Xx
Xh()
X{
X	x local1, local2, local3;
X
X	return local2;
X}
X
Xx
Xi(x arg)
X{
X	x local1, local2, local3;
X
X	return local2;
X}
X
X#ifndef pyr
Xx
Xdoubly_recursive(int depth_to_go)
X{
X	if (depth_to_go > 0){
X		return(f(doubly_recursive(depth_to_go-1),
X				doubly_recursive(depth_to_go-1)));
X	} else {
X		x local;
X		return(local);
X	}
X}
X#endif
X
X// Now call the routines & see what happens ...
Xint
Xmain()
X{
X	// test for calling of ctors & dtors on nested calls ...
X	{
X		x local;
X
X		local = f(g(),h());
X	}
X#ifndef pyr
X	// test for calling of ctors & dtors in recursive calls ...
X	doubly_recursive(3);
X#endif
X	// test for calling of ctors & dtors in nested calls occurring in
X	//  an expression
X	{
X		x a;
X		if (intf(i(g()),a))
X			7;
X	}
X	return 0;	// ought to return true status, but .....
X}
End of testing_prog.cc
chmod u=,g=---,o= testing_prog.cc
echo x - x.cc 1>&2
sed 's/^X//' > x.cc << 'End of x.cc'
X// noddy class for testing purposes
X//
X// BEWARE: This file relies on being able to coerce a class pointer into
X// a long so that it can be printed.
X
X#include "x.h"
X#include <stream.h>
X
Xstatic void
Xtell_world(char * who, x* address)
X{
X	cout << who << " called; \"this\" = " << (long) address << "\n";
X	// Might be more convenient when debugging to use stderr, so that
X	//  stays in sync with error messages - but test makefile assumes
X	//  stdout.
X}
X
Xstatic void
Xerror_address_mismatch(char* routine, x* says, x* actual)
X{
X	cerr << "ERROR: address mismatch in call of " << routine
X		<< "; class instance thought address was " << (long) says
X		<< ", but it was actually " << (long) actual << "\n";
X	extern void exit(int);		// can't rely on any particular header file!
X	exit(1);
X}
X
Xx::x()
X{
X	tell_world("x::x()",this);
X	self = this;
X}
X
Xx::x(x& xref)
X{
X	tell_world("x::x(x&)",this);
X	self = this;
X	if (xref.self != &xref)
X		error_address_mismatch("x::x(x&)",xref.self,&xref);
X}
X
Xx&
Xx::operator=(x& rhs)
X{
X	tell_world("x::operator=(x&)",this);
X	if (rhs.self != &rhs)
X		error_address_mismatch("x::operator=(x&)",rhs.self,&rhs);
X	if (self != this)
X		error_address_mismatch("x::operator=(x&)",self,this);
X	return(*this);
X}
X
Xx::~x()
X{
X	tell_world("x::~x()",this);
X	if (self != this)
X		error_address_mismatch("x::~x()",self,this);
X}
End of x.cc
chmod u=,g=---,o= x.cc
echo x - x.h 1>&2
sed 's/^X//' > x.h << 'End of x.h'
X// simplest class which completely avoids bitwise copying.
X// good for testing calling of constructors and destructors.
X
Xclass x {
X	class x* self;	// Note own address for testing/debugging purposes
Xpublic:
X	x();
X	x(x&);
X	x& operator=(x&);
X	~x();
X};
End of x.h
chmod u=,g=---,o= x.h

------- End of Forwarded Message