Thread: Implementing try/catch as Macros

  1. #1
    Registered User
    Join Date
    Jul 2008
    Posts
    29

    Implementing try/catch as Macros

    So this post has a couple of questions:

    1. What does the stack look like when a signal is caught (via registering your own function with signal()). The reason that I ask is because I did a little assembly hacking to get the ebp register value and thus manually look through the stack, since the ra value is right after the ebp value. This works when I try it normally, its just when I try calling it from within the signal handler that i get really weird values. I tried looking them up via the nm utility but the range on the function ptrs all started with 4 whereas the values I was getting started with a 6.

    2. So I was thinking that in macros in conjunction with signals would allow me to do the trick of a try catch type block. I could change catch to some random label and insert another random label after the catch. Then, i replace the try with a function call to set global variables with the location of the two previously mentioned labels and the current values of all the registers. Next, when the signal is caught, I replace all the values of the current registers with the saves versions and lastly goto the appropriate label (the catch block). Lastly, the macro would insert a goto finish label at the end of the try block so as to skip the catch block.

    As far as what I dont know how to do in all that is two things. First, I dont know how to get the preprocessor to insert unique labels in the correct spots. Anyone know how? And secondly, I dont think that the signal handler can simply change the registers and jump since theres some state somewhere else that I need to unravel, right?

    Any help with all of this is greatly appreciated,
    chacham15

  2. #2
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    Things like stacks and registers are highly implementation-dependent and thus such questions cannot really be answered in a general fashion.

    If you're looking to implement exceptions in C, setjmp() and longjmp() are the normal way:
    Code:
    #include <stdio.h>
    #include <setjmp.h>
    
    static jmp_buf exception_buf;
    #define TRY if(setjmp(exception_buf) == 0)
    #define CATCH else
    #define THROW() longjmp(exception_buf, 1)
    
    int main(void)
    {
      TRY
      {
        puts("I am in a try block.");
        THROW();
        puts("I will not be seen.");
      }
      CATCH
      {
        puts("Exception caught.");
      }
    
      return 0;
    }
    This is, of course, about as basic as exception handling gets. You can get more fancy by longjmping with various values to get different exception types, but implementing this with macros would be tricky. You'd have to use a switch statement (I can't think of any other portable way) and getting that properly wrapped with a macro could prove ugly. But it's probably doable.

  3. #3
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    Addendum: An obvious way of handling multiple exception types would be to set a global variable (or, perhaps, push something onto a stack) before the longjmp. So you can easily avoid the need for a switch.

    There. Let's see if this statement holds up.

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    The libpng library has a pretty nice try/catch macro set for use in C.

    Is this the only bit of C++ you're interested in, or will you be looking to add aspects of "classes" later on?
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    Jul 2008
    Posts
    29
    The thing is that if I wanted to use a library, I'd be writing in C++ which is more suited for doing this kind of thing. I want to write my own version of this (as I have for printing out stack traces and such).

    Now a few questions. I can kinda guess how the code you've added does the job but what happens if in the try block i do 1/0? Will that still work? If so, how does the code in the signal handler work? See, Im trying to implement my own versions of these things becuase I think that it gives me a greater understanding of whats actually going on (and its also fun!, but thats prob. just me). So if you could explain whats going on under the covers, so to speak, that would be helpful.

    Secondly, I may want to add classes in the future (but, again, I want to implement that myself)

    Thanks!
    chacham15

  6. #6
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    You should be able to do longjmp from the signal handler.

    Also consider that if you want to nest your TRY/CATCH blocks, then you need to track the current jump buffer, and restore to the previous one when leaving the current block - not sure how you go about doing that. Probably adding something in the CATCH macro to "restore to previous level".

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    So you want some kind of 'throw' from C code, which will become a C++ exception later on?
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #8
    Registered User
    Join Date
    Jul 2008
    Posts
    29
    >So you want some kind of 'throw' from C code, which will become a C++ exception later on?

    As a future goal, yes. But for now, i want it for some more mundane things:

    For example,

    Code:
    BOOL isValidPointer(void *ptr, int size){
           char *temp = ptr;
           size = size - 1;
           try {
                  while (size >= 0){
                          char c = *(temp+size);
                          size = size - 1;
                  }
           } catch (exception e) { //even } catch { is ok for now
                  return(FALSE);
           }
           return(TRUE);
    }
    but as far as trying to make the exception thrown compatible with anything else i dont care.

    Thanks,
    chacham15

  9. #9
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Why don't you just write your code in C++? If you want to, you can only use exceptions, without using other features of C++. But even that would make your life easier than bashing the stack with longjmp() . . . .

    But anyway. More about signals: http://www.cs.utah.edu/dept/old/texi...ibrary_21.html
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  10. #10
    Registered User
    Join Date
    Jul 2008
    Posts
    29
    I mostly do it for the experience. I feel that if you know how the tools you use work then you'll be able to use them better. Also, architecting complicated systems is fun.

  11. #11
    Registered User
    Join Date
    Jul 2008
    Posts
    29
    How would you implement getting a stack trace from inside the signal handler? I've tried getting the base pointer then adding sizeof(void*) to get the return address and repeating but all I get are invalid pointers. Any ideas?

  12. #12
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Are you accounting for local variables? If a function has local variables, those will go on the stack, too.

    There must be a way to do this reasonably easily, but I don't know of it.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  13. #13
    Registered User
    Join Date
    Jul 2008
    Posts
    29
    The stack is layed out in the following manner:

    Base Pointer
    Return Address
    Stack Variables

    So, yes. The interesting thing to note is that when I try to run the getStackTrace function from normal execution, it works perfectly. However, from a signal handeler, it doesnt. Why?

  14. #14
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    The only thing I can think of is this: a signal handler has to be called from somewhere. This code is probably low-level code in the kernel somewhere, and perhaps it doesn't follow the same stack layout that you expect from normal functions.

    It's pretty far-fetched -- especially since most of the Linux kernel is written in C and I'm sure Windows isn't too different -- and it means that you should at least be able to read the stack for the signal handler itself.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  15. #15
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by dwks View Post
    The only thing I can think of is this: a signal handler has to be called from somewhere. This code is probably low-level code in the kernel somewhere, and perhaps it doesn't follow the same stack layout that you expect from normal functions.

    It's pretty far-fetched -- especially since most of the Linux kernel is written in C and I'm sure Windows isn't too different -- and it means that you should at least be able to read the stack for the signal handler itself.
    Although in Linux at the very least, the "base-pointer" (that is, frame-pointer) is excplicitly optimized away with -fomit-frame-pointer when compiling the kernel - so if you expect the format of
    Code:
    Base Pointer
    Return Address
    Stack Variables
    then the first part will not (always - the compiler may still generate frame pointer code if it determines that frame-pointer makes better code [which is decided by heuristics - not a precise scientific decision]) be present.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Order of execution of preprocessor macros
    By DL1 in forum C Programming
    Replies: 2
    Last Post: 04-02-2009, 06:52 PM
  2. parameterized macros vs. functions
    By Tbrez in forum C Programming
    Replies: 3
    Last Post: 04-02-2009, 12:33 PM
  3. function definition with macros
    By toshog in forum C++ Programming
    Replies: 2
    Last Post: 03-08-2009, 09:22 PM
  4. Macros inside of macros
    By Chewie8 in forum C Programming
    Replies: 2
    Last Post: 02-24-2008, 03:51 AM
  5. Macros vs Inline Functions
    By vb.bajpai in forum C Programming
    Replies: 4
    Last Post: 08-02-2007, 11:51 AM

Tags for this Thread