brian@hpausla.aso.hp.com (Brian Coogan) (01/23/90)
I've just been fighting with the return statement of perl 3.0 pl 8 and losing badly. There appear to be some bugs, or something rather non-intuitive, about the way return works. I'm not sure of the exact circumstances, but return will fail where simply evaluating an expression still returns a value. If it's a programming error on my part, it's sophisticated, as I've stepped through and verified the subroutines and they do appear to work. It's occurred to me that perl might be getting confused about numeric vs string context vs array context and I've tried quite a few permutations to get around that, no luck. Would be glad of any help from gurus out there - read on McDuff... (longish) This all started when I thought I'd add a binary option to my little conversion program. Two hours later I have a working version, which I had to hack to death to get it to behave!! The interesting thing is that one of the failing cases works with perl -d (atob (-bd) works, but btoa still fails). This is not encouraging (stack problems?). I'm running perl on an HP9000/800 (RISC) (HP-uX 3.1) machine; I get the same symptoms on a HP9000/300 (68030) (HP-UX 6.5) machine, except that perl -d doesn't help either case. Details: The program is meant to convert from a given base to another, including characters. The failures only occur with binary mode. Binary mode involves two extra subroutines, atob and btoa. Before I added them, everything else worked fine. It still does, only binary breaks. Some examples, the way they should look: $ cvt -dx 60 120 10 3c 78 a $ cvt -bd 10000 16 $ cvt -db 34 100010 At least, that's what's meant to happen. In real life, $ cvt -bd 10000 $ cvt -db 34 $ perl -d cvt -bd 10000 Loading DB from perldb.pl 3.0.1.1 89/10/26 main(20): ($myname = $0) =~ s%.*/%%; DB<1> c 16 $ perl -d cvt -db 34 Loading DB from perldb.pl 3.0.1.1 89/10/26 main(20): ($myname = $0) =~ s%.*/%%; DB<1> c $ [ie: no output] I've included for your perusal two versions of the script, one hacked to make it work, the other the way I would like it to be. The working version is cvt.hack, but it has a lot of debug output. The failure is called cvt. If you can fix this for me, or correct some mistake, I'll be greatly grateful. Once this is fixed I hope to post it. thanks, Brian Coogan, Hewlett-Packard Australian Software Operation. ACSnet: brian@hpausla.oz UUCP: hplabs!hpausla!brian Internet: brian%hpausla@hplabs.hp.com Tel: +61 3 871 1648 (TZ=EST-10) #---------------------------------- cut here ---------------------------------- # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by Brian Coogan <brian@hpausln> on Tue Jan 23 22:23:56 1990 # # This archive contains: # cvt cvt.dbg # # Error checking via wc(1) will be performed. unset LANG echo x - cvt cat >cvt <<'@EOF' #! /usr/bin/perl # cvt # Convert between bases # # Usage: cvt -<from><to> [from ...] # # where <from> and <to> are each single letters meaning: # o octal # d decimal # x hex # b binary # c character # # Brian Coogan 6 Jan 90 # # $Header: cvt,v 1.1.1.1 90/01/23 21:50:44 brian Exp $ # $Locker: $ ($myname = $0) =~ s%.*/%%; $mode = shift; die "Usage: $myname -[odbcx][odbcx] [args]\n" unless ($mode =~ m|-([odbcx])([odbcx])[^/]*$|); $from = $1; $to = $2; if ($#ARGV >= $[) { while ($val = shift) { print do cvt($val) . "\n"; } exit(0); } while ($val = <>) { print do cvt($val) . "\n"; } exit(0); sub cvt { local($val) = @_; # # Input # if decimal, its already ok # $val = oct($val) if $from eq 'o'; $val = hex($val) if $from eq 'x'; $val = ord($val) if $from eq 'c'; $val = &atob($val) if $from eq 'b'; # # Output # return(&prettychar($val)) if $to eq 'c'; return(&btoa($val)) if $to eq 'b'; return(sprintf("%$to", $val)); } sub prettychar { local($val) = @_; # isprint simulation return(sprintf("%c", $val)) if ($val > 32 && $val <= 126); # known control chars return('\r') if $val == 015; return('\n') if $val == 012; return('\f') if $val == 014; return('\t') if $val == 011; return('SP') if $val == 040; # misc control chars return(sprintf("^%c", ($val + 0100))) if ($val < 32); # # If we get this far, it may be a terminal dependent character, # but as we can't portably determine whether it is, we print # it in octal # return(sprintf("\\%3o", $val)); } # # Ascii binary (aka base 2) to internal # sub atob { local($string) = @_; local($val, $dig) = 0; foreach $dig (split(/ */, $string)) { $val = $val * 2 + $dig; } return($val); } # # Internal binary (aka base 2) to ascii. No particular reason why # they're signed; that code can be removed if desired (comment out # tagged lines). # sub btoa { local($val) = @_; local($sign) = ''; # signed local(@digits) = (); if ($val < 0) # signed { # signed $sign = '-'; # signed $val = - $val; # signed } # signed $val = int($val); # sorry, we're dumb here while ($val != 0) { unshift(@digits, ($val & 1) ? "1" : "0"); $val = int($val/2); } return($sign . join('', @digits)); } @EOF set `wc -lwc <cvt` if test $1$2$3 != 1294012229 then echo ERROR: wc results of cvt are $* should be 129 401 2229 fi chmod 555 cvt echo x - cvt.dbg cat >cvt.dbg <<'@EOF' #! /usr/bin/perl # cvt # Convert between bases # # Usage: cvt -<from><to> [from ...] # # where <from> and <to> are each single letters meaning: # o octal # d decimal # x hex # b binary # c character # # Brian Coogan 6 Jan 90 # # $Header$ # $Locker$ ($myname = $0) =~ s%.*/%%; $mode = shift; die "Usage: $myname -[odbcx][odbcx] [args]\n" unless ($mode =~ m|-([odbcx])([odbcx])[^/]*$|); $from = $1; $to = $2; if ($#ARGV >= $[) { while ($val = shift) { print do cvt($val) . "\n"; #$xx = do cvt($val); #print "top output $xx\n"; } exit(0); } while ($val = <>) { #print do cvt($val) . "\n"; $xx = do cvt($val); print "output $xx\n"; } sub cvt { local($val) = @_; # # Input # if decimal, its already ok # $val = $val + 0 if $from eq 'd'; $val = oct($val) if $from eq 'o'; $val = hex($val) if $from eq 'x'; $val = ord($val) if $from eq 'c'; $val = &atob($val) if $from eq 'b'; printf "cvt got number in as $val\n"; # # Output # return(&prettychar($val)) if $to eq 'c'; if ($to eq 'b') { $tmp = &btoa($val); print "cvt: retval = $tmp, global = $result\n"; #$tmp.' '; $tmp; # method 1 - works "$tmp"; # method 2 - works #return "$tmp"; # method 3 - fails. last; } #return(&btoa($val)) if $to eq 'b'; # what I really want to do sprintf("%$to", $val); } sub prettychar { local($val) = @_; # isprint simulation return(sprintf("%c", $val)) if ($val > 32 && $val <= 126); # known control chars return('\r') if $val == 015; return('\n') if $val == 012; return('\f') if $val == 014; return('\t') if $val == 011; return('SP') if $val == 040; # misc control chars return(sprintf("^%c", ($val + 0100))) if ($val < 32); # # If we get this far, it may be a terminal dependent character, # but as we can't portably determine whether it is, we print # it in octal. # return(sprintf("\\%3o", $val)); } # # Ascii binary (aka base 2) to internal # sub atob { local($string) = @_; local($val, $dig) = 0; foreach $dig (split(/ */, $string)) { $val = $val * 2 + $dig; } #return($val); # only works for single digits $val; } # # Internal binary (aka base 2) to ascii. No particular reason why # they're signed; that code can be removed if desired (comment out # tagged lines). # sub btoa { local($val) = @_; local($sign) = ''; # signed local(@digits) = (); print "btoa: input $val\n"; if ($val < 0) # signed { # signed $sign = '-'; # signed $val = - $val; # signed } # signed $val = int($val); # sorry, we're dumb here while ($val != 0) { unshift(@digits, ($val & 1) ? "1" : "0"); $val = int($val/2); } printf "btoa: ascii output %s\n", $sign . join('', @digits); $result = $sign . join('', @digits); # try a global #return($sign . join('', @digits)); # returns nothing $sign . join('', @digits); } @EOF set `wc -lwc <cvt.dbg` if test $1$2$3 != 1485062808 then echo ERROR: wc results of cvt.dbg are $* should be 148 506 2808 fi chmod 755 cvt.dbg exit 0
brian@hpausla.aso.hp.com (Brian Coogan) (01/24/90)
Brian Coogan <brian@hpausla.aso.hp.com> writes in comp.lang.perl: > I've just been fighting with the return statement of perl 3.0 pl 8 and > losing badly. There appear to be some bugs... I just recompiled cmd.c with JMPCLOBBER defined and the bug went away. Thanks for your help (especially Paul Maisano who suggested the fix). Serves me right for not watching the fixes going by more closely. thanks folks, Brian.
glen@proexam.UUCP (Glen Brydon) (02/04/90)
In article <4080005@hpausla.aso.hp.com> brian@hpausla.aso.hp.com (Brian Coogan) writes: >Brian Coogan <brian@hpausla.aso.hp.com> writes in comp.lang.perl: >> I've just been fighting with the return statement of perl 3.0 pl 8 and >> losing badly. There appear to be some bugs... > >I just recompiled cmd.c with JMPCLOBBER defined and the bug went away. >Thanks for your help (especially Paul Maisano who suggested the fix). >Serves me right for not watching the fixes going by more closely. > >thanks folks, >Brian. I haven't seen any reply from Larry Wall about this stuff. It concerned me when Anders Pilegaard posted his alarming article giving rather mysterious symptoms (non of which I experienced). As he wrote to me: >From cucard!daimi.dk!andersp Tue Jan 30 01:18:04 1990 >Date: Mon, 29 Jan 90 14:45:49 +0100 >From: Anders Pilegaard <cucard!daimi.dk!andersp> >Subject: Re: IMPORTANT: Mysterious errors in perl patch level 8, solved >. . . >I then began actually debugging perl and after some time discovered >that a free string struct had some wild references resulting in >attempts to dereference a NIL pointer. After some more debugging it >appeared that this wild value was put there while the string struct >was free'd, indicating stray pointers. Quite some hours later I found >the real culprit, setjmp/longjmp. Perl uses a local register variable > ============== >st to hold a stack. As this stack may be changed by various routines >(foremost eval) it is often reset to the value of a global variable. >This is not done around setjmp, and setjmp/longjmp does NOT guarantee > ================== >handling of register variables correctly (At least is says so in the >======================================== >manual page on our sun-3). . . . > >It is both subtle and yet so simple. Because of the nature of this >bug, virtually ANY variable may be clobbered. It may appear in any > ======================================= >script utilising longjmp's, and that includes not only subroutines, >but also last, next, redo, and goto. But the fix is quite simple. > >Actually it seems that Larry Wall has foreseen this. He has introduced > ============================ >an #ifdef JMPCLOBBER around the critical sections. This activates >four assignments around each setjmp and should take care of all >critical variables. The problem is that he only defined it for >cray's and ANSI compilers. And it seems that at least sun's and hp's >should also define this. And who knows how many other >architectures/operating systems are affected? > >The reason that I posted my article with such an alarming header is >that it is quite difficult to determine whether a system is affected > =================================================== >by this bug. On our systems the same script produced two very visible >reactions (core dump) and two actions I wouldn't have noticed had I >not been debugging that particular script --- at least it would have >been some time before I found out. On my system (SunOS version 4.0.3 running on 3/280 arch) the man page for setjmp(3) is quite informative (more so than 4.3 BSD): SETJMP(3) C LIBRARY FUNCTIONS SETJMP(3) NAME setjmp, longjmp, sigsetjmp, siglongjmp - non-local goto . . . . . DESCRIPTION . . . . . setjmp() saves its stack environment in env for later use by longjmp. A normal call to setjmp() returns zero. setjmp() also saves the register environment. If a longjmp() call ============================== . . . . . point data registers are restored to the values they had at the time that setjmp() was called. But, because the regis- ter storage class is only a hint to the C compiler, vari- =========== ables declared as register variables may not necessarily be assigned to machine registers, so their values are unpredictable after a longjmp. This is especially a problem for programmers trying to write machine-independent C rou- =================== tines. . . . . . EXAMPLE The following code fragment indicates the flow of control of the setjmp() and longjmp() combination: function declaration ... jmp_buf my_environment; ... if (setjmp(my_environment)) { /* register variables have unpredictable values ==================== code after the return from longjmp ... } else { /* do not modify register vars this is the return from setjmp ... } SEE ALSO cc(1V), sigsetmask(2), sigvec(2), ieee_flags(3M), signal(3), setjmp(3V) BUGS . . . . . >> On Sun-2 and Sun-3 systems setjmp() also saves the register << >> environment. Therefore, all data that are bound to regis- << >> ters are restored to the values they had at the time that << >> setjmp() was called. All memory-bound data have values as << >> of the time longjmp() was called. However, because the << >> register storage class is only a hint to the C compiler, << >> variables declared as register variables may not necessarily << >> be assigned to machine registers, so their values are << >> unpredictable after a longjmp. When using compiler options << >> that specify automatic register allocation (see cc(1V)), the << >> compiler will not attempt to assign variables to registers << >> in routines that call setjmp. << ===================================================================== It seems only too clear that my computer and its operating system should be treated like the cray and those with ANSI compilers. I will be interested in seeing how Larry deals with this problem in his upcoming bugfix (#9). Are there systems out there which guarantee both that the compiler will in fact put your variable in a register AND that all the registers will be restored as Larry has assumed most will? Needless to say I have applied a temporary fix and for me this fixed Brian Coogan's return problem (as it did for him). While the gray areas of the language seem to be more interesting to most people (including me), this stuff scares me to death. Setjmp(3) seems in fact to be one of those gray areas of UNIX. As I wrote to Anders Pilegaard, it surprises me the way this particular problem has been publcized (or not). It is especially confusing then Larry already anticipated it, but seemed not to realize the danger of his assumptions. I hope to see the official fix for this one.
lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (02/06/90)
In article <4080004@hpausla.aso.hp.com> brian@hpausla.aso.hp.com (Brian Coogan) writes:
: I've just been fighting with the return statement of perl 3.0 pl 8 and
: losing badly. There appear to be some bugs, or something rather
: non-intuitive, about the way return works.
There were at least three little return buglets that should be fixed in patch 9.
1) Couldn't return ().
2) Occasional return of garbage value (or dump of core) in calling
a subroutine the first time through (i.e. when growing the
stack). This is caused by some statements in cmd.c misplaced
inside #ifdef JMPCLOBBER. If defining #JMPCLOBBER manually
fixes this, it's probably this bug. Patch 9 will fix it
so you can undef JMPCLOBBER again for a little efficiency.
3) A return embedded in an expression could lose track of
whether an array value or scalar was required for the function.
Larry
lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (02/07/90)
In article <418@proexam.UUCP> glen@proexam.UUCP (Glen Brydon) writes: : In article <4080005@hpausla.aso.hp.com> brian@hpausla.aso.hp.com (Brian Coogan) writes: : >I just recompiled cmd.c with JMPCLOBBER defined and the bug went away. : >Thanks for your help (especially Paul Maisano who suggested the fix). : >Serves me right for not watching the fixes going by more closely. : : I haven't seen any reply from Larry Wall about this stuff. It concerned : me when Anders Pilegaard posted his alarming article giving rather : mysterious symptoms (non of which I experienced). As he wrote to me: : [message deleted] : : It seems only too clear that my computer and its operating system : should be treated like the cray and those with ANSI compilers. I : will be interested in seeing how Larry deals with this problem in : his upcoming bugfix (#9). Are there systems out there which guarantee : both that the compiler will in fact put your variable in a register : AND that all the registers will be restored as Larry has assumed most : will? Needless to say I have applied a temporary fix and for me this : fixed Brian Coogan's return problem (as it did for him). : : While the gray areas of the language seem to be more interesting to : most people (including me), this stuff scares me to death. Setjmp(3) : seems in fact to be one of those gray areas of UNIX. As I wrote to : Anders Pilegaard, it surprises me the way this particular problem has : been publcized (or not). It is especially confusing then Larry already : anticipated it, but seemed not to realize the danger of his assumptions. : : I hope to see the official fix for this one. There are several things going on here. The first is that there is a bug in cmd.c that hides a statement inside #ifdef JMPCLOBBER that should be outside. These are the statements that say st = stack->ary_array. These are necessary after any expression evaluation because the stack may have been realloced. This has nothing to do with registers. But I believe this is why defining JMPCLOBBER fixed some flakiness. Patch 9 moves these outside the JMPCLOBBER code. Now, as to registers and setjmp/longjmp. We have to distinguish two levels of support here. First, as in the long manual section you quoted, we have machines such as Sun which profess to restore ALL values, but it is indeterminate whether they are restored to their value at setjmp() time or longjmp() time. That's okay, because perl doesn't rely on any variables that could change between the setjmp() and the longjmp(). You shouldn't need JMPCLOBBER on a Sun, at least not if their documentation tells the truth on all Sun architectures. There is a second level of (non-)support here, which is the ANSI level--namely that registers are not guaranteed to have ANY reasonable value after a longjmp(), that is, the value will be neither that at setjmp() time, nor that at longjmp() time. The official solution to this is to declare any variables that you care about as volatile, so that they aren't kept in registers over the setjmp()/longjmp(). Several of you sent me patches to this effect. I don't like the "official" solution. It's overkill. And cmd_exec() is the one routine that can't afford any excess overhead. The routine really wants registers, and much of the routine is outside of setjmp()/longjmp(). So, instead of abandoning the registers, I merely make sure that I have some alternate way of restoring the registers after a longjmp(). This is the code you will find inside of #ifdef JMPCLOBBER. It's unnecessary overhead if registers are restored by longjmp(). The JMPCLOBBER code only adds overhead when entering or exiting a loop or block, because that's the only code that can longjmp. There's one extra statement going in, and two extra going out. And the ones going out are only exercised if the longjmp() actually happens. This has got to be less overhead than abandoning registers altogether. The only problem with it is when to define JMPCLOBBER. It's currently defined on Cray and ANSI C machines. We run the risk of finding a new compiler or machine which isn't ANSI but has ANSI behavior. I think that's a risk I'm willing to take. It may be possible to write a Configure test for it that will usually be right, but it looks hard. For the moment, I'm content to say that if you're on an oddball architecture, and you get flaky results, try defining JMPCLOBBER. I don't think it's something worth panicking about. Larry
tom@ssd.csd.harris.com (Tom Horsley) (02/09/90)
I think the solution of re-loading the register variables rather than declaring everything as volatile is a good idea, but it needs one extra frill (at least the way it is implemented in patch level 8). The variables you restore the register variables from *DO* need to be declared volatile. Quite a few of the newer optimizing compilers don't care if you declare a variable register or not, if they can keep it in a register, they will do so. This also means that some of the non-register variables (which appear to be referenced across a setjmp) need to be declared volatile, or restored from a volatile copy just like the register variables. I have a problem now compiling with the highest optimization level getting "panic: corrupt saved stack index" messages, I am perfectly willing to believe it is an optimizer bug in my compiler, but it may also be a problem with setjmp/longjmp, I have not had enough time to actually debug it yet (but it happens the same way with or without JMPCLOBBER). -- ===================================================================== domain: tahorsley@ssd.csd.harris.com USMail: Tom Horsley uucp: ...!novavax!hcx1!tahorsley 511 Kingbird Circle or ...!uunet!hcx1!tahorsley Delray Beach, FL 33444 ======================== Aging: Just say no! ========================
lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (02/14/90)
In article <TOM.90Feb9070637@hcx2.ssd.csd.harris.com> tom@ssd.csd.harris.com (Tom Horsley) writes:
: I think the solution of re-loading the register variables rather than
: declaring everything as volatile is a good idea, but it needs one extra
: frill (at least the way it is implemented in patch level 8). The variables
: you restore the register variables from *DO* need to be declared volatile.
: Quite a few of the newer optimizing compilers don't care if you declare a
: variable register or not, if they can keep it in a register, they will do
: so.
:
: This also means that some of the non-register variables (which appear to be
: referenced across a setjmp) need to be declared volatile, or restored from a
: volatile copy just like the register variables.
Er, there are three variables that are used to restore registers. cmdparm
is already declared volatile. cmd->c_flags is part of a structure, and
goto_targ is a global. Are you saying that parts of a structure
and global variables also might get put into registers?
Actually, I can believe a super-optimizing compiler might put a global
into a register. I can't imagine a stucture element, tho. I doubt
either is your problem.
: I have a problem now compiling with the highest optimization level getting
: "panic: corrupt saved stack index" messages, I am perfectly willing to believe
: it is an optimizer bug in my compiler, but it may also be a problem with
: setjmp/longjmp, I have not had enough time to actually debug it yet (but it
: happens the same way with or without JMPCLOBBER).
This indicates that the "oldsave" variable is getting clobbered somehow.
But that one is also declared volatile.
Actually, it's declared VOLATILE. Perhaps VOLATILE isn't getting
defined right. Does your cpp define __STDC__?
Larry
bart@videovax.tv.tek.com (Bart Massey) (02/15/90)
In article <7068@jpl-devvax.JPL.NASA.GOV> lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) writes: > Are you saying that parts of a structure > and global variables also might get put into registers? > > Actually, I can believe a super-optimizing compiler might put a global > into a register. I can't imagine a stucture element, tho. I doubt > either is your problem. Heck, I'll say it. Try running GCC-1.36 -O over the following C code, and be surprised that, at least on the VAX and 68k, the structure member ends up in a register. Note that, at least as of 1.36, this is a very fragile optimization, but it's bound to get nothing but better. ----- struct foo { int a, b; }; main() { struct foo bar; for( bar.b = 0; bar.b < 10; bar.b++ ) nothing( bar.b ); /* force an external reference */ } ----- And the brand-new DecStation 3100 (PMAX) Ultrix compiler does global register optimizations, or so I am told. Aren't compilers wonderful? Bart Massey ..tektronix!videovax.tv.tek.com!bart ..tektronix!reed.bitnet!bart
lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (02/16/90)
In article <5716@videovax.tv.tek.com> bart@videovax.tv.tek.com (Bart Massey) writes:
: Heck, I'll say it. Try running GCC-1.36 -O over the following C code,
: and be surprised that, at least on the VAX and 68k, the structure member
: ends up in a register. Note that, at least as of 1.36, this is a very
: fragile optimization, but it's bound to get nothing but better.
:
: -----
: struct foo { int a, b; };
:
: main()
: {
: struct foo bar;
:
: for( bar.b = 0; bar.b < 10; bar.b++ )
: nothing( bar.b ); /* force an external reference */
: }
: -----
:
: And the brand-new DecStation 3100 (PMAX) Ultrix compiler does global
: register optimizations, or so I am told.
:
: Aren't compilers wonderful?
Gack.
Ok, I'll spread a few more judicious volatiles here and there on my globals
and structure elements. Blech. All this gobblygook just to make life
a little easier for a few compiler writers. setjmp()/longjmp() are NOT
in the same class as asynchronous interrupts.
"volatile" must go. This is non-negotiable. :-) :-) :-)
Just another puerile hacker,
Larry
mike@umn-cs.cs.umn.edu (Mike Haertel) (02/16/90)
In article <7080@jpl-devvax.JPL.NASA.GOV> lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) writes: >Ok, I'll spread a few more judicious volatiles here and there on my globals >and structure elements. Blech. All this gobblygook just to make life >a little easier for a few compiler writers. setjmp()/longjmp() are NOT >in the same class as asynchronous interrupts. > >"volatile" must go. This is non-negotiable. :-) :-) :-) Note that if -traditional is used with gcc, it automatically recognizes functions that call setjmp() and effectively forces all references from within those functions to be volatile. Of course, particularly if you call setjmp() from somewhere within a big, oft-used function, this is an efficiency hit, so volatile declarations may be more appropriate, if more work. -- Mike Haertel <mike@ai.mit.edu> "COBOL programmers are destined to code COBOL for the rest of their lives, and thereafter." -- Bertrand Meyer
bart@videovax.tv.tek.com (Bart Massey) (02/16/90)
In article <1990Feb15.202214.14987@umn-cs.cs.umn.edu> mike@umn-cs.cs.umn.edu (Mike Haertel) writes: > In article <7080@jpl-devvax.JPL.NASA.GOV> lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) writes: > >Ok, I'll spread a few more judicious volatiles here and there on my globals > >and structure elements. Blech. All this gobblygook just to make life > >a little easier for a few compiler writers. setjmp()/longjmp() are NOT > >in the same class as asynchronous interrupts. > > > >"volatile" must go. This is non-negotiable. :-) :-) :-) > > Note that if -traditional is used with gcc, it automatically recognizes > functions that call setjmp() and effectively forces all references from > within those functions to be volatile. > > Of course, particularly if you call setjmp() from somewhere within > a big, oft-used function, this is an efficiency hit, so volatile > declarations may be more appropriate, if more work. This whole discussion probably belongs somewhere else, but I couldn't resist one last word. The problem, as Mike points out, is not the "volatile" keyword, which is a serious feature for those of us writing memory-mapped device drivers. The problem is the gratuituous, superfluous, and altogether obnoxious change by the ANSI folks of the most common traditional semantics of setjmp() . Under BSD Unix, at any rate, unless you call _setjmp(), you get a *system call* anyway, to save the signal mask as well as the machine state. What ANSI *should* have done, IMHO, is to specify setjmp() and longjmp() to save all auto variables, and _setjmp() and _longjmp() to have the current more efficient but less comprehensible and useful semantics. The perceived problem is that old-style setjmp() forces either the save of essentially the entire machine state, including possibly a gazillion registers, or implementation of setjmp() as compiler builtins. My claim is that the cost of saving the machine state is swamped on many UNIX machines by the cost of the system call, and that it wouldn't be that hard to implement setjmp() and longjmp() as compiler builtins which save the live state and call a library routine, as I assume GCC does based on Mike's comments above. Please don't take away my "volatile"! :-) Bart Massey ..tektronix!videovax.tv.tek.com!bart ..tektronix!reed.bitnet!bart
tom@ssd.csd.harris.com (Tom Horsley) (02/17/90)
>Ok, I'll spread a few more judicious volatiles here and there on my globals >and structure elements. Blech. All this gobblygook just to make life >a little easier for a few compiler writers. setjmp()/longjmp() are NOT >in the same class as asynchronous interrupts. That's right, they aren't, they are worse, they are a perversion that is being hidden from the compiler disguised as ordinary function calls. We don't have these problems with our Ada compiler, because exception frames and non-local gotos and wot-not are actually a part of the language. setjmp()/longjmp() must go. This is non-negotiable. :-) e+9. Meanwhile, to make this article actually have something to do with perl, I should report the results I got when I finally debugged (or at least suppressed) my "panic: corrupt saved stack index" problems: 1) You were right, VOLATILE was not being defined as volatile, but fixing this did not make the problem go away. 2) There are goto's in the if (setjmp()) code. These gotos imply that the entire body of the routine is reachable following a setjmp(), not just a few little sections of code. 3) The variables gimme, sp, retstr, tmps, go_to, and newsp are not declared volatile and are also not necessarily restored correctly following the longjmp (for some of them, it depends on whether or not any of the switch body is executed, and that depends on the value returned from longjmp). 4) When I declared these 6 variables VOLATILE, the code started working perfectly. 5) I don't actually know what specifically was happening, I stopped working on it once I got it to work in step 4, but one other experiment I made is worth reporting. I made 6 volatile variables to save these six values in, and did saves and restores around the setjmp() calls, and I *still* got the panic messages. My two best theories are a compiler bug, or one of these variables is really updated prior to the longjmp and wants to keep its updated value, not the value it had when the first setjmp() was called. P.S. Our compiler does not (yet) keep fields of structs in registers. The back end is capable of doing it, but the front end currently does not do very aggressive alias analysis (for C, Ada is another matter). -- ===================================================================== domain: tahorsley@ssd.csd.harris.com USMail: Tom Horsley uucp: ...!novavax!hcx1!tahorsley 511 Kingbird Circle or ...!uunet!hcx1!tahorsley Delray Beach, FL 33444 ======================== Aging: Just say no! ========================
lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (02/20/90)
In article <TOM.90Feb17084626@hcx2.ssd.csd.harris.com> tom@ssd.csd.harris.com (Tom Horsley) writes:
: setjmp()/longjmp() must go. This is non-negotiable. :-) e+9.
I confess I like Ada exceptions a lot better too.
: 1) You were right, VOLATILE was not being defined as volatile, but fixing
: this did not make the problem go away.
I can see another Configure test coming... *sigh*
: 2) There are goto's in the if (setjmp()) code. These gotos imply that the
: entire body of the routine is reachable following a setjmp(), not just
: a few little sections of code.
Yes, but it's in a loop anyway, so that's true whatever. And gotos are just
C's little way of telling you it wishes it had a real exception mechanism
that would let you exit blocks by default instead of restarting them...
: 3) The variables gimme, sp, retstr, tmps, go_to, and newsp are not
: declared volatile and are also not necessarily restored correctly
: following the longjmp (for some of them, it depends on whether or not
: any of the switch body is executed, and that depends on the value
: returned from longjmp).
Variables gimme and sp are function parameters, which is why I overlooked
them. Presuming JMPCLOBBER is defined, retstr, newsp and go_to are
always taken care of if you assume that the longjmp() never returns a
value that isn't handled by the switch, which it doesn't (but I ought
to have a default case for paranoia reasons anyway.) tmps is a scratch
variable, and is only used locally, never over a setjump()/longjmp().
It looks like your problem was either gimme or sp. Probably sp. They
will both be volatilized.
: 4) When I declared these 6 variables VOLATILE, the code started working
: perfectly.
If you could tell me if it keeps working with only gimme and sp volatilized,
I'd be much obliged. I'm not planning on volatilizing the others.
: 5) I don't actually know what specifically was happening, I stopped
: working on it once I got it to work in step 4, but one other
: experiment I made is worth reporting. I made 6 volatile variables to
: save these six values in, and did saves and restores around the
: setjmp() calls, and I *still* got the panic messages. My two best
: theories are a compiler bug, or one of these variables is really
: updated prior to the longjmp and wants to keep its updated value, not
: the value it had when the first setjmp() was called.
Neither gimme nor sp is updated at any time in the routine, let alone
between setjmp() and longjmp(). And the others are supposedly accounted for.
Thanks for the input.
#5, er, I mean, Larry