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