GCC – modify where execution continues after function return [closed]

No, this is not possible portably, and I’m not sure to guess exactly what you want to achieve.

Terminology

Perhaps you want some non-local jump. Read carefully about setjmp.h, coroutines, call stack, exception handling, continuations, and continuation-passing-style. Understanding what call/cc is in Scheme should be very beneficial.

setjmp and longjmp

setjmp and longjmp are standard C99 functions (and they are quite fast, because the saved state is actually quite small). Be quite careful when you use them (in particular to avoid any memory leak). longjmp (or the related siglongjmp in POSIX) is the only way in portable standard C99 to escape from some function and get back into some caller.

The idea is to provide an “escape code path” from a deep call chain without any additional overhead

This is exactly the role of longjmp with setjmp. Both are quick, constant-time, operations (in particular unwinding a call stack of many thousands of call frames with longjmp takes a short and constant time). The memory overhead is practically one local jmp_buf per catch point, not a big deal. The jmp_buf is rarely put outside of the call stack.

A common way to use efficiently them would be to put the setjmp-ed jmp_buf in a local struct (so in your call frame) and pass the pointer to that struct to some internal static function(s) which indirectly would call longjmp on error. Hence setjmp and longjmp can, with wise coding conventions, mimic quite well and efficiently the complex semantics of C++ exception throwing and handling (or of Ocaml exceptions, or of Java exceptions, which both have a different semantics than C++). They are portable basic bricks enough for such a purpose.

Practically speaking, code something like:

  struct my_foo_state_st {
    jmp_buf jb;
    char* rs;
    // some other state, e.g a ̀ FILE*` or whatever
  };

  /// returns a `malloc̀ -ed error message on error, and NULL on success
  extern const char* my_foo (struct some_arg_st* arg);

The struct my_foo_state_st is the private state. The my_foo is the public function (which you would declare in some public header). You did document (at least in the comment) that it returns a heap allocated error message on failure, hence the caller is responsible for freeing it. On success, you documented that it returns NULL. Of course, you could have other conventions and other arguments and/or result.

We declare and implement now an error function which is printing the error message into the state and escapes with a longjmp

  static void internal_error_printf (struct my_foo_state*sta, 
       int errcode, 
       const char *fmt, ...) 
   __attribute__((noreturn, format(printf(2,3))));

  void internal_error_printf(struct my_foo_state*sta, 
       int errcode, const char *fmt, ...) {
    va_arg args;
    va_start(args, fmt);
    vasprintf(&sta->rs, fmt, args);
    va_end(args);
    longjmp(sta->jb, errcode);
  }

We now have several possibly complex and recursive functions doing the bulk of the work. I only sketch them, you know what you want them to do. Of course you might want to give them some additional arguments (that is often useful, and it is up to you).

  static void my_internal_foo1(struct my_foo_state_st*sta) {
    int  x, y;
    // do something complex before that and compute x,y
    if (SomeErrorConditionAbout(sta))
       internal_error_printf(sta, 35 /*error code*/,
                            "errror: bad x=%d y=%d", x, y);
    // otherwise do something complex after that, and mutate sta
  }

  static void my_internal_foo2(struct my_foo_state_st*sta) {
    // do something complex 
    if (SomeConditionAbout(sta))
       my_internal_foo1(sta);
    // do something complex and/or mutate or use `sta`
  }

(even if you have dozens of internal functions like above, you don’t consume a jmp_buf in any of them; and you could also recurse quite deeply in them. You just need to pass a pointer -to struct my_foo_state_st in all of them, and if you are single-threaded and don’t care about reentrancy, you could store that pointer in some static variable… or some thread-local one, without even passing it in some argument, which I find still preferable -since more re-entrant and thread friendly).

At last, here is the public function: it sets up the state and do a setjmp

  // the public function
  const char* my_foo (struct some_arg_st* arg) {
     struct my_state_st sta;
     memset(&sta, 0, sizeof(sta));
     int err = setjmp(sta->jb);
     if (!err) { // first call
       /// put something in `sta` related to ̀ arg̀ 
       /// start the internal processing
       //// later,
       my_internal_foo1(&sta);
       /// and other internal functions, possibly recursive ones
       /// we return NULL to tell the caller that all is ok
       return NULL;
     }
     else { // error recovery
       /// possibly release internal consumed resources
       return sta->rs;
     };
     abort(); // this should never be reached
  }

Notice that you can call your my_foo a billion times, it will not consume any heap memory when not failing, and the stack will grow by a hundred of bytes (released before returning from my_foo). And even if it failed a billion times by your private code calling a billion times the internal_error_printf no memory leak happens (because you documented that my_foo is returning an error string which the caller should free) if coding properly.

Hence using properly setjmp and longjmp a billion times does not eat a lot of memory (only a few hundred bytes on the call stack for one single local jmp_buf, which is popped on the my_foo function return). Indeed, longjmp is slightly more costly than a plain return (but it does the escape that return does not), so you would prefer to use it on error situations.

But using setjmp and longjmp is tricky but efficient and portable, and makes your code difficult to understand as documented by setjmp. It is important to comment it quite seriously. Using these setjmp and longjmp cleverly and wisely does not require “gigabytes” of RAM, as wrongly said in the edited question (because you consume only one single jmp_buf on the call stack, not billions of them). If you want more sophisticated control flow, you’ll use a local jmp_buf at each and every dynamic “catch point” in the call stack (and you’ll probably have a dozens of them, not billions). You’ll need millions of jmp_buf only in the hypothetical case of a recursion of several millions call frames, each being a catch point, and that is not realistic (you’ll never have a recursion of a depth of one million, even without any exception handling).

See this for a better explanation of setjmp for “exception” handling in C (and SFTW for other ones). FWIW, Chicken Scheme has a very inventive usage of longjmp and setjmp (related to garbage collection and to call/cc !)


Alternatives

setcontext(3) was perhaps POSIX but is now obsolete.

GCC has several useful extensions (some of them understood by Clang/LLVM) : statement exprs, local labels, labels as values and computed goto, nested functions, constructing function calls, etc.

(My feeling is that you are misunderstanding some concepts, notably the precise role of the call stack, so your question is very unclear; I gave some useful references)

returning a small struct

Notice also that on some ABIs, notably x86-64 ABI on Linux, returning a small struct (e.g. of two pointers, or of one pointer and one int or long or intptr_t number) is extremely efficient (since both pointers or integers go thru registers), and you could take advantage of that: decide that your function returns a pointer to the primary result and some error code, both packed in a single small struct:

struct tworesult_st {
 void* ptr;
 int err;
};

struct towresult_st myfunction (int foo) {
  void* res = NULL;
  int errcode = 0;
  /// do something
  if (errcode) 
    return (struct tworesult_st){NULL, errcode};
  else
    return (struct tworesult_st){res, 0};
}       

On Linux/x86-64 the code above is optimized (when compiled with gcc -Wall -O) to return in two registers (without any stack consumed for the returned struct).

Using such a function is simple and very efficient (no memory involved, the two member ̀ struct` will be passed in processor registers) and could be as simple as:

struct tworesult_st r = myfunction(34);
if (r.err) 
  { fprintf(stderr, "myfunction failed %d\n", r.err); exit(EXIT_FAILURE); }
else return r.ptr;

Of course you could have some better error handling (it is up to you).

Other hints

Read much more about semantics, in particular operational semantics.

If portability is not the major concern, study the calling conventions of your system and its ABI and the generated assembler code (gcc -O -Wall -fverbose-asm foo.c then look inside foo.s) , and code the relevant asm instructions.

Perhaps libffi could be relevant (but I still don’t understand your goals, only guessed them).

You could try using label exprs and computed gotos, but unless you understand the generated assembler code, the result might not be what you expect (because the stack pointer changes at function calls and returns).

Self-modifying code is frowned upon (and “impossible” in standard C99), and most C implementations put the binary code in a read-only code segment. Read also about trampoline functions. Consider perhaps JIT compiling techniques, à la libjit, asmjit, GCCJIT.

(I firmly believe that the pragmatical answer to your concerns is either longjmp with suitable coding conventions, or simply returning a small struct; both can be used portably in a very efficient way, and I cannot imagine a case where they are not efficient enough)

Some languages: Scheme with its call/cc, Prolog with its backtracking features, are perhaps more adapted (than C99 is) to the needs of the OP.

Leave a Comment