39

Big picture: I have a module with functions and a module with procedures and functions over those functions.

When I combine two functions (from function's module interface):

double f1(double alpha, double x);
double f2(double beta, double x);

In several ways, (one of them is adding):

double OP_Addition(double (*f)(double,double) , double (*g)(double,double), double param1, double param2, double x);

Gives no problem with the following (piece of) implementation:

z1 = (*f)(param1, x);
z2 = (*g)(param2, x);
y = z1 + z2;
return y;

But when I want to return a pointer to a "new" function, something like:

void *OP_PAdd( double (*f)(double,double), double param3 );

I can not get it to work properly, neither make the right "call". I want to have use the output "function" as input in other functions.

dbush
  • 205,898
  • 23
  • 218
  • 273
MCL
  • 566
  • 4
  • 16
  • 1
    I don't understand what you're trying to do and what you mean by "can not get it to work properly". – melpomene Jun 11 '16 at 19:18
  • 6
    Note that C does not have lambdas (AKA anonymous functions). You can return a pointer to function in C, but that function must be declared at compile time. E.g. you can't take an integer and return a function adding such integer to its parameter. Or take two function pointers and return a pointer to the pointwise sum of these two functions. There might be some nonportable libraries for lambdas (or partial application), and lambdas are built-in in C++ now, but there's no built-in support in C. – chi Jun 11 '16 at 22:14
  • 2
    @chi *yet*. WG14 seems to like [this proposal](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2030.pdf) to add lambdas to the language for C2X. – Alex Celeste Jun 11 '16 at 22:51
  • Why do you ask, and what actual application do you have in mind? – Basile Starynkevitch Jun 12 '16 at 15:17
  • 2
    Functions are not first order objects in C. You can pass around pointers to existing functions, but functions itself are not objects that can be created or passed by value. I suspect you may come from a functional or dynamically typed language background (OCaml, Haskell, Python, Ruby, Lisp), where functions *are* first order objects. Note that this is not an inherent limitation of imperative low-level programming. There are other compiled system programming languages where functions are first order objects. Also as @chi pointed out there's a proposal to add this to C2x. – datenwolf Jun 12 '16 at 15:29
  • Can you give a more concrete example of what you're trying to accomplish? Perhaps then we can offer a more concrete answer. – dbush Jun 23 '16 at 15:20

7 Answers7

32

When returning a function from another function, the cleanest way to do this is with a typedef:

typedef double (*ftype)(double, double);

Then you can declare your function like this:

ftype OP_PAdd( ftype f, double param3 )
{
    ....
    return f1;
}

You can do this without a typedef, but it's messy:

double (*OP_PAdd( double (*f)(double,double), double param3 ))(double,double)
{
    return f1;
}

So when you have function pointers as either parameters or return values of other functions, use a typedef.

EDIT:

While you could declare the type like this:

typedef double ftype(double, double);

You can never directly use a type like this in practice. A function can't return a function (only a pointer to a function), and a variable of this type can't be assigned to.

Also, you don't need to explicitly dereference a function pointer to call the function, so the fact that the pointer itself is hidden is not a big issue. It's also convention to define function pointers as a typedef. From the man page for signal:

   #include <signal.h>

   typedef void (*sighandler_t)(int);

   sighandler_t signal(int signum, sighandler_t handler);
dbush
  • 205,898
  • 23
  • 218
  • 273
  • 2
    I don't like hiding pointers behind typedefs. I think it's better to make `ftype` an actual function type, then return `ftype *`. – melpomene Jun 11 '16 at 19:24
  • 11
    In general, yes it's not a good idea to hide pointers within typedefs. But the case of functions, it's unavoidable. There's no such thing as a function type, only a pointer to a function. – dbush Jun 11 '16 at 19:26
  • 7
    Nonsense: `typedef double ftype(double, double); ftype *OP_PAdd(ftype *f, double param3);` – melpomene Jun 11 '16 at 19:28
  • @melpomene; Moreover, typedefing function in this case makes code clean and more readable. – haccks Jun 11 '16 at 19:41
  • "*You can never directly use a type like this in practice.*" You actually can, for silly reasons: `void foo(ftype f)` works. – melpomene Jun 11 '16 at 20:15
  • 1
    @melpomene Functions in parameters are automatically adjusted to function pointers. – uh oh somebody needs a pupper Jun 12 '16 at 06:10
  • @melpomene: I can think of lots of good reasons to never hide "object pointers" (C's term for non-function pointers) behind typedefs, but none of them apply to function pointers. And the implicit function-to-function-pointer conversion obviously makes the distinction less significant. Can you explain your rationale for applying such a rule to function pointers? – ruakh Jun 12 '16 at 19:52
  • @haccks I never argued against `typedef`ing in general. – melpomene Jun 12 '16 at 19:57
  • @sleeptightpupper Yes, that's the silliness I was referring to. – melpomene Jun 12 '16 at 19:57
  • @ruakh No, at this point it's just a gut feeling. I don't have a good argument. – melpomene Jun 12 '16 at 19:58
25

Other answers are correct and interesting, but you should be aware that in portable C99, there is no way to have genuine closures as C functions (and this is a fundamental limitation of C). If you are not aware of what closures are, read the wiki page carefully on them (and also read SICP, notably its §1.3). Notice however that in C++11 you do have closures, using std::function and lambda-expressions. And most other programming languages (Ocaml, Haskell, Javascript, Lisp, Clojure, Python, ....) have closures.

Because of the lack of genuine closures in C ("mathematically" the only closed values in C functions are global or static variables or literals), most libraries accepting C function pointers provide an API handling callbacks with some client data (a simple example could be qsort_r, but more seriously look inside GTK). That client data (generally an opaque pointer) can be used to keep closed values. You probably want to follow a similar convention (so systematically pass function pointer as callbacks with some additional client data), so you'll need to change the signatures of your C functions (instead of passing just a raw function pointer, you'll pass both a function pointer and some client data as a callback, to "emulate" closures).

You could sometimes generate a C function at runtime (using non-standard features, probably with the help of the operating system or some external library). You might use some JIT compiling library such as GNU lightning, libjit (both would generate some slow-running code quickly), asmjit (you'll generate each machine instruction explicitly, and it is your responsibility to emit fast x86-64 code), GCCJIT or LLVM (both are above existing compilers so can be used to emit -a bit slowly- some optimized code). On POSIX & Linux systems, you could also emit some C code in some temporary file /tmp/tempcode.c, fork a compilation (e.g. gcc -fPIC -Wall -O2 -shared /tmp/tempcode.c -o /tmp/tempcode.so) of that code into a plugin, and dynamically load that generated plugin using dlopen(3) & dlsym(3)..

BTW we don't know what the actual application you are coding is, but you might consider embedding inside it some interpreter, e.g. Lua or Guile. You'll then use and provide callbacks to the embedded evaluator/interpreter.

tRuEsAtM
  • 3,517
  • 6
  • 43
  • 83
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • 1
    DV because "...there is no way to have genuine closures as C functions" - I just explained how to do it, without relying on machine-dependent inline assembly, and only using standard functions. – DeftlyHacked Aug 19 '16 at 07:51
  • I down-voted because I feel you assumed they meant newly generated when they stated "new" (their quotes, not mine), and the general discussion of closures and other languages - Since they specified C as a tag, this was largely irrelevant, although it was quite interesting :). I did appreciate loading in a newly compiled module, as I've done that in the past. I would remove the down-vote if you added a something similar to @dbush's answer. – HungryBeagle Aug 25 '16 at 14:24
13

Do you mean something like this? The decider() function returns a pointer to another function, which is then called.

#include <stdio.h>
#include <stdlib.h>

typedef double(*fun)(double, double);

double add(double a, double b) {
    return a + b;
}

double sub(double a, double b) {
    return a - b;
}

double mul(double a, double b) {
    return a * b;
}

fun decider(char op) {
    switch(op) {
        case '+': return add;
        case '-': return sub;
        case '*': return mul;
    }
    exit(1);
}

int main(void)
{
    fun foo;

    foo = decider('+');
    printf("%f\n", foo(42.0, 24.0));

    foo = decider('-');
    printf("%f\n", foo(42.0, 24.0));

    foo = decider('*');
    printf("%f\n", foo(42.0, 24.0));

    return 0;
}

Program output:

66.000000
18.000000
1008.000000

EDIT: Following comments under the @dbush answer, this version steps back from the typedef as a pointer, to just a function. It gives the same output, but in decider() it compiles cleanly and gives the correct output, no matter whether I write return add; or return &add;

#include <stdio.h>
#include <stdlib.h>

typedef double(fun)(double, double);

double add(double a, double b) {
    return a + b;
}

double sub(double a, double b) {
    return a - b;
}

double mul(double a, double b) {
    return a * b;
}

fun *decider(char op) {
    switch(op) {
        case '+': return add;     // return &add;
        case '-': return sub;
        case '*': return mul;
    }
    exit(1);
}

int main(void)
{
    fun *foo;

    foo = decider('+');
    printf("%f\n", foo(42.0, 24.0));

    foo = decider('-');
    printf("%f\n", foo(42.0, 24.0));

    foo = decider('*');
    printf("%f\n", foo(42.0, 24.0));

    return 0;
}
Weather Vane
  • 33,872
  • 7
  • 36
  • 56
  • @melpomene interesting comments under **dbush** answer, so I added a second version here. But I am unsure why the function return value works both ways, as I remarked in the revision. – Weather Vane Jun 11 '16 at 19:51
  • 1
    C is very loose about converting function types to function pointer types. For example, to get a pointer to a function, you can use the function name by itself, or you can apply the address-of operator `&`, and it will work either way. Similarly, when invoking a function through a function pointer, you can explicitly dereference the pointer when calling the function, or you can omit the `*` and again it will work either way. I personally would prefer it if C were more strict about requiring the address-of and dereference operators, but for historical reason it's not. – Tom Karzes Jun 11 '16 at 20:05
  • @TomKarzes thank you, I was expecting `return add;` to generate a compiler error along the lines of "ill-formed function call". – Weather Vane Jun 11 '16 at 20:07
  • Perhaps there is a parallel with this: `char str[42];` followed by `scanf("%s", str);` or `scanf("%s", &str);` In MSVC either is acceptable but in an earlier question I was told the latter is an error. Certainly it would be if `str` was a pointer, not an array. – Weather Vane Jun 11 '16 at 20:11
  • @WeatherVane: `&str` has the wrong type and a modern compiler which checks those variadic arguments against the format string should definitively warn about that type-missmatch. – too honest for this site Jun 11 '16 at 20:25
  • @Olaf my point was why is it right with a function but not with an array? How can `str` give anything different to `&str` when `str[]` is an array (not a function argument)? – Weather Vane Jun 11 '16 at 23:03
  • 1
    @WeatherVane: Not sure I know what you mean. `str` and `&str` **do** yield a different result! Most likely not the value (buit even that is not guaranteed), but just the type, but they differ very well. – too honest for this site Jun 11 '16 at 23:12
  • @Olaf part of my edit to this answer, was to ask why the function is acceptable either as `add` or `&add` and was drawing a comparison with the array example using `str` or `&str`. In both examples, each coding give *exactly* the same result. – Weather Vane Jun 11 '16 at 23:20
  • 1
    @WeatherVane: Again: It might give the same **assembler code**, but not the same result. A function name will be converted to a pointer to that function, as will `&func`. For an array, the types will not be the same. So different semantics and any better compiler will warn about a type conflict for the array-case. – too honest for this site Jun 11 '16 at 23:23
  • @Olaf I repeat: `scanf("%s", str);` and `scanf("%s", &str);` have **exactly** the same result. What else could possibly be different? There is only one piece of information about the array `str` apart from its type and size. – Weather Vane Jun 11 '16 at 23:26
  • 2
    @WeatherVane The compiler knows the difference. The latter will generate a warning: `format ‘%s’ expects type ‘char *’, but argument 2 has type ‘char (*)[6]’` – dbush Jun 11 '16 at 23:30
  • @dbush we have been through that. I am asking why it's ok for a function but not for an array. OIaf said the assembler code might be the same, but... that's my point: it's the same. – Weather Vane Jun 11 '16 at 23:31
  • 1
    @WeatherVane: It is wrong from the language aspect. And an implementation might generate different values (e.g. if the type is encoded in the pointer - unlikely for current systems, but allowed). Also the compiler might generate any kind of code, as that invokes undefined behaviour. For a function, it is well defined that both `func` and `&func` **here** generate excactly the same result (i.e. including the same type). Things differ for e.g. `sizeof` where `sizeof(func)` is UB per definitionem. – too honest for this site Jun 11 '16 at 23:37
  • But surely a reference to the array `str` decays to a pointer, whereas `&str` is the address of the array, which is the same thing. So what *is* the difference? – Weather Vane Jun 11 '16 at 23:41
  • 1
    @WeatherVane; `str` and `&str` are not the same thing. `str` will decay to *pointer to it's first element* while `&str` is the address of array `str` itself. In case of `function` both `func` (after conversion) and `&func` are address of function. There is nothing like elements in case of function. – haccks Jun 12 '16 at 08:59
3

in C, you can return pointer to function, but to do that, function needs to exist first, and dynamically creating functions is not something C says is possible, never mind how to do it

if your code is going to work only on one OS and one processor (and probably some other restrictions), you may be able to:

  1. allocate page of memory
  2. write data and machine code doing what you want, calling functions passed by pointer etc.
  3. change memory protection from read/write to read/execute
  4. return pointer to created function
  5. don't worry that you you need 4kB per function

there probably are somewhere libraries for that, but necessarily not portable

Jordan Szubert
  • 176
  • 1
  • 1
  • 4
  • Some libraries are able to generate a new C function (with non-portable tricks or operating system help). See [my answer](http://stackoverflow.com/a/37775530/841108). – Basile Starynkevitch Jun 12 '16 at 15:01
0

So you want a function to return a pointer to a function.

double retfunc()
{
   return 0.5;
}

double (*fucnt)()
{
  return retfunc;
}

main()
{
   printf("%f\n", (*funct())());
}
Bing Bang
  • 524
  • 7
  • 16
0

Since some people are apparently paranoid about writing a hack to solve this problem, here's a less-hacky way to do it: Use a static struct with setjmp and longjmp.

jmp_buf jb;

void *myfunc(void) {
    static struct {
        // put all of your local variables here.
        void *new_data, *data;
        int i;
    } *_;
    _ = malloc(sizeof(*_));
    _.data = _;
    if (!(_.new_data = (void *)(intptr_t)setjmp(jb)))
        return _.data;
    _.data = _.new_data;
    /* put your code here */
    free(_);
    return NULL;
}

To explain what's going on here, setjmp will return a value of 0 when the jump buffer is created, otherwise it'll return the value passed by longjmp (eg. longjmp(jb, 5) will cause setjmp to return 5).

So, what we're doing is having our function return a pointer to it's allocated data structure; and then calling our closure like:

void *data = myfunc();
longjmp(jb, (int)(intptr_t)data);

Please note that an int is not guaranteed to be large enough to store a pointer on all platforms; so you may need to create a data pool and return/pass the data by handle (index in the pool).

As I've stated before, a closure is just a function with all of it's data allocated on the heap.

I've been writing hacks for N64 and PSP games for years. People claiming that this is impossible have likely never tinkered with that kind of stuff. Mostly just boils down to a lack of experience.

DeftlyHacked
  • 405
  • 2
  • 9
  • 1
    Interesting hack. Unfortunately it is not standard conforming. By the standard `setjmp` cannot appear in assignment expressions and `longjmp` may not refer to a `jmp_buf` initialize in a function scope that is now dead. Also you should at least ensure that `_` is `_Thread_local` and `volatile`. – Jens Gustedt Aug 22 '16 at 20:21
  • Good point. In any case, there are other ways to implement closures in C. I won't say they're pretty, but the concept is simple enough. Just allocate the state for the closure on the heap. Actually, I used this same trick a long time ago to implicitly pass a 'this' parameter to functions to fake classes in C. Didn't think about it back then, but it's technically closures. – DeftlyHacked Aug 22 '16 at 20:39
  • Your approach doesn't make a function (pointer), it makes an object that needs to be handled differently from an ordinary function (pointer). If that can be admitted as a solution, why not just use a struct containing a function pointer and some state and call that as `someStruct->funPtr(someStruct)` in order to implement closures? I don't understand why you need these complicated things. – fuz Aug 23 '16 at 08:55
  • Since "you've been writing PSP hacks" and "it boils down to lack of experience", I hope you'll accept some feedback from one of the main HBL devs (back in the MoHH/Patapon exploits days). There is *no portable way* to do it in C. Other commenters have already highlighted the flaws in your approach. The only ways are 1) using a global var to keep the allocated state (portable, but bye bye multithreading) or 2) dynamically generating an assembly trampoline (arch and OS specific, since you need *executable* memory). Of course you'd wrap everything up in #defines to keep sanity. – Andrea Biondo Aug 24 '16 at 07:59
  • By the way, this works only if your function is very simple (no stack state, everything's in registers) or if the stack isn't touched between `myfunc()` and `longjmp(...)`, so that the saved SP still points to valid local state. In your example, it depends on how much stack `longjmp` trashes. (This is because you're jumping to a dead scope) – Andrea Biondo Aug 24 '16 at 08:03
  • @AndreaBiondo "There's no portable way to do it in C"...This post was actually meant to be an alternative to my previous post which was downvoted because it implemented a stack smash via setjmp that relocated the current stack frame to the heap; and that's apparently scary to some people. Note that the technique does both of the things you mentioned; and entirely in C using only standard functions. Also note that I declared the fake 'stack' as `static` in the above answer so that it wasn't included in the stack frame itself. – DeftlyHacked Aug 24 '16 at 20:21
  • @DeftlyHacked I appreciate cool hacks (and yours are), but what you propose in the other post is *not* a good idea. You're assuming the stack layout, and you *don't* know that. What if I use a different compiler/arch/ABI/layout? About `static`, I didn't notice it at first, but it blows reentrancy out of the window, just like global vars. The point I'm making is that the `myfunc` scope which `setjmp` stores is dead. The fact that `_` is not on the stack doesn't change that. – Andrea Biondo Aug 24 '16 at 20:53
  • @DeftlyHacked Also (after fixing syntax errors) I compiled this answer with GCC 6.1.1, on a x86_64 Fedora 24 box. I got a segfault. I go check it out, and I find GCC is loading a value from stack when getting back control (after `setjmp`), then it dereferences that value and crashes because it's crap. That is because the stack got corrupted. Even if `_` is not on the stack, GCC is still using (in my case) 16 bytes of stack. – Andrea Biondo Aug 24 '16 at 20:56
  • _ isn't on the stack. it's a static object. not sure why you got a segfault, but this was merely a proof-of-concept anyway. I didn't actually test it. – DeftlyHacked Aug 24 '16 at 20:58
  • @DeftlyHacked I didn't say it was (it isn't). It segfaults because of what I said earlier: this works if `myfunc()` doesn't use the stack or if it isn't touched between `myfunc()` and `longjmp()`. None of which is true 99% of the time. Making locals `static` often won't keep the compiler from using a minimal amount of stack. Sorry if it sounds like a rant, didn't mean it to be one :) – Andrea Biondo Aug 24 '16 at 21:06
  • Well, there is one way to portably solve this problem in C that I can think of off the top of my head. If you create a dummy-func that just calls setjmp and returns; and then call it from 2 different scopes; you can do a memory comparison of the 2 stack frames and the only thing that's different should be the return address. Any time you want to call a closure, call the dummy first, and copy the return address of the dummy over the return address in the stack frame of your closure. – DeftlyHacked Aug 24 '16 at 21:13
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/121785/discussion-between-andrea-biondo-and-deftlyhacked). – Andrea Biondo Aug 24 '16 at 21:17
-1

I'm gonna get really hacky here, so hold on to your breeches.

The standard C api comes with a 2 functions called setjmp and longjmp. Poor naming aside, what they essentially do is store a copy of the current state (including the stack position and register values) into a jmp_buf (or, the technical name, a continuation).

Now, lets say you create a function:

jmp_buf jb;

void sfunc(void) {
    void *sp_minus1 = 0xBEEFBABE;
    setjmp(jb);
}

When you call sfunc, a stack frame will be created. Because there are no arguments to this function, the first entry in the stack will be the return address and immediately after it will be the sp_minus1 object.

Why is this relevant? Well, the address of sp_minus1 is relative to the start of the stack frame. If you can find the address of the stack frame in jb, you can change it...say, to a location in the heap?

What we've got at this point is a way to create stack frames for longjmp function calls on the heap that can contain additional state about the context in which they were called; or in other words, closures.

I don't think I've ever seen anyone use longjmp/setjmp this way, but if you're looking for a way to dynamically generate and return functions in C, I think this would be your best route.

EDIT:

Here's an example implementation of the hack I'm describing:

#include <inttypes.h>  // intptr_t
#include <setjmp.h>    // longjmp, setjmp
#include <stdio.h>     // printf
#include <stdlib.h>    // malloc, free
#include <string.h>    // memcpy


typedef struct {
    jmp_buf jb;
    int fixupc;
    int fixupv[10];
    size_t stack_size;  // this is only an approximation
    void *stack_ptr;
} CLOSURE;


int getclosure(CLOSURE *closure) {
    unsigned int i, size;
    void *i_ptr = &i, *sp;
    unsigned char *data = (unsigned char *)(void *)closure->jb;
    memset(closure, 0, sizeof(CLOSURE));
    if (!setjmp(closure->jb)) {
        printf("looking for 0x%08X...\n\n", (unsigned int)(intptr_t)i_ptr);
        for (i = 0; i < sizeof(closure->jb); i++) {
            memcpy(&sp, &data[i], sizeof(void *));
            size = (unsigned int)(intptr_t)(sp - i_ptr);
            if (size < 0x300) {
                closure->fixupv[closure->fixupc++] = i;
                printf("  fixup @ 0x%08X\n", (unsigned int)(intptr_t)sp);
                if (sp > closure->stack_ptr) {
                    closure->stack_size = size;
                    closure->stack_ptr = sp;
                }
            }
        }
        if (!closure->stack_ptr)
            return 0;
        printf("\nsp @ 0x%08X\n", (unsigned int)(intptr_t)closure->stack_ptr);
        printf("# of fixups = %i\n", closure->fixupc);
        /*
         * once we allocate the new stack on the heap, we'll need to fixup
         * any additional stack references and memcpy the current stack.
         *
         * for the sake of this example, I'm only fixing up the pointer
         * to the stack itself.
         *
         * after that, we would have successfully created a closure...
         */
         closure->stack_size = 1024;
         sp = malloc(closure->stack_size);
         memcpy(sp, closure->stack_ptr, closure->stack_size);
         memcpy(&data[closure->fixupv[0]], &sp, sizeof(void *));
         closure->stack_ptr = sp;
         return 1;
    } else {
        /*
         * to this bit of code right here
         */
        printf("holy shit!\n");
        return 0;
    };
}

void newfunc(CLOSURE *closure) {
    longjmp(closure->jb, 1);
}

void superfunc(CLOSURE *closure) {
    newfunc(closure);
}

int main(int argc, char *argv[]) {
    CLOSURE c;
    if (getclosure(&c)) {
        printf("\nsuccess!\n");
        superfunc(&c);
        free(c.stack_ptr);
        return 0;
    }
    return 0;
}

This is technically a form of stack smashing, so by default, GCC will generate stack canaries that cause the program to abort. If you compile with '-fno-stack-protection', it'll work.

DeftlyHacked
  • 405
  • 2
  • 9
  • I don't want to think what kind of can of worms this opens. But then again, maybe I fear it because I don't know it. – bolov Aug 19 '16 at 08:14
  • @DeftlyHacked Interesting! I'll have to play around with this. btw, I though you downvoted the post you commented on. – dbush Aug 19 '16 at 14:52
  • Well, I meant to, but at the time, I didn't actually have the privilege. If you find this interesting, you may also find it cool that you can use this same technique to create exploits. Setjmp/Longjmp pretty much indirectly gives you control of the stack pointer, and once you have that, arbitrary code execution is possible. I believe libpng was once used to exploit a gaming console like this. – DeftlyHacked Aug 19 '16 at 17:01
  • This is an implementation specific trick. As you are saying, some valid compilers or options (`-fstack-protection`) disallow such a trick. – Basile Starynkevitch Aug 22 '16 at 11:27
  • @BasileStarynkevitch, if you bothered to read the last line of the post, I specifically stated, "This is technically a form of stack smashing, so by default, GCC will generate stack canaries that cause the program to abort. If you compile with '-fno-stack-protection', it'll work.". The OP merely asked how to return a pointer to a new function; he didn't say that it couldn't involve disabling safety precautions and hacking the stack pointer. Pretty much all C threading libraries do this same trick (eg. libmill); they just do it in assembly instead of C. – DeftlyHacked Aug 22 '16 at 17:29
  • @DeftlyHacked It's not just stack smashing. You'd be scribbling all over the heap since your new stack pointer is incorrectly set up on all architectures I know of except HPPA. This is assuming you managed to overwrite the stack pointer at all, which I'm not so sure about. I'm pretty sure you're just overwriting the saved register that happened to contain `&i` considering that many operating systems (including Linux) use xor cookies on the sp and ip in the `jmp_buf` to prevent exploits from doing what you just tried to do. – Art Aug 23 '16 at 14:04
  • Yup. Just checked. On my flavor of Linux you're thinking that the stack pointer is where a normal register is saved, which happens to contain some garbage value (garbage since it's not used in this function at all) that happens to be close enough to the value you're looking for. – Art Aug 23 '16 at 14:23
  • @Art, if you read the code, you can see that's how it's intended to work. It initializes a jmp_buf with setjmp. Then, it searches for any values within it that are within 0x300 bytes of the address of a local variable. It's reasonable to assume that anything that close is also on the stack; so it adds those matches to a list of fixups. After all of the fixups are found, it's assumed that because stack grows downward that the fixup with the highest address is the address of the stack frame. We allocate more memory than we need and just memcopy. Hence the comment, "this is only an approximation" – DeftlyHacked Aug 24 '16 at 20:34
  • @Art, please note that this function's purpose isn't to alter the return address of the stack frame, it's to preserve the stack frame by relocating it to the heap before the stack is unwound; that way the original context (the state of all local variables) when setjmp was called is preserved; just like a closure. – DeftlyHacked Aug 24 '16 at 20:41