We have implemented "longjmp–Restore stack environment" in our code base. The longjmp
routine is called by a particular error_exit
function which can be invoked from anywhere.
Thus it is possible that when longjmp
is called the setjmp
routine may not have been called and the buffer can have invalid value leading to a crash.
Can I initialise the buffer to NULL
or is there any check available to check for unset or invalid value. One way is that I can set a flag variable whenever setjmp
is called, and I can check against that. But that is only a hack.
void error_exit()
{
extern jmp_buf buf;
longjmp(buf, 1);
return 1;
}
Can I do something like this?
void error_exit()
{
extern jmp_buf buf;
if(buf)
longjmp(buf, 1);
return 1;
}
The code is mixed C/C++, I know I can replace setjmp
and longjmp
with C++ exception handling everywhere, but that is not possible now, can I instead catch longjmp
with invalid buffer which leads to a crash?
jmp_buf
is not particularly well documented. In linux headers, you can find something like:
typedef int __jmp_buf[6];
struct __jmp_buf_tag {
__jmp_buf __jmpbuf; /* Calling environment. */
int __mask_was_saved; /* Saved the signal mask? */
__sigset_t __saved_mask; /* Saved signal mask. */
};
typedef struct __jmp_buf_tag jmp_buf[1];
Setting it to zero and then test whole size may be a lost of time.
Personally, I would keep a pointer to this buffer, initializing it to NULL and setting it right before setjmp.
jmp_buf physical_buf;
jmp_buf *buf = NULL;
...
buf = &physical_buf;
if (setjmp(*buf)) {
...
}
It is the same idea as having a separate flag. Moreover you can allocate jmp buffers dynamically if necessary.
Knowing whether the buffer has been set or not is not a real problem, you could just have an auxiliary variable that holds that information.
The real problem is that you can't longjmp
sideways, this is has undefined behavior and can't work for fundamental reasons. Once you returned from the function in which you have called setjmp
the stack of that function is invalidated and overwritten by subsequent calls. So the setjmp
context isn't valid anymore. And I am not talking of the jmp_buf
itself, but of the stack state that is recorded in it.
So the only thing you can do is to have an auxiliary variable that records if you have set the buffer, and that you unset as soon that you leave the function with the setjmp
in question.
Good question.
As far as I can see from the POSIX standard (http://pubs.opengroup.org/onlinepubs/9699919799/functions/longjmp.html http://pubs.opengroup.org/onlinepubs/9699919799/functions/setjmp.html http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/setjmp.h.html) jmp_buf
is opaque, save that the latter reference requires it to be an array type:
The
<setjmp.h>
header shall define the array typesjmp_buf
and ...sigjmp_buf
.
I believe in practice you would be save bzero()
-ing the buffer, and comparing it against zero before jumping to it, but in theory an all zero jmp_buf
would be permissible on some as yet to be discovered POSIX system. If you were bothered about this (I wouldn't be), an option would be to set_jmp
a dummy buffer to some jump point you never use, and then memcmp
your jmp_buf
against this dummy jmp_buf
before doing the jump. That way you would only use legal (i.e. initialized by set_jmp
) jmp_buf
s.
An alternative would be to maintain a separate flag indicating whether it has been initialised (or wrap both in a struct
).
I believe I should insert the mandatory warning on the manpage re set_jmp
and long_jmp
, in that it makes applications difficult to read, and has unpredictable effects on signal handling (the latter cured with sigsetjmp()
). Also, in a C++ context it obviously does not unwind your exception handlers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With