lufthansa747
lufthansa747

Reputation: 2061

Save & Copy jmp_buf C++

Is it possible and valide to make a copy of jmp_buf and restore it later? something like

jmp_buf oldEnv = env;
int val = setjmp(env);
.......
env = oldEnv;

I have used memcopy() and sizeof(env), to copy jmp_buf data. This seems to work fine. is this just a coincidence?

Upvotes: 4

Views: 3706

Answers (4)

BobG
BobG

Reputation: 2171

There is a lot of inaccurate information in the responses.

Ben is right in that jmp_buf cannot be reliably saved and restored, and cannot be reliably used with automatic objects with non-trivial destructors. However, if the original question is actually how to save multiple non-local goto points, one solution is to just use a jmp_buf stack:

jmp_buf env[2];
int env_index = 0;

// first/outer computation
if (setjmp(jmp_buf[env_index++], 0) == 0) {
   ...
   .. call second/inner computation here ..
   env_index--;
} else {
   ...
   env_index--;
}

// in second/inner computation
if (setjmp(jmp_buf[env_index++], 0) == 0) {
  .. do computation here ..
  env_index--;
} else {
  .. trap code here ..
  env_index--;
}

Regarding setjmp/longjmp vs. try/catch in C++: the only limitation on using setjmp/longjmp is when automatic objects with non-trivial destructors are created but not destroyed between setjmp and longjmp - that is, if I do something like setjmp followed by an auto-variable of std::map<std::string, int> x;, put a value or two into x, then longjmp - the destructor of std::map is not called to clean up the internal map allocation. But if I have something like this:

// some external library written purely in C
extern "C" do_some_floating_point_computation(params...);

void SIGFPE_handler(...) {
  ...
  .. do longjmp back to wrap_C_Computation_Library here ..
  .. after SIGFPE handling ..
}

SomeClass::wrap_C_Computation_Library(...) {
  .. set up SIGFPE handler ..
  .. setjmp ..
  do_some_floating_point_computation(params...);
  .. setjmp error handler
  .. clean up SIGFPE handler ..
}

there is nothing wrong with using setjmp in the class method and longjmp in the SIGFPE handler. (Likewise, trapping some signal across C++ method invocations that don't rely on automatic objects with non-trivial destructors is also ok.)

Upvotes: 1

user1095108
user1095108

Reputation: 14603

The only way to do it safely is to implement your own setjmp/longjmp lookalike. Fortunately this is easy to do for most compiler/architecture pairs.

Upvotes: 0

Ben Voigt
Ben Voigt

Reputation: 283733

You can do that only if you don't do anything with the jmp_buf in the interim. Most notably, you can't call setjmp again, restore the old jmp_buf content, and use longjmp to get back to an earlier setjmp call.

The rule in the C Standard:

The longjmp function restores the environment saved by the most recent invocation of the setjmp macro in the same invocation of the program with the corresponding jmp_buf argument.

Because jmp_buf is "an array type", the call to longjmp is actually passing a decayed pointer; it is the actual address of the jmp_buf that the above verbiage concerning "corresponding jmp_buf argument" references, and not merely its content.

I don't know how the Standard guarantees that you'll return to the context of the most recent setbuf, if you're been mucking with the contents of the jmp_buf, so I would treat any modification of the jmp_buf as making it completely unusable for longjmp purposes.

If you know something about the internal layout on your particular platform, and you're using jmp_buf to save processor context to go into a debug log, that sort of thing is fine. But copies can't be used with longjmp.

Upvotes: 2

Michael Albers
Michael Albers

Reputation: 3779

According to http://en.cppreference.com/w/c/program/jmp_buf the type of jmp_buf is unspecified. So you don't know what you're going to get when you actually use a jmp_buf and sizeof might not be returning the actual size of the storage you're memory you'd want to copy. A memcpy and sizeof probably will work, but since you don't know for certain, you might wind up with all sorts of errors.

This also begs the question why you'd want to copy it? The contents of jmp_buf shouldn't be used at all by you. All that you're doing is providing the storage space for the OS to use when setjmp populates env. Like Ron Popeil said, "Set it and forget it."

Upvotes: 1

Related Questions