1

My program uses an environment variable DBG_MSG value to determine the level of debug messages. DBG_MSG=3 prints the maximum debug information.

However whenever the program is behaving in a strange unexpected way the environment variable is not set to print the full debug information. And when program is rerun with environment set it won't show the same error.

I am thinking of implementing a signal handler for SIGUSR1 to set this environment variable at runtime, using putenv(3). This way I can send the signal to a hung job to make it print more debug info.

What are some safety measures to take when doing this ?

Are there any other ways to change environment of a running program from outside ?

punekr12
  • 653
  • 2
  • 7
  • 14
  • 1
    I'm confused. Probably others will be as well. – user3344003 Jun 23 '15 at 19:01
  • 2
    The problem is that the bug disappears when you print debug messages, which means your program invokes undefined behavior, so a debugger will help a lot, a memory debugger like [valgrind](http://www.valgrind.org) will even help more, and posting the problematic code will be of help to the person who might help you. – Iharob Al Asimi Jun 23 '15 at 19:03
  • 1
    @iharob What you say is true except that this is much more likely to be a race condition leading to deadlock than a memory corruption problem (so, `helgrind` instead of `valgrind` maybe) and the description makes me think we're talking about a very large, complicated network daemon that would not be practical to post even a cut-down version of. – zwol Jun 23 '15 at 19:09

4 Answers4

3

putenv is not async-signal-safe, and therefore should never be called from a SIGUSR1 handler. Also, changes made by putenv are not necessarily noticed by getenv calls in another thread.

What you should do instead is read your DBG_MSG environment variable only once, on startup, and store the value in a global variable with type volatile sig_atomic_t. Your debug-logging routines should look at this variable to decide how much information to print. Then you have your signal handler adjust the value of the variable.

I would suggest, also, that SIGUSR1 should increment the variable, and SIGUSR2 should decrement it. That way you can both raise and lower the log level, as necessary.

sig_atomic_t may be very small, and is not guaranteed to be either signed or unsigned: a portable program can only use it to store values in the range 0 through 127 inclusive. Therefore, make sure that your signal handlers clamp the value to the range that is meaningful for your program (that is, don't increment the log level past the maximum or reduce it past the minimum).

zwol
  • 135,547
  • 38
  • 252
  • 361
1

The safety measures are: don't do it.

putenv(3) is not async-signal safe (mostly because it can call malloc(3)), and so you shouldn't really call it from a signal handler.

Filipe Gonçalves
  • 20,783
  • 6
  • 53
  • 70
  • It's not safe to call arbitrary functions from `gdb` either; in fact, depending on where you broke into the program it could be *exactly* as risky as calling them from an async signal handler. – zwol Jun 23 '15 at 19:07
  • @zwol Oh, I had no idea. That's interesting. Thanks for letting me know! I'm going to update my answer. – Filipe Gonçalves Jun 23 '15 at 19:09
  • I am aware of this hack and have used it in development. But I am looking for a more user friendly way to do this. Something that a user can activate if needed. – punekr12 Jun 23 '15 at 19:12
  • 1
    Think about it this way: Async signal handlers have to be very careful what they do because they could have interrupted execution of any part of the program (unless signals are blocked), including the guts of a library function. Well, a debugger break-in is *even more* invasive than that: it can even interrupt a program that has all blockable signals blocked. So it is necessary to be even more cautious when calling back into the program. (The human driving the debugger can inspect the call stack and decide what's safe to do, of course.) – zwol Jun 23 '15 at 19:17
0

You need to ensure you are not mettling with env variable from within your program. Env variables should be set once from your shell and leave alone. .. after all , they are environment variables . They just setup or define an environment for your program.

Scalable
  • 1,550
  • 4
  • 16
  • 29
0

There is one more way .... you can implement ioctl calls also ..

even many drivers are doing same thing ..

SHASHI BHUSAN
  • 612
  • 6
  • 12