2

I have a pretty unique case where I am calling a 3rd party library (which I cannot modify) from a higher-level C program.

This code has a clean-up routine that calls exit() - which terminates the whole application.

However, I do not want to terminate the whole application at this time, as there is still some work that must be done by the main application.

So to solve this, I tried to 'trick' this 3rd party library by temporarily 'aliasing' the exit() function call to a dummy function using dlsym - and then later restoring exit() to its normal state. This solution almost works - using LD_PRELOAD to point to the dummy exit wrapper I can see this dummy exit function being called - however, imminently after this I get a segmentation fault when this function goes out of scope.

I suspect this has to do with the fact that gcc by default puts an attribute called noreturn on this function.

Is there a way to remove this noreturn attribite, or better still another way of preventing this 3rd party library from calling exit()?

Any and all suggestions would be most appreciated.

John McGrath
  • 151
  • 1
  • 11
  • If this is threaded: Let the `exit()` replacement call `pause()` and when done send it a signal to have `pause()` return and call the real `exit()`? – alk Oct 05 '15 at 15:42
  • Given you don't know what the 3rd party library does to its data before calling `exit()`, your intperposing `exit()` call can *never* return, which is what I assume you mean when you say your `exit()` "function goes out of scope". – Andrew Henle Oct 05 '15 at 16:08
  • 4
    "*as there is still some work that must be done by the main application.*" would perhaps `atexit()` help you? – alk Oct 05 '15 at 16:16
  • 4
    Even if you could, it's a phenomenally bad idea to try to trick code that thinks it's calling `exit()` into calling something else instead. If you need to perform your own cleanup, then either do it *before* calling the library routine, or register an exit handler as @alk suggested. If you don't want to exit at all, then don't call that library function at that time. – John Bollinger Oct 05 '15 at 16:46
  • 1
    Also, it is ... *rude* ... for a library function to call `exit()` in the first place, at least if there is no alternative that avoids exiting. Especially so if the library insists that programs that use it exit that way -- consider that no one program can use two such libraries. If it were me, I'd be looking into dumping the library altogether. – John Bollinger Oct 05 '15 at 16:53
  • Do a [`setjmp`](http://linux.die.net/man/3/setjmp) before calling the library and in your dummy `exit` do a [`longjmp`](http://linux.die.net/man/3/longjmp) back to the `setjmp`. You cannot simply return from your dummy `exit` function as the library does not expect `exit` to return. – 4566976 Oct 05 '15 at 18:30
  • 1
    @alk thanks a lot - atexit seems to be doing the trick. I changed the previous routine calling the cleanup function to now use atexit to register the call to the cleanup function. So now only when the main application exits the pesky cleanup function is called then. – John McGrath Oct 05 '15 at 19:38
  • Thanks for all the suggestions. Some really interesting answers here. I had thought about putting the (rude!) library in its own thread but glad I didn't have to do that as I would have to then add all the ipc stuff. For noe atexit seems to be doing the trick. Thanks again – John McGrath Oct 05 '15 at 19:43

1 Answers1

1

Ignoring the fact that this may be a bad idea and that this is an old question and it seams to be answered in the comments. There is an alternative solution to this if using gcc on Linux (maybe other systems to, I wouldn't know).

/* compile with "gcc -Wl,-wrap,exit -o test wrap_exit.c" */
/* check exit status with "echo $?" */

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

void __real_exit(int status);

void __wrap_exit(int status)
{
  int stat = 2;
  printf("trying to exit with status %d\n", status);
  printf("now exiting for real with status %d\n", stat);
  __real_exit(stat);
}

int main(void)
{
  exit(1);

  return 0;
}
evading
  • 3,032
  • 6
  • 37
  • 57