Path: news.mitre.org!blanket.mitre.org!agate!newsgate.duke.edu!nntprelay.mathworks.com!news.mathworks.com!mvb.saic.com!info-vax From: Jerry Leichter Newsgroups: comp.os.vms Subject: RE: setjmp/longjmp & VMS Message-ID: <9712220312.AA22190@uu3.psi.com> Date: Sun, 21 Dec 97 21:00:41 EST Organization: Info-Vax<==>Comp.Os.Vms Gateway X-Gateway-Source-Info: Mailing List Lines: 96 Can any of the C wizards tell me what is wrong with the following: #include #include #include jmp_buf e; void dummy() { longjmp(e,0); return; } int main() { int first = 1; setjmp(e); if(first) { first = 0; } else { goto cnt; } printf("1\n"); dummy(); printf("2\n"); cnt: printf("3\n"); exit(0); } On VMS it prints 1 out in a loop, while on all other platforms I have tried, I get the result I expect: 1 line with 1 and one with 3. You may *expect* this result, but it can't be justified on the basis of the C standard. The problem you are running into is in making an assumption about the values of automatic variables "around" a setjmp() call. In your example, "first" is such a variable. People generally make one of two assumptions: 1. An automatic variable will retain the value it had at the point when setjmp() was called, regardless of subsequent changes; 2. An automatic variable will retain the value it had at the point *longjmp()* is called, regardless of the value it had when setjmp() was called. You're assuming (2). The C standard, however, supports *neither* assumption. Consider: If "first" is actually stored on the stack, then setjmp() won't actually save it, and indeed when you do a longjmp() first's value will be whatever was last stored in that stack location. This gives you behavior (2). On the other hand, if "first" is optimized into a register, then a typical implementation of setjmp() will save that register in the jmp_buf. When longjmp() restores the registers, and the previous value of "first" magically reappears. This gives you behavior (1). Both behaviors can in fact be observed in different compilers - and often in the same compiler, depending on what variables are optimized into registers. In fact, however, you can't even say from the standard that you'll see either behavior (1) or behavior (2). You may see some other value entirely! It's not easy to come up with an example; in fact, I don't know of any compiler that actually works this way. But it's theoretically possible. Hmm, one possible case: Suppose that your compiler can do split-lifetime analysis, and is clever enough to notice that "first" and another variable, "second", are never live at the same time. It could then assign both to the same storage location on the stack. In that case, if you do a setjmp(), then execute code in which "second" gets assigned to, then do a longjmp(), the value you see for "first" is actually the value written to "second". Many compilers to split lifetime analysis for variables bound to registers; DEC C certainly does. I don't know if it does the same analysis for variables maintained on the stack. A common proposal to "fix" this problem is to declare first volatile. However, this doesn't work: The semantics of volatile are implementation- specific, but the Standard suggests that a volatile variable receives all assignments that would be done by the Standard's abstract description. However, there is nothing in the Standard that says what the abstract machine is supposed to do with this case. In *most* implementations, declared first volatile will force behavior (2), since it will keep it out of a register and may prevent its lifetime being split; but there's no guarantee. If you want a guarantee, you only have one alternative: Make first volatile static. The static ensures that first's lifetime must be the lifetime of the entire program execution (well, not quite, but the difference isn't relevant here); and the volatile ensures that all apparent stores to memory are really done. A volatile global would do as well, of course. (Since volatile is implementation-specified, it's not clear to me that even this is really a guarantee in the eyes of the Standard; but in practice it should work almost everywhere. Actually, while I don't have the text of the Standard handy, I suspect one could successfully show that just static (or global) is enough' volatile isn't needed. -- Jerry