Ilya  Pakhmutov
Ilya Pakhmutov

Reputation: 179

Is there some version of longjmp that can output long values?

I'm working on a framework on C language, for it I want to implement exceptions, for it I'm using longjump with setjump, but on x64 machines longjump still outputs an integer.

I've created a class (struct with vptr essentially), which represents exception, but to throw it out in code I need to throw a pointer to this structure. The pointer has an unsigned long long value (qword) for x64 machines and unsigned int (dword) for x86, so I shall require only qword to be in output to handle the error.

Are there implementations of longjmp and setjmp, which can output qword?

Or maybe I could write my own longjump, but for it the original source code is required.

Upvotes: 0

Views: 220

Answers (2)

Alexey Frunze
Alexey Frunze

Reputation: 62086

You can enclose your jmp_buf-typed variable in a larger structure, possibly larger by just sizeof(void*). Then just before calling longjmp() you can store the pointer in that extra space. There's no need to try to squeeze a pointer into an int.

Example:

#include <stdio.h>
#include <setjmp.h>

struct jmp_buf_struct
{
  jmp_buf jb;
  void* exc_ptr;
};

void may_throw(jmp_buf jb)
{
  struct jmp_buf_struct* jbs_ptr = (struct jmp_buf_struct*)jb;
  jbs_ptr->exc_ptr = "Exception message!";
  longjmp(jb, 1);
}

int main()
{
  struct jmp_buf_struct jbs;
  if (setjmp(jbs.jb))
  {
    printf("Threw %p = \"%s\".", jbs.exc_ptr, (char*)jbs.exc_ptr);
  }
  else
  {
    may_throw(jbs.jb);
    puts("Didn't throw.");
  }
  return 0;
}

Output:

Threw 0x55638ebc78c4 = "Exception message!".

Upvotes: 2

Luis Colorado
Luis Colorado

Reputation: 12698

If you want to be portable, then you can use array indexes, to an array where you store all the 64bit pointers (or simply an array of pointers to structures with pages of information about what to do on some exception).

How do you populate such an array is another question. Of course you don't need to populate the array with all the instances that can become an exception, only with the ones you have try-ed and are able to catch. But probably you will need more than just a pointer (as you have to deal with the runtime case in which you have the same exception, catched in multiple active places in your stack.)

Once you solve the above problem, probably you can even use a short int for the thing, once you have understood the nature of the problem you need to solve.

Based on reading the comments, I see you comment that a global variable is not suitable because of multithreading concerns. First, you can have it global, in the context of the thread (as e.g. the errno variable), as that's the reason of using a void * to call the routine the thread executes, and returns back once finished. You can have it there, private to thread global data.

On a second point, if you want to manage such strange things from the point of view of C, as manipulating the stack in weird ways, the functions mentioned do (I don't believe you know completely how the internals of setjmp()/longjmp() work.) I can tell you that the setjmp()/longjmp() api was written a long of time ago (in the range of 50 years now), in the times of old V6 unix code, to cope with unknown unix device drivers error processing ---a very controlled and simple environment---) simply, the use of longjmp() is far more complicated (and strongly discouraged, even by their authors K & R) than switching to a different language (like the suggested C++) that fully supports exceptions in its core (this recommendation is not mine, it has been suggested in the comments to your question)

Third. If you use setjmp() and longjmp() you need to know also that they (both) use the calling thread's stack to mark the pointer and the where to go to store the information. So, you have to control, for example, that if you do a longjmp() in a signal handler, you can severely destroy the stack of the thread executing the signal handler (which is the one that got interrupted by the signal) if it is not the same thread as the one who did the setjmp() call. The reason for this is that the thread interrupted will switch its stack with the one of the thread that did the setjmp() and both threads will begin executing code with the same stack at different points, this jumps back to the time of implementation of both functions (there was only a pdp computer available, no multiple cpus/cores as it is common today, so there was only a stack) You have to be specially careful here, because normally, the thread that generates the exception is the same that the places to catch it, but this can be false for asynchronous traps, like signal processing.

By the way, what you are doing is very interesting, and will allow you to know how a language implements internally complex behaviours like exception processing. I applause you for your courage on trying this kind of things, and don't hesitate, that if you need a mentor in C++ I'll be available for you.

Just don't give up!!

Upvotes: 1

Related Questions