Joomla TemplatesWeb HostingFree Joomla Templates
Home Blogs Implementing exceptions with setjmp/longjmp

Implementing exceptions with setjmp/longjmp

An article about setjmp/longjmp made me to realize that exceptions can be implemented with setjmp and longjmp functions. So I started writing a proof of concept and came up with the below implementation.

struct JumpBuffer
{
    jmp_buf *Jmpbuf;
    JumpBuffer *Next;
};

struct JumpBuffer *gTopMostJmpBuf = NULL;
int count = 0;

void PushJmpBuf(jmp_buf *jmpbuf)
{
    struct JumpBuffer *jumpBuffer;
    
    jumpBuffer = (JumpBuffer *)malloc(sizeof(struct JumpBuffer));
    jumpBuffer->Jmpbuf = jmpbuf;
    jumpBuffer->Next = gTopMostJmpBuf;
    gTopMostJmpBuf = jumpBuffer;
}

jmp_buf *PopJmpBuf()
{
    assert(gTopMostJmpBuf != NULL);
    struct JumpBuffer *jumpBuffer = gTopMostJmpBuf;
    gTopMostJmpBuf = jumpBuffer->Next;

    jmp_buf *jmpbuf = jumpBuffer->Jmpbuf;
    free(jumpBuffer);

    return jmpbuf;
}

jmp_buf *GetTopMostJmpBuf()
{
    assert(gTopMostJmpBuf != NULL);
    return gTopMostJmpBuf->Jmpbuf;
}

enum
{
    kExceptionAll = 0,
    kExceptionDivisionByZero,
    kExceptionInvalidParam,
    kExceptionIndexOutOfBound,
};

#define MyTry \
jmp_buf *jmpbuf = (jmp_buf *)malloc(sizeof (jmp_buf)); \
PushJmpBuf(jmpbuf); \
int setjmpret = setjmp(*jmpbuf); \
if (setjmpret == 0)

#define MyCatchIf(exception) \
else if (setjmpret == exception || exception == kExceptionAll)

#define MyEndTry \
else \
{ \
    free(PopJmpBuf()); \
    longjmp(*GetTopMostJmpBuf(), setjmpret); \
} \
free(PopJmpBuf());

#define MyThrow(exception) \
longjmp(*GetTopMostJmpBuf(), exception)

void func2()
{
    printf("func2\n");
    MyThrow(kExceptionInvalidParam);
//    MyThrow(kExceptionIndexOutOfBound);
}

int func1()
{
    char buf[1024] = { 0 };
    printf("func1\n");
    MyTry
    {
        func2();
    }
    MyCatchIf(kExceptionIndexOutOfBound)
    {
        printf("Index out of bound\n");
    }
    MyEndTry

    return 2;
}

int main(int argc, char **argv)
{
    int a[10];
    int ret = 1;
    MyTry
    {
        printf("Hello World %p %p\n", a, a + 1);
        ret = func1();
    }
    MyCatchIf(kExceptionDivisionByZero)
    {
        printf("Division By Zero\n");
    }
    MyCatchIf(kExceptionInvalidParam)
    {
        printf("Invalid Parameter\n");
    }
    MyEndTry
    printf("ret = %d\n", ret);

    return 0;
}

As you can see from the code we use stack of jmpbuf. Whenever a try block starts, we allocate new jmpbuf, initialize it and push it into stack. When an exception is throwed we pop the top jmpbuf from the stack and jump into that location. Each catch block checks the return value of setjmp and if it matches with exception to be catched then that block will be execute. If an exception is not catched in the current try block then we pop the next jmpbuf from the stack and jump into that location. This continues until the exception is catched or jmpbuf stack become empty.

This proof-of-concept implemetation really helps me to understand how exceptions are implemented in languages like C++, Java, C# and etc.

Comments

Name *
Email (For verification & Replies)
URL
Code   
ChronoComments by Joomla Professional Solutions
Submit Comment

Last Updated (Saturday, 04 July 2009 15:03)