From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Thread: 103376,2cb1f0b6d642e1dc X-Google-NewGroupId: yes X-Google-Attributes: gida07f3367d7,domainid0,public,usenet X-Google-Language: ENGLISH,ASCII-7-bit Path: g2news2.google.com!news1.google.com!newsfeed2.dallas1.level3.net!news.level3.com!bloom-beacon.mit.edu!newsswitch.lcs.mit.edu!nntp.TheWorld.com!not-for-mail From: Robert A Duff Newsgroups: comp.lang.ada Subject: Re: Pascal Calling Convention Date: Sat, 26 Mar 2011 16:46:37 -0400 Organization: The World Public Access UNIX, Brookline, MA Message-ID: References: <9b04626e-567d-408c-aab3-39b964b3ffd6@l2g2000prg.googlegroups.com> NNTP-Posting-Host: shell01.theworld.com Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: pcls6.std.com 1301172397 5515 192.74.137.71 (26 Mar 2011 20:46:37 GMT) X-Complaints-To: abuse@TheWorld.com NNTP-Posting-Date: Sat, 26 Mar 2011 20:46:37 +0000 (UTC) User-Agent: Gnus/5.1008 (Gnus v5.10.8) Emacs/21.3 (irix) Cancel-Lock: sha1:ZgKkGR4JEEf1DU/0enzlkPnjZVM= Xref: g2news2.google.com comp.lang.ada:19451 Date: 2011-03-26T16:46:37-04:00 List-Id: Keith Thompson writes: > Keep in mind that "undefined" behavior doesn't just mean that the code > will do one of N reasonable things. It means that the compiler is > permitted to *assume*, for the sake of optimization, that no undefined > behavior will occur during the execution of the program. > > This particular case is relatively straightforward, but there have > been some serious bugs caused by this kind of thing. Indeed. >...One example > that springs to mind: some code read from uninitialized memory as > a source of entropy for pseudo-random number generation (not the > only source). That seems like a reasonable thing to do, but the > compiler optimized away the code that did the reading, resulting > in some really bad "random" numbers. It doesn't seem reasonable to me. Uninitialized variables do not contain random data. They contain arbitrary data. And it's quite likely that such arbitrary data happens to be the same every time, or has some other non-random pattern. Bad Guys sometimes exploit such patterns to cause security problems. >>>...it >>> could legitimately print "a suffusion of yellow" or cause your >>> keyboard to explode. >> >> True, according to the C standard. But I'm pretty sure that there's >> some other standard that will prevent it from blowing up my keyboard. >> ;-) > > Or from blowing up your rocket? ;-) The computer I'm typing on does not control rockets, so I think doing things like i++ + ++i won't have any effect on any rockets. Laws of physics makes it unlikely. ;-) >> By the way, when explaining what "undefined behavior" means, why does >> everybody choose a spectacular example, like exploding keyboards, >> or seg faults? I think the worst thing of all is when undefined >> behavior does exactly what you want it to do, leaving a latent >> bug that will rear its ugly head years later, when you change >> some code totally unrelated to the bug, or upgrade your compiler, >> or... > > Agreed. Good. I think folks like you and me who understand what "undefined behavior" means in C, or "erroneous behavior" in Ada, ought to explain it that way. Too many programmers are puzzled by the concept, which has important implications for language designers (like me). >>>...(C's "undefined behavior" is very much like >>> Ada's "erroneous execution" -- and IMHO C chose a better term to >>> describe it.) >> >> "very much like"? Is there any difference at all? (Other than >> the fact that C has more of it, I mean.) > > There's no actual difference that I'm aware of. I was just being > cautious. > >> I agree on the terms. An even better term, IMHO, would be >> "unpredictable behavior". > > Except that there's no requirement that the behavior must be > unpredictable. > > An implementer is free to define the behavior of some construct > whose behavior is not defined by the language standard. At least > in C, this is a common way to provide extensions. I don't understand your objection: "Undefined behavior" means "the language standard doesn't define the behavior". "Unpredictable behavior", means "you can't predict the behavior based on the language standard". Either way, some particular implementation might define the behavior, or allow you to predict the behavior. Seems like the same thing, to me. The message to convey is "Don't do that!". >>> Furthermore, the order of evaluation of the argument expressions >>> isn't *necessarily* related to the order in which the results are >>> pushed onto the stack (assuming there even is a stack). >> >> There must be a stack. But you're right -- parameters might be >> passed in registers, or some other way, and there's no reason >> to assume that the evaluation order will match the way they're >> passed. > > We've had some lengthy arguments about this over in comp.lang.c. > > Yes, an implementation for a language that supports recursion must > have a stack, in sense of a last-in first-out data structure for > activation records. Right. See my other post, where I claim that's true even without recursion, assuming the language defines LIFO procedure calls. Without recursion and multi-threading, maybe the address of every call frame is known at compile/link time, but still, variables are being created and destroyed in LIFO order. Local variables in Ada or C are not like static variables in C, even if you eliminate recursion. > But the word "stack" is also used to refer to a contiguous chunk > of memory whose "top" is indicated by the address stored in a > "stack pointer". The stack is grown or shrunk by adding to or > subtracting from the stack pointer (not necessarily respectively). > The last-in first-out "stack" of activation records is implemented > using this kind of hardware stack on almost all implementations of > both C and Ada -- but neither language standard requires that it > must be done this way. For example, I've heard about IBM mainframe > implementations in which each new activation record is allocated > from something like a heap, so there's no necessary relationship > among the addresses of local variables for successive calls. > > I note that the word "stack" doesn't even appear in the C standard, > which manages to describe function calling without using the concept. > Ada refers in passing to stacks for tasks an interrupts; I'm not > sure what kind of requirement that imposes. > > I have no doubt that you're aware of all this,.. Thanks for your confidence. ;-) Yes, I'm aware. >...but some readers might > interpret your (quite correct) statement that "There must be a stack" > to mean that there must be a contiguous hardware stack, managed via > a stack pointer register, that grows and shrinks linearly in memory. Thanks for the clarification. I agree with the above, and of course I agree that the stack doesn't have to be a contiguous block of memory. But why do you call that "contiguous stack" thing a "hardware stack"? I mean, on most architectures, push/pop are implemented by subtract/add instructions on the stack pointer register. That's not a whole lot of "hardware support for stacks". The hardware has instructions that support implementing arrays, and linked lists, too, but we don't call them "hardware arrays" or "hardware linked lists". OK, on x86, there are push/pop instructions. But most stack manipulation is still just subtract/add. Call pushes a return address. Enter/leave instructions are stack-oriented, but nobody uses those, because they're slow. Maybe "the stack" on x86 could be called a "hardware stack", but it's pretty marginal in practice. By the way, "the stack" in GNAT is split into primary and secondary stacks. I still call those, taken together, "a stack". - Bob