From: Bruno H. <ha...@il...> - 2002-12-20 13:29:20
|
Hi, I've added to the CVS the GC-safety checker. How to use it: 1) "CC=g++ configure". You must use a C++ compiler for this feature because the checker needs to insert some additional code everytime someone does an assignment between 'object' variables in the heap and in registers. The C++ compiler is the perfect tool for doing this. 2) After the Makefile is generated, add "-DDEBUG_GCSAFETY -DNO_GENERATIONAL_GC -DNO_TYPECODES" to the CFLAGS. The NO_GENERATIONAL_GC is because I didn't bother to make it work with generational GC - it doesn't matter, and generational GC is a pain anyway when you start running clisp under gdb. The NO_TYPECODES is because I haven't tested the patch with TYPECODES. (The only 32-bit platform I have available for testing TYPECODES is FreeBSD, and the g++ with which is comes gives internal compiler errors.) 3) Build clisp, and run your program with it. If it aborts, you have found a GC-safety bug. 4) To debug this GC-safety bug, add -g and remove the optimization options from the CFLAGS (because the C backtraces that gdb produces are not very useful when there are inline functions, therefore remove -O2 in order to make all calls notinline). Then rebuild clisp, run your program with it, under gdb, and when the program aborts, compare - the global variable alloccount, - the allocstamp fields of the 'object's involved. If an 'object' has an allocstamp that is < alloccount, and this object is not an immediate object (fixnum, short-float, machine, subr etc.) and not a constant symbol (one of these: S(nil), S(t), etc.), then you have found the GC-safety bug. The fix is to store this object temporarily on the STACK where it is GC-safe. What it will detect: - If you pass the address of an 'object' in registers to a function that expects an 'object' on the STACK (a.k.a. 'gcv_object_t'), then you will get a compile time error. - If you call a function that does some memory allocation and then use an 'object' that was in registers (i.e. not in a GC-safe location) during that time, you will get a crash at runtime. What it will not detect: - If you call a function that is marked as "can trigger GC" but does no memory allocation in this particular case, and then use an 'object' that was in registers, this will not be noticed. - Undefined behaviour: Car(STACK_0) = allocate_cons(); Here the C compiler is free to evaluate STACK_0 and allocate_cons() in arbitrary order. If the compiler evaluates allocate_cons() before STACK_0, DEBUG_GCSAFETY will not detect anything. But the bug is still there: another compiler could evaluate STACK_0 before allocate_cons(). Bugs found: - 1 bug found at compile-time, and fixed yesterday. - several bugs found during "make" and "make check", also fixed yesterday. - Many more bugs during "make check" are waiting to be fixed. I didn't fix them because I got tired of it, and Sam should learn something too :-) Bruno |
From: Sam S. <sd...@gn...> - 2002-12-20 14:44:50
|
> * In message <158...@ho...> > * On the subject of "DEBUG_GCSAFETY" > * Sent on Fri, 20 Dec 2002 14:28:28 +0100 (CET) > * Honorable Bruno Haible <ha...@il...> writes: > > I've added to the CVS the GC-safety checker. thanks! doesn't work though: g++ -W -Wswitch -Wcomment -Wpointer-arith -Wimplicit -Wreturn-type -Wno-sign-compare -falign-functions=4 -g -DDEBUG_OS_ERROR -DDEBUG_SPVW -DSAFETY=3 -DDEBUG_GCSAFETY -DNO_TYPECODES -DUNICODE -DEXPORT_SYSCALLS -DDYNAMIC_FFI -c spvw.c In file included from spvw.d:22: lispbibl.d:7337: warning: volatile register variables don't work as you might wish In file included from spvw.d:510: spvw_objsize.d: In function `uintL objsize(void*)': spvw_objsize.d:161: warning: invalid offsetof from non-POD type `struct s8string_'; use pointer to member instead spvw_objsize.d:161: warning: invalid offsetof from non-POD type `struct s8string_'; use pointer to member instead spvw_objsize.d:165: warning: invalid offsetof from non-POD type `struct s8string_'; use pointer to member instead spvw_objsize.d:165: warning: invalid offsetof from non-POD type `struct s8string_'; use pointer to member instead spvw_objsize.d:167: warning: invalid offsetof from non-POD type `struct s8string_'; use pointer to member instead many more warnings spvw.d: In function `void init_symbol_functions()': spvw.d:1079: warning: invalid offsetof from non-POD type `struct record_'; use pointer to member instead spvw.d: In function `void init_symbol_values()': spvw.d:1287: warning: invalid offsetof from non-POD type `struct record_'; use pointer to member instead spvw.d:1290: warning: invalid offsetof from non-POD type `struct record_'; use pointer to member instead spvw.d: In function `int main(int, char**)': spvw.d:2530: invalid operands of types `object*' and `gcv_object_t*' to binary `operator-' In file included from spvw.d:2989: spvw_memfile.d: In function `void savemem(object)': spvw_memfile.d:253: warning: invalid offsetof from non-POD type `struct record_ '; use pointer to member instead spvw_memfile.d:254: warning: invalid offsetof from non-POD type `struct record_ '; use pointer to member instead spvw_memfile.d: In function `void loadmem_from_handle(short unsigned int, const char*)': spvw_memfile.d:890: warning: invalid offsetof from non-POD type `struct record_ '; use pointer to member instead spvw_memfile.d:891: warning: invalid offsetof from non-POD type `struct record_ '; use pointer to member instead spvw_memfile.d:1318: warning: invalid offsetof from non-POD type `struct record_'; use pointer to member instead spvw_memfile.d:1322: warning: invalid offsetof from non-POD type `struct subr_t '; use pointer to member instead make: *** [spvw.o] Error 1 -- Sam Steingold (http://www.podval.org/~sds) running RedHat8 GNU/Linux <http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/> <http://www.mideasttruth.com/> <http://www.palestine-central.com/links.html> It's not just a language, it's an adventure. Common Lisp. |
From: Bruno H. <ha...@il...> - 2002-12-20 15:08:04
|
Sam writes: > spvw_objsize.d:167: warning: invalid offsetof from non-POD type `struct > s8string_'; use pointer to member instead > > many more warnings I don't know how to get rid of these. I think casting a pointer to member to function to 'int' in C++ is even more risky than using offsetof, because the internal representation of a pointer to member function is unspecified (and often takes more than 4 bytes). > spvw.d: In function `int main(int, char**)': > spvw.d:2530: invalid operands of types `object*' and `gcv_object_t*' to binary > `operator-' I didn't test with DEBUG_SPVW. Anyway the fix is obvious, because the type of STACK has changed from 'object *' to 'gcv_object_t *'. Bruno |
From: Sam S. <sd...@gn...> - 2002-12-20 15:33:47
|
> * In message <158...@ho...> > * On the subject of "Re: DEBUG_GCSAFETY" > * Sent on Fri, 20 Dec 2002 16:07:07 +0100 (CET) > * Honorable Bruno Haible <ha...@il...> writes: > > Sam writes: > > spvw_objsize.d:167: warning: invalid offsetof from non-POD type `struct > > s8string_'; use pointer to member instead > > > > many more warnings > > I don't know how to get rid of these. can we "use pointer to member instead"? :-) what's POD type? > I think casting a pointer to member to function to 'int' in C++ is > even more risky than using offsetof, because the internal > representation of a pointer to member function is unspecified (and > often takes more than 4 bytes). can you write a cast operator? (at least this will move all warnings to one place and then we will not miss new warnings in the stream of the old ones) -- Sam Steingold (http://www.podval.org/~sds) running RedHat8 GNU/Linux <http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/> <http://www.mideasttruth.com/> <http://www.palestine-central.com/links.html> Fighting for peace is like screwing for virginity. |
From: Bruno H. <br...@cl...> - 2002-12-20 16:07:15
|
Sam writes: > can we "use pointer to member instead"? :-) As I said, I don't think an 'offsetof' that uses pointer to member and then a cast to 'int' would be more portable than the one we have currently. > what's POD type? "Plain old data". A C++ struct/class type that has no user-defined copy-assignment operator, destructor etc. See http://www.kuzbass.ru:8086/docs/isocpp/ chapter 9. > > I think casting a pointer to member to function to 'int' in C++ is > > even more risky than using offsetof, because the internal > > representation of a pointer to member function is unspecified (and > > often takes more than 4 bytes). > > can you write a cast operator? It is not possible to write a user-defined cast operator from pointer-to-member-function to int in C++. Bruno |
From: Sam S. <sd...@gn...> - 2002-12-20 16:56:10
|
> * In message <158...@ho...> > * On the subject of "DEBUG_GCSAFETY" > * Sent on Fri, 20 Dec 2002 14:28:28 +0100 (CET) > * Honorable Bruno Haible <ha...@il...> writes: > > - Many more bugs during "make check" are waiting to be fixed. I didn't > fix them because I got tired of it, and Sam should learn something > too :-) []> (tan 1l0) abort in 0x08249188 in F_R_float_F (x={one_o = 541492077, allocstamp = 329}, y= {one_o = 541489633, allocstamp = 328}) at realelem.d:253 253 if_realp(y,,abort();); both x and y are on the stack. y is a long float. the crash is actually in ngci_pointable(). unfortunately, object_out does not work any longer: (gdb) p object_out(obj) Program received signal SIGABRT, Aborted. 0x42028cc1 in kill () from /lib/i686/libc.so.6 (gdb) p object_out(STACK[-1]) Cannot resolve function object_out(object) to any overloaded instance (gdb) p (STACK[-1]) $6 = {one_o = 541487689} (gdb) p object_out(541487689) Cannot resolve function object_out(object) to any overloaded instance -- Sam Steingold (http://www.podval.org/~sds) running RedHat8 GNU/Linux <http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/> <http://www.mideasttruth.com/> <http://www.palestine-central.com/links.html> The difference between genius and stupidity is that genius has its limits. |
From: Bruno H. <br...@cl...> - 2002-12-20 17:33:31
|
Sam writes: > []> (tan 1l0) > abort in > 0x08249188 in F_R_float_F (x={one_o = 541492077, allocstamp = 329}, y= > {one_o = 541489633, allocstamp = 328}) at realelem.d:253 > 253 if_realp(y,,abort();); > > both x and y are on the stack. What do you mean? A value that is on the STACK doesn't have an allocstamp. y's allocstamp is too low. This means y was in a register when some GCing function was called. NB: In the real*.d and comp*.d files, most functions can trigger GC, even if not explicitly noted. This is because they all create numbers, and in most cases these numbers are non-immediate. > the crash is actually in ngci_pointable(). All such crashes are in ngci_pointable(). ngci_pointable is the function which does the check. > unfortunately, object_out does not work any longer: Doesn't matter. You know y was not held in a GC safe location. Now look at the source code. Of course you might want to check 'sin' and 'cos' before 'tan'... Bruno |
From: Sam S. <sd...@gn...> - 2002-12-20 17:53:18
|
> * In message <158...@ho...> > * On the subject of "Re: DEBUG_GCSAFETY" > * Sent on Fri, 20 Dec 2002 18:32:43 +0100 (CET) > * Honorable Bruno Haible <br...@cl...> writes: > > Sam writes: > > > []> (tan 1l0) > > abort in > > 0x08249188 in F_R_float_F (x={one_o = 541492077, allocstamp = 329}, y= > > {one_o = 541489633, allocstamp = 328}) at realelem.d:253 > > 253 if_realp(y,,abort();); > > > > both x and y are on the stack. > > What do you mean? A value that is on the STACK doesn't have an > allocstamp. F_R_float_F was called like this: F_R_float_F(R_R_durch_R(STACK_0,STACK_1),STACK_2) are you saying that this is unsafe because STACK_2 could have been evaluated _before_ R_R_durch_R is computed and thus it is not safe? *&$%&^$%&$%!!!! > > unfortunately, object_out does not work any longer: > Doesn't matter. it does. could you please make it work again? it's very hard to debug anything when you cannot print objects. -- Sam Steingold (http://www.podval.org/~sds) running RedHat8 GNU/Linux <http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/> <http://www.mideasttruth.com/> <http://www.palestine-central.com/links.html> The software said it requires Windows 3.1 or better, so I installed Linux. |
From: Bruno H. <br...@cl...> - 2002-12-20 18:06:25
|
Sam writes: > F_R_float_F was called like this: > > F_R_float_F(R_R_durch_R(STACK_0,STACK_1),STACK_2) > > are you saying that this is unsafe because STACK_2 could have been > evaluated _before_ R_R_durch_R is computed and thus it is not safe? Yes. And this one is not safe either: F_R_float_F(STACK_2,R_R_durch_R(STACK_0,STACK_1)) even though DEBUG_GCSAFETY will not catch it. (gcc appears to evaluate function call arguments from right to left. Other compilers could do it from left to right.) > *&$%&^$%&$%!!!! With some temporary variables and enough pushSTACK, popSTACK you'll get it GC-safe. > could you please make it work again? > it's very hard to debug anything when you cannot print objects. I'll look at it. Bruno |
From: Sam S. <sd...@gn...> - 2002-12-20 22:22:13
|
> * In message <158...@ho...> > * On the subject of "DEBUG_GCSAFETY" > * Sent on Fri, 20 Dec 2002 14:28:28 +0100 (CET) > * Honorable Bruno Haible <ha...@il...> writes: > > I've added to the CVS the GC-safety checker. $ cvs up $ CC=gcc ./configure --with-debug --build build-g-cxx $ cd build-g-cxx $ ./clisp -q -norc > (nreverse (copy-seq #(1 2 3))) #(#<ADDRESS #x00000000> #<ADDRESS #x00000000> 3) > ouch! -- Sam Steingold (http://www.podval.org/~sds) running RedHat8 GNU/Linux <http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/> <http://www.mideasttruth.com/> <http://www.palestine-central.com/links.html> Never trust a man who can count to 1024 on his fingers. |
From: Sam S. <sd...@gn...> - 2002-12-21 16:42:49
|
> * I write: > > > * In message <158...@ho...> > > * On the subject of "DEBUG_GCSAFETY" > > * Sent on Fri, 20 Dec 2002 14:28:28 +0100 (CET) > > * Honorable Bruno Haible <ha...@il...> writes: > > > > I've added to the CVS the GC-safety checker. > > $ cvs up > $ CC=gcc ./configure --with-debug --build build-g-cxx > $ cd build-g-cxx > $ ./clisp -q -norc > > (nreverse (copy-seq #(1 2 3))) > #(#<ADDRESS #x00000000> #<ADDRESS #x00000000> 3) > > > > ouch! fixed. -- Sam Steingold (http://www.podval.org/~sds) running RedHat8 GNU/Linux <http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/> <http://www.mideasttruth.com/> <http://www.palestine-central.com/links.html> God had a deadline, so He wrote it all in Lisp. |
From: Sam S. <sd...@gn...> - 2002-12-22 17:25:19
|
to my dismay and disappointment, this did not catch all observable bugs. the documentation patch (lisp files only!) bails out with *** - FBOUNDP: (CLASS-NAME CLASS) is not a function name on loading clos.lisp: (defgeneric class-name (class) (:method ((class class)) (class-classname class))) (this is the first defgeneric) > * In message <158...@ho...> > * On the subject of "Re: DEBUG_GCSAFETY" > * Sent on Fri, 20 Dec 2002 14:28:28 +0100 (CET) > * Honorable Bruno Haible <ha...@il...> writes: > - Many more bugs during "make check" are waiting to be fixed. just one bug in pathname.d and and a handful in arithmetics. everyone is urged to build with g++ and run their applications. maybe more bugs will be fixed? -- Sam Steingold (http://www.podval.org/~sds) running RedHat8 GNU/Linux <http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/> <http://www.mideasttruth.com/> <http://www.palestine-central.com/links.html> Who is General Failure and why is he reading my hard disk? |