Talk:Setjmp.h
This is the talk page for discussing improvements to the Setjmp.h article. This is not a forum for general discussion of the article's subject. |
Article policies
|
Find sources: Google (books · news · scholar · free images · WP refs) · FENS · JSTOR · TWL |
This article is rated C-class on Wikipedia's content assessment scale. It is of interest to the following WikiProjects: | |||||||||||||||||||||||||||
|
copyvio
[edit]I've written a new article, using a non-tainted para from the previous version: Talk:Setjmp/longjmp/Temp. EdC 19:36, 16 July 2006 (UTC)
- I have moved that to be the main version. Mangojuicetalk 11:35, 29 July 2006 (UTC)
What is this copyvio all about? Isn't one GFDL project allowed to use information from another GFDL project ??? 209.92.136.131 19:25, 17 July 2006 (UTC)
- Not if the copied text has invariant sections and cover text that the including project is unable to respect. EdC 00:59, 18 July 2006 (UTC)
Just Plain Wrong
[edit]I removed a very verbose section of code, supposedly "...by pietro gagliardi; august 25, 2006" (152.163.100.7)
- Segfaults on the scanf.
- Does not do what the comments say it does
While I could rewrite this code, it's much clearer to just use User:BrianCully's since it exhibits the behavior of setjmp/longjmp in less lines. (I'll test that next, but I have a feeling it's much higher quality code.) krallja 06:50, 27 August 2006 (UTC)
- OK, I realized that User:BrianCully's version doesn't exhibit nonlocal flow control, so I wrote one that basically did what "pietro" was trying to do, except without the pointer mistakes. krallja 07:09, 27 August 2006 (UTC)
Re: Just Plain Wrong
[edit]Sorry, didn't see that. I thought, when I wrote the code, that it was to demonstrate exactly how setjmp/longjmp worked with deeply nested function calls (in my case, up to 4 levels) - pietro gagliardi, october 1, 2006
The second code example could be better
[edit]The second code example has a few problems:
- The "while" would be better as "if", since it's not actually controlling the iteration; "i" is set outside the "loop" each time.
- It prints that longjmp will be called with i, but actually it is called with i + 1.
- It doesn't demonstrate the value being passed from longjmp to setjmp very well.
- It shouldn't give the impression that this is an ok way to iterate. Perhaps a big comment about "for demonstration only, don't actually do this."
I'd be happy to just delete this second exanple.
Please leave it there. That is the simplest way to explain what setjmp/longjmp do.
An example of the fork-like idiom mentioned in the first paragraph of the article would be much better. It would demonstrate not only what setjmp/longjmp does, but why you might want to use it, and give an effective example of how to use setjmp/longjmp in your own code.
The code in the second example still doesn't do what it says it does. If it's so confusing that people editing this article haven't gotten it right after a couple of tries, what are people reading this article in order to learn about setjmp/longjmp going to think?
Speaking of just plain wrong...
[edit]What do other editors think — is it worth reworking all three examples to be proper ANSI C? At the moment, every one of them invokes undefined behavior because the setjmp
invocations are not
- the entire controlling expression of a selection or iteration statement;
- one operand of a relational or equality operator with the other operand an integer constant expression, with the resulting expression being the entire controlling expression of a selection or iteration statement;
- the operand of a unary
!
operator with the resulting expression being the entire controlling expression of a selection or iteration statement; or - the entire expression of an expression statement (possibly cast to void).
(Quoted from N869.) The fix, of course, would be to rework each example to use switch (setjmp(jmp_buf)) ...
, which might be less clear to the layman. I'll make the change in a few days if nobody objects, or points out another interpretation of the Standard on this issue. --Quuxplusone 06:47, 25 November 2006 (UTC)
- No, you're absolutely right; it's one of those lesser-known gotchas. Actually, if you write a para about that issue in the article then that should help explain why the if(setjmp... or switch(setjmp... idiom is used. EdC 11:28, 25 November 2006 (UTC)
Okay, it's done. I added a quote and link to the C99 Rationale, too. I'm going to try to write up an example equivalent to "nested catch blocks" and add it to the page, but if it turns out to be too ugly, I won't add it. I already uglified the first example a little bit with that switch-statement fallthrough, but I wanted to get the idea of catching a specific return value and catching any non-zero return value indiscriminately. --Quuxplusone 19:57, 26 November 2006 (UTC)
Nested catch blocks
[edit]I'm putting this example here rather than in the article because it's so horribly hackish. Most importantly, I realized after writing the above comment that there's no way to "re-throw" an arbitrary status from first
back to main
; the nested function has to "declare" each of the exception types it might re-throw, which I've done with the RETHROW(
value)
macro. N.B.: the memcpy
calls are virtually guaranteed to do the right thing, because jmp_buf
is "an array type suitable for holding the information needed to restore a calling environment". (Still, that doesn't mean it does hold all the information needed to restore the environment — it could be an array[1]
of pointers to records that really hold the data. But that would just be evil.)
- If anyone can come up with a library (not original research :) that uses
setjmp
this way, I think that would be a valuable addition to the article. --Quuxplusone 00:55, 27 November 2006 (UTC)
#include <setjmp.h> #include <stdio.h> #include <string.h> static jmp_buf global_jmpbuf; #define THROW(value) longjmp(global_jmpbuf, value) #define TRY do { jmp_buf tmp; \ memcpy(tmp, global_jmpbuf, sizeof tmp); \ switch (setjmp(global_jmpbuf)) { case 0: #define CATCH(value) break; case value: #define RETHROW(value) break; case value: \ memcpy(global_jmpbuf, tmp, sizeof tmp); \ THROW(value); #define ENDTRY break; } \ memcpy(global_jmpbuf, tmp, sizeof tmp); } while (0) void first(void); void second(void); int main() { TRY { first(); puts("Returned to main."); } CATCH(1) { puts("Caught 1 in main"); } ENDTRY; return 0; } void first(void) { TRY { second(); } CATCH(2) { puts("Caught 2 in first"); } RETHROW(1) ENDTRY; return; } void second(void) { THROW(1); /* THROW(2); */ }
merge with setjmp.h
[edit]Yes, I was too lazy to do it myself, so I just called attention to setjmp.h by adding a little bit of info. Go ahead with merge. Fresheneesz 06:06, 30 November 2006 (UTC)
Suggested change in default case
[edit]Does anyone mind if the default code is changed to:
default: { /* Take any action required on failure. */ printf("first failed, status %d\n", specific_status); break;
The default case is wrong when specific_status is 0, since it says status is nonzero. Nereocystis 21:08, 17 January 2007 (UTC)
- Yes, but specific_status is only 0 when setjmp returns a non-zero value that is not caught by a case label. I've changed it to:
default: { /* Take any action required on failure. */ if (specific_status != 0) printf("first failed, status %d\n", specific_status); else printf("first failed, status unknown\n"); break; }
Hopefully that's clearer. –EdC 21:53, 17 January 2007 (UTC)
Cooperative multitasking
[edit]I just removed the section titled "Cooperative multitasking", which contained a program purporting to use setjmp and longjmp to simulate two threads running concurrently. Unfortunately, that's not the way longjmp works — you can't "longjmp" to a place (such as the middle of child
) that no longer exists. longjmp is similar to C++ exception handling: you can jump around inside a single function, or you can "unwind the stack" to an earlier position, but you can't jump "down" the stack, from main
to child
, and expect anything sensible to happen.
The code may very well work on some implementations, but given that this is an encyclopedia article on the standard C header, which is shared by all implementations, it doesn't make sense to include platform-specific code here. --Quuxplusone 02:11, 15 September 2007 (UTC)
- Something doesn't have to be supported on all platforms in order to be mentioned in an encyclopedia like Wikipedia. A majority or a significant number will do esp. if it's clearly documented
- I've tested this code on Cygwin before posting and my research has shown that this technique is used widely in thread libraries like Really Simple Threads and TinyTimbers. Please list any architechtures on which you know it doesn't work before you say it's platform-specific.
- Perhaps you know of a specification or recommendation that says setjmp cannot be used to jump "down" the stack, but then you refer to it in the section I added instead of deleting it.
-- Nic Roets 19:09, 16 September 2007 (UTC)
- ISO/IEC 9899:1999 7.13.2.1:2:
...if the function containing the invocation of the setjmp macro has terminated execution211) in the interim, or if the invocation of the setjmp macro was within the scope of an identifier with variably modified type and execution has left that scope in the interim, the behavior is undefined.
- Still, if this mechanism is used it should be mentioned. EdC 19:23, 16 September 2007 (UTC)
- 'Anonymous' removed references to C99 and his comment hinted that it's also 'undefined' under C89 and 'probably also K&R'. So he implied that it's not only undefined according to standards documents, but also to most implementations of setjmp. It works under most implementaions. —Preceding unsigned comment added by Nroets (talk • contribs) 15:33, 20 September 2007 (UTC)
"C99 provides that longjmp is guaranteed to work only when (...)" This is an ambiguous wording. I assume you meant to say something like "the only guarantee is that it works when (...)". However, the wording "is guaranteed to work only when(...)" rather suggests a meaning such as "it is guaranteed to fail otherwise". —Preceding unsigned comment added by 92.202.69.70 (talk) 10:12, 25 February 2009 (UTC)
- To a reader unfamiliar with how language standards work, maybe. Be careful if you edit it. Potatoswatter (talk) 02:00, 26 February 2009 (UTC)
Just plain wrong, redux
[edit]The Single UNIX Specification, Version 4 from The Open Group:
: set jump point for a non-local goto – System Interfaces Reference,An application shall ensure that an invocation of setjmp() appears in one of the following contexts only:
* The entire controlling expression of a selection or iteration statement * One operand of a relational or equality operator with the other operand an integral constant expression, with the resulting expression being the entire controlling expression of a selection or iteration statement * The operand of a unary ’!’ operator with the resulting expression being the entire controlling expression of a selection or iteration * The entire expression of an expression statement (possibly cast to void)
If the invocation appears in any other context, the behavior is undefined.
Taking the return of setjmp
is undefined behaviour. It may work on your platform, but it is not portable. EdC (talk) 01:59, 14 April 2008 (UTC)
Adding a simpler example
[edit]A simpler example before the first one may be useful to smooth out the learning curve:
#include "stdio.h" #include "setjmp.h" jmp_buf jmpbuf; void func() { longjmp(jmpbuf, 1); } int main(void) { if (!setjmp(jmpbuf)) { puts("First time."); func(); } else puts("Second time."); return 0; }
- It's simple, but it may not force students to think. Setjmp is in any case a highly advanced / specialized topic. With both this one and the current example, I'd like change the order of the if-then-else around e.g. if(setjmp()) { puts("second"); } else { ... }. And add local variables. -- Nic Roets (talk) 22:23, 1 March 2009 (UTC)
- The if-then-else is that way to keep control flow more "linear". Local variables are a big to-do, but make sure to be perfectly compliant and to demonstrate exactly what you want. Potatoswatter (talk) 09:28, 2 March 2009 (UTC)
Deletion of limitations section
[edit]Per this diff:
Potatoswatter, would you please explain the deletion of this material. You wrote in the edit summary that the issue was "already addressed". However, I do not see any material indicating that returning from the function which called setjmp will invalidate the jump buffer. Maybe I'm missing something. Before you delete the content again, would you please indicate where in the article this is explained? I am asking, because this is a fairly common error and, after a very lengthy debugging session due to this error, I think it would be useful for programmers if the Wikipedia article mentioned this limitation. Thank you for your time and for your consideration.
← Michael Safyan (talk) 00:45, 29 July 2008 (UTC)
- Check the first paragraph of the "preemptive multitasking" section:
C99 provides that longjmp is guaranteed to work only when the destination is a calling function, i.e., that the destination scope is guaranteed to be intact. Jumping to a function that has already terminated by return or longjmp is undefined.[6] However, most implementations of longjmp do not specifically destroy local variables when performing the jump. Since the context survives until its local variables are erased, it could actually be restored by setjmp. In many environments (such as Really Simple Threads and TinyTimbers), idioms such as if(!setjmp(child_env)) longjmp(caller_env); can allow a called function to effectively pause-and-resume at a setjmp.
- Although it can be seen as an error, it can also be seen as thinking wishfully for additional functionality which, with a little extra care, is usually possible to achieve. Did you try executing the "paused" function atop a stack cushion? Potatoswatter (talk) 01:02, 29 July 2008 (UTC)
- Thank you for the offer of help. I already fixed the problem. Basically, I had a wrapper around a setjmp call. Since the wrapper returned, the corresponding call to longjmp reset the stack pointer beyond the length of the stack. On the next instruction after setjmp, which compared the result of setjmp, the program aborted with KERN_PROTECTION_FAILURE: EXC_BAD_ACCESS. Go GDB! Removing the wrapper and calling setjmp directly fixed the problem. In my case, I was using setjmp/longjmp for exception handling emulation, using for loops and lots of macros to make it look like normal exception handling (albeit with a different set of "keywords").
- Back onto the subject of the Wikipedia article, I think that this material deserves its own section or -- at the very least -- it should not be lumped in with an explanation of a particular use of setjmp/longjmp, since this limitation applies to all uses of setjmp/longjmp. I personally think that my explanation is clearer, since the emphasis in what you quoted is on calling longjmp immediately after setjmp, not on performing an ordinary return after setjmp. Perhaps the limitations section might contain two paragraphs: one on returning after setjmp (what I wrote) and one on calling longjmp after setjmp (moved from the "Preemptive multitasking" section)?
- Thank you for your time and consideration. Have a good day. ← Michael Safyan (talk) 04:19, 29 July 2008 (UTC)
- Maybe there should be a "caveats" section to collect the different usage nuances, also including what you're allowed to do with the return value. Calling it a limitation seems misleading, because a limitation is something that can't be overcome just with elbow grease. For what it's worth, the stack cushion method likely would re-enable your exception mechanism, although that's clearly not the way to go. Potatoswatter (talk) 05:41, 29 July 2008 (UTC)
- You're right. "Caveats" is probably a better section title than "Limitations." I will rename the section and try to reorganize the material, and you can always leave me a message if there's something you don't like.
- ← Michael Safyan (talk) 09:00, 29 July 2008 (UTC)
- Cool. That section should be updated to exactly reflect the semantics defined by C99 for local variables, "soon." Potatoswatter (talk) 15:44, 29 July 2008 (UTC)
Multitasking
[edit]Hi. The section on multitasking seems to imply that setjmp/longjmp can only be used for cooperative multitasking. However, I have implemented a user thread library with preemption based on setjmp/longjmp. I would be happy to provide the example as public domain on Wikipedia. My only concern about doing so is that the source may be too long for the article; the header "uthr.h" is roughly 80 lines and the source file "uthr.cpp" is roughly 1500 lines. The example uses sigaltstack to ensure that the threads run on separate stacks, so that if one of the stacks is overrun, it will not silently corrupt the stack of one of the other threads. For preemption, it uses the setitimer function; this could be replaced with SetTimer on Windows. Anyway, are there any thoughts on this? Here is the header file to give a small sample:
- [code snipped to save space]
Comments? Thoughts? Thank you in advance for your responses. ← Michael Safyan (talk) 00:02, 31 July 2008 (UTC)
- Impressive turnaround, but it's not encyclopedic. Please don't promote your own work on WP. A quick search turns up a plethora of simple threading libs, but I don't see any so small or unspecialized... possibly because pthreads are so easy and portable, and the principle of dividing the initial stack space often scales and ports badly. Potatoswatter (talk) 07:04, 31 July 2008 (UTC)
- I wasn't trying to use Wikipedia to promote my work. The only reason I would want my name to remain there is because if a professor or employer of mine sees my code on Wikipedia, I don't want him to think that I simply copied it from Wikipedia. Anyway, more to the point, I was wondering if it would be worth explaining in the multitasking section that setjmp/longjmp can be used for preemptive multitasking, not just cooperative multitasking, if there is a timer handy. I was also wondering if it would be worth mentioning that, using sigaltstack, silently overrunning one stack into another can be avoided. And if it is worth mentioning these things, if there were any suggestions of how to go about it. Or should I just be bold? This source demonstrates/explains/mentions using sigaltstack to give each thread a separate stack. ← Michael Safyan (talk) 14:33, 31 July 2008 (UTC)
- Threading is complicated and you can always find a way to improve a particular implementation. Preemptive multitasking tends to get easier when there's a timer available ;v) ; a cooperative thread system plus a timer pretty much satisfy the requisites. Threading in general is on the fringe of this article's scope since both the standard and most particular implementations only support the restored-child mechanism incidentally. Typically application developers don't implement basic threading systems and OS developers don't do it in C. Also, posting your work here is promoting it even if your name isn't attached. Potatoswatter (talk) 23:05, 31 July 2008 (UTC)
Exception handling
[edit]There appears to me to be a bug of sorts in the sample code under this heading. If second() were to hypothetically complete successfully and return, first() would then also return without restoring the exception stack. If some hypothetical later part of the program were to then raise an exception and longjmp() to exception_env, it would find exception_env still containing the environment of the now non-existent first(). Is there some additional subtlety I'm missing here? 203.171.85.67 (talk) 04:11, 18 July 2009 (UTC)
- I agree; I fixed it. Potatoswatter (talk) 11:20, 18 July 2009 (UTC)
"Alternatives"/"modern use" of setjmp
[edit]Reading over this, I get the impression that use of setjmp/longjmp is sort of considered like wanton use of goto (meaning goto used more than one single time as a well-defined and quick exit that can avoid having the visual nesting-nightmare that a do..while(0) construct can become..) Something that should almost never be done, in favor of "better" constructs in newer languages - the language-level support for exceptions in C++, call/cc in Scheme/LISP (?), explicit coroutine syntax in whatever languages use them, system-level threading and multi-tasking constructs, etc. Is this impression correct, that setjmp is basically how exceptions were implemented before C++ existed (and possibly how exceptions were implemented in C++ compilers)? If so, are there any circumstances where setjmp should be used in modern programming languages, other than embedded systems if using C++ would be prohibitive on a memory/processor/etc basis.Jimw338 (talk) 17:51, 21 April 2012 (UTC)
- I think most embedded C programmers will tell you that they had never used setjmp(). If they want run 2 different "tasks", they either use some operating system or they break one of the tasks down into a state machine. And some people are able to write perfectly good code without ever using any form of exception handling.
- So I think setjmp() is most useful when (a) someone who is used to exception handling is asked to write C code or (b) someone wants cooperative multitasking with the highest possible level of portability or (c) (the most likely scenario) a C programmer wants to brag about how sharp and versatile his language is. -- Nic Roets (talk) 21:32, 21 April 2012 (UTC)
- C++ exceptions are not usually implemented on top of setjmp. They are designed to execute under really exceptional circumstances, usually by performing table lookups mapping return addresses from the stack to catch blocks and local object destruction segments. This cuts the cost of not taking an exception to zero, but it's not appropriate for very small embedded systems because the table lookup mechanism involves a lot of code. (The tables themselves may as well, but a correct C program would manually implement the same anyway.) On the other hand, setjmp is not a dedicated exception mechanism.
- The portable way to do coroutines is with checkpointing/state machines. The article notes that setjmp-based coroutines are not standard-compliant.
- setjmp is rarely appropriate. It's not particularly lightweight as the jmp_buf structure may be large, but it is lighter weight than the common alternative of returning a status flag from every function. Problems arising from its use are hard to debug. Potatoswatter (talk) 06:05, 23 April 2012 (UTC)
Messy Examples and Unwarranted Revert
[edit]It's no secret that all three code examples are slightly messy. And I'm no expert on this whole editing Wikipedia thing kids these days do but after an attempt at cleanup by User:82.9.176.6 (Me), User:Schily reverted the change because apparently "int main(void) is wrong."
I'm not entirely sure how it is "wrong." Two other functions in that example (first() and second()) are already declared this way. This is common occurrence and is used all over the latest C99 Draft which this code is supposed to conform to.
I wanted to just revert this unwarranted revert but I expect it will just devolve to a war. Does anyone have anything wrong with reverting the change? I don't see anything wrong with the proposed code: https://en.wikipedia.org/w/index.php?title=Setjmp.h&oldid=668969362#Exception_handling
It compiles fine under gcc -std=c99 -pedantic -Wall -Wextra with no errors or warnings and the only warnings given by clang -std=c99 -pedantic -Weverything are regarding unreachable code and functions which should be noreturn. And also, I personally find it much cleaner.
Arch-TK (talk) 21:07, 26 July 2015 (UTC)
- Just because something is mentioned in C99 does not verify that it is correct C. Note that one very important basic of the C language is that the existence and position of spaces and comments does not change the code. C99 introduced // as a comment sign and thus made a decision against this basic rule, as compilers that allow // cannot disregard the position of spaces/cmments anymore. Even worse: compilers that allow // need to make existing old and correct C programs invalid in order to do so. Given the fact that main() is always called with three parameters (argc, argv, env) int main(void) would be in conflict with a platform that offers a protoype for main(). Schily (talk) 10:12, 27 July 2015 (UTC)
int main(void)
has been correct since C89 (I don't know of a PDF it would be legal to link to, sorry—but see C89 §2.1.2.2 a.k.a. C90 §5.1.2.2.1 if you can find a copy of either), so any implementation that disallows this is wrong and has been wrong for at least 26 years. Also, one of the code examples is preceded by the remark: "The following code adheres to the 1999 ISO C standard", so expecting it to be written in some sort of lowest-common-denominator dialect seems unreasonable.
- I'm not sure what your comment about
//
is supposed to demonstrate, but if you're saying C99 is broken and silly, this isn't the best evidence for it. Comments are deleted during tokenization (C89 §2.1.1.2, C90 §5.1.1.2, C99 §5.1.1.2), a translation phase traditionally handled by the preprocessor; other preprocessor features are (and always have been) sensitive to the kind of whitespace given:
- I'm not sure what your comment about
#define ok this is ok
#define bad this
isn't ok
char *c = "this is a correct string literal";
char *d = "this is a
syntax error";
- Also, the existence of comments can be significant:
{
int a = 2, b = 4;
int c = a+++b; /* 6 */
}
{
int a = 2, b = 4;
int c = a+/**/++b; /* 7 */
}
- FWIW, I have never seen an implementation that declares a prototype for
main
, and since prototypes were invented by the same standard that disallowed providing one formain
, I don't imagine they are very common. 86.163.139.100 (talk) 10:41, 27 July 2015 (UTC)
- FWIW, I have never seen an implementation that declares a prototype for
- Your point seems to revolve around how, on certain implementations, this might not work. But this is irrelevant since the code is meant to conform to C99 and that implies a C99 compliant implementation. If someone tries to compile C99 code on a compiler which doesn't fully implement C99 then any issues are their problem. You can say, "But it might not work on a shitty implementation." But you can say that about any code and use it to dismiss anything as "wrong." (Also, I'm not sure about the legality of posting that link so I just replaced it with a link to the C99 page where I found the document.) Arch-TK (talk) 12:16, 27 July 2015 (UTC)
- This is correct C:
int a = 9; a //* comment */= 3;
A K&R cpp converts this into:
int a = 9; a /= 3;
Your example is based on the precedence of ++ before +. AFAIR: int main(void) is something that was introduced by C++ and not valid in C, but I'll check for a C89 standard and read. Schily (talk) 12:51, 27 July 2015 (UTC)
- You have a third opinion from User:86.163.139.100 and you've been given the EXACT sections for the C89, C90 and C99 standards. The only relevant of which should be C99 (§5.1.2.2.1) because that's the standard to which this code should adhere. I would consider this issue resolved. But I don't understand where you are getting your reasons from. The standard explicitly states that no prototype is provided for main and that it should either be defined as
int main(void) {...}
orint main(int argc, char *argv[]) {...}
. Nothing more, nothing less. Additionally, main is also defined like this in example #7 at §7.8.1 C99 (or example #7 at §7.7 in C90). Finally, you mentioned (argc, argv, env) as three parameters passed to main, but the C standard doesn't mention this anywhere, as far as I can see, in the latest C99 or C90 drafts.(§J.5.1)- Arch-TK (talk) 12:34, 28 July 2015 (UTC)
- You have a third opinion from User:86.163.139.100 and you've been given the EXACT sections for the C89, C90 and C99 standards. The only relevant of which should be C99 (§5.1.2.2.1) because that's the standard to which this code should adhere. I would consider this issue resolved. But I don't understand where you are getting your reasons from. The standard explicitly states that no prototype is provided for main and that it should either be defined as
- I now remember why I reverted the int main(void). This was because I associated this with void main() from C++ programs and this is definitely something really obscure. Schily (talk) 09:56, 30 July 2015 (UTC)
- So... Does this mean I can revert your revert or is there anything else you have an issue with? Arch-TK (talk) 16:49, 30 July 2015 (UTC)
- I now remember why I reverted the int main(void). This was because I associated this with void main() from C++ programs and this is definitely something really obscure. Schily (talk) 09:56, 30 July 2015 (UTC)
Stack cushion
[edit]Very nice article. However, could anyone explain why this stack cushion thing works or give some reference. It seems to me like plain magic. I don't know why it works. But it definitely does. (I googled it, but came up with just a lot of cushions) 188.146.129.53 (talk) 21:34, 29 November 2015 (UTC)
- Right, so basically that code is like a giant undefined behaviour which is not portable across implementations and might blow up in your face, but I imagine it works something like this: Let's say that things are implemented as such: return values are stored in eax, setjmp is implemented so that it stores the values of the registers in a variable and longjmp is implemented so that it just restores these values back to their respective registers and sets eax. So, we enter our program and have our first stack frame for main, we setjmp into our first jump buffer, this now has all the registers. Now we call "call_with_cushion", this creates a new stack frame on top of main's stack frame, and then makes space on the stack for an array of size 1000, and then calls "child" which creates the next stack frame. child now setjmps to the second jump buffer, this is important, the register values stored in this jump buffer make ESP point somewhere down the stack from main, about 1000 bytes away from main's stack frame, now we longjmp to main, this is the important part, since we're now in main, ESP now points back up at where main is and since main can do whatever it wants to do, it can wipe all the stuff which is on down stack which belongs to the stack frames of call_with_cushion and child, this is why the second jump buffer is now invalidated since it has an ESP pointing to memory which may or may not have been overwritten which means that if we did longjmp there we would not know what would happen, basically lots of UB. So now main can do its thing, push things on the stack, pop things from the stack, and if we didn't have a "call_with_cushion" and those 1000 bytes of spare space, the stack frame for child would be long gone, but hopefully it isn't, since when main finishes whatever it was doing (calling printf) we now longjmp with that invalid buffer, this sets the registers to look as they did before with the only difference being that eax is now 1 (return value) and now child can continue doing its things.
- The main issue with this approach is that C is implementation ambiguous. The C standard doesn't care how you implement things, or what the ABI is, or how setjmp and longjmp are done, this is why this stuff is hidden from the programmer since it's all platform and implementation dependant, if the implementation of C didn't use a stack (unlikely but nothing says impossible) or some other important detail differed, this code would be screwed.
- So in short, I'll run over this again, memory looks like this when child is first called |main SF|call_with_cushion SF <1000 bytes of space>|child SF|, we longjmp back to main which means this could happen |main SF leaking into call_with_cushion SF but hopefully not reaching the 1000 bytes limit|child SF (technically invalid)|, and then we longjmp back to child hopefully as long as child's SF hasn't been overwritten.
- I'm tired and I'm not sure how best to describe this, so sorry for the vagueness, I might write this up nicely and put it on the wikipedia page.Arch-TK (talk) 23:08, 1 December 2015 (UTC)
External links modified
[edit]Hello fellow Wikipedians,
I have just modified one external link on Setjmp.h. Please take a moment to review my edit. If you have any questions, or need the bot to ignore the links, or the page altogether, please visit this simple FaQ for additional information. I made the following changes:
- Added archive https://web.archive.org/web/20090726081425/http://www.uwm.edu/cgi-bin/IMT/wwwman?topic=setjmp%283%29&msection= to http://www.uwm.edu/cgi-bin/IMT/wwwman?topic=setjmp%283%29&msection=
When you have finished reviewing my changes, you may follow the instructions on the template below to fix any issues with the URLs.
This message was posted before February 2018. After February 2018, "External links modified" talk page sections are no longer generated or monitored by InternetArchiveBot. No special action is required regarding these talk page notices, other than regular verification using the archive tool instructions below. Editors have permission to delete these "External links modified" talk page sections if they want to de-clutter talk pages, but see the RfC before doing mass systematic removals. This message is updated dynamically through the template {{source check}}
(last update: 5 June 2024).
- If you have discovered URLs which were erroneously considered dead by the bot, you can report them with this tool.
- If you found an error with any archives or the URLs themselves, you can fix them with this tool.
Cheers.—InternetArchiveBot (Report bug) 16:36, 12 June 2017 (UTC)