Skip to content

Catching SPL exceptions potentially invokes undefined behavior #24

@cmlsharp

Description

@cmlsharp

Source

Stack unwinding is simulated in exception.{h,c} by utilizing the setjmp and longjmp functions from the C standard library. These functions dynamically create for non-local gotos, allowing control flow to be transferred from one function to an arbitrary location in another.

There functions, while useful, carry a subtle "gotcha". When control flow is transferred, whether or not registers are restored is unspecified (it is undefined in GCC, not sure about clang), meaning the values of non-volatile variables with automatic storage duration that have changed between the setjmp and longjmp calls are unspecified.

Example of the UB:

int foo(int);
void bar(int, int);

int main(void)
{
    int x = 10, y = 5;
   // Do stuff with x and y
    try { // setjmp is called in the expansion of `try`
        x = foo(y); // x is modified
        bar(x,y); // Throws an exception, which calls longjmp
    } catch (ANY) {
         // x might have been in a register but it's value has (maybe) been clobbered
         fprintf(stderr, "The value of x is %d", x); 
    }
}

Recommendation

I don't think that leaving potentially UB-causing constructs in a library designed for students. I would propose removing this feature and refactoring the library to function without it.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions