This is the mail archive of the guile@cygnus.com mailing list for the guile project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Well it's funny that everyone is talking about bugs caused by the optimiser -- I just found where I was being bitten by it too, probably bitten for some time without realising exactly where the problem was coming from. The error: insert_test.scm:38:5: In procedure point+ in expression (point+ (random-error-point) (list # # ...)): insert_test.scm:38:5: Wrong type argument in position 1: (e{@e{@-01 0.0050657 0.0244) Doesn't explain much except that you can see something that looks like memory corruption and it is happening to what should be a floating point value. What finally turned out to be the cause: { int c; long pos = 0; SCM result; SCM tok_buf = scm_makstr( 100L, 0 ); while( 1 ) { switch( c = scm_getc( port )) { /* lots of cases removed */ default: { char *p = SCM_CHARS( tok_buf ); scm_ungetc( c, port ); result = scm_istring2number( p, pos, 10L ); if( SCM_BOOL_F != result ) return( result ); return( SCM_CAR( scm_intern( p, pos ))); } } } } As you can see, *p takes the internal memory of tok_buf which is then not referred to before the next return() statement. This leaves the optimiser free to throw away tok_buff and scm_istring2number can sometimes activate garbage collection. The quick solution is to put a volatile in the declaration of tok_buf, another (better?) solution is to avoid scm_istring2number() and scm_intern(), preferring something that works directly on the SCM value. Thus, the following works without the volatile declaration: default: { char *p = SCM_CHARS( tok_buf ); SCM sub = scm_make_shared_substring( tok_buf, SCM_MAKINUM( 0 ), SCM_MAKINUM( pos )); scm_ungetc( c, port ); result = scm_string_to_number( sub, SCM_UNDEFINED ); if( SCM_BOOL_F != result ) return( result ); return( scm_string_to_symbol( sub )); } The reason is that even when tok_buf is thrown away, sub keeps the memory usable and sub hangs in there right till the end. The implications of this are logical enough once you have gone through it a few times but it is going to become a big trap to newbies unless it gets well documented. As an aside, it is interesting to note that the libguile code for scm_make_shared_substring() uses the optimiser-defeating trick for exactly the same reason, so using this function is a way of passing the buck. On the other hand scm_string_to_symbol() does NOT use the optimiser protection nor does it declare anything volatile. Apparently, the only reason that it works is because function arguments tend to be on the stack (OK, I'm on 386-linux system, they are ALWAYS on the stack) but this is not an absolute truth -- I'll give the UltraPenguin a try sometime and see if I can break it. Something for the TODO list I guess is to draw a line around which functions can get you into trouble (e.g. SCM_CHARS(), SCM_ROCHARS(), etc) and maybe start thinking about the sort of cases those functions have been used in. One big one is probably SMOB code that takes a SCM value which is the SMOB and first thing it does is extract a pointer to a C struct. >From there on in, all the work is done with the C struct and the SCM pointer is probably left untouched in 9/10 cases. Most of these are safe because the SCM value is a function argument so it's on the stack. Better than that, most SMOBs aren't created just to be used once and destroyed so something else usually points to them. Neither of these protections are completely trustworthy (unless you always use a 386 and pass your args on the stack). - Tel