2

In some of our code; we are getting a segmentation fault and the gdb stacktrace shows the pointer is pointing to 0x1. We have 3 instances of these segmentation faults and in each one; the pointer ends up pointing to 0x1.

I would like to recover 'gracefully' from this error; instead of SEGFAULT. I can't check for NULL; since that would be 0. Do I explicitly check for address 0x1?

This is on Linux using GCC3.4.2 (SLES9 machine)

Kevin
  • 4,618
  • 3
  • 38
  • 61
shergill
  • 3,738
  • 10
  • 41
  • 50

3 Answers3

14

Yes, the reason you're getting a pointer pointing to 0x1 is most likely because you're dereferencing a structure which is pointing to null:

struct some_struct* ptr = NULL;
char blah = ptr->foo;

And it happens that foo is at offset 1 from the start of the structure. So the math ends up being *(0+1).

Ana Betts
  • 73,868
  • 16
  • 141
  • 209
11

I would like to recover 'gracefully' from this error instead of SEGFAULT. I can't check for NULL since that would be 0. Do I explicitly check for address 0x1?

Probably not the best idea.

The way to recover (technically, recovery is not plausible, you really need to prevent it instead) would be to assume that 0x1 is as bad as NULL and not try to use it in that case, something like:

if ((p == 0) || (p == 0x1))
    return;
// Otherwise use p.

However, I hesitate greatly in calling that graceful. The right thing to do is track down what's causing the pointer to be set to that invalid value and fix it. That's particularly apt since a piece of code dodgy enough to generate a pointer value of 1 would probably also be dodgy enough to generate 2, or any other non-valid pointer.

Checking against 1 is akin to stopping headaches with a painkiller when someone's continuously smacking you in the head. You could take that tablet to ease the headache but surely it would be better to fix the root cause of the problem (i.e., stop the person smacking you in the head).

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • I agree with fixing it before it comes to this. Just wanted to point out that (assuming a 4k page size) it might be better to check for `(ptr < (void*)0x1000)`. Or use the PAGESIZE `#define` if it exists. Because you can be pretty sure that the page at `0x0` won't be mapped. – mpontillo Mar 06 '12 at 03:32
  • All pointers on NT whose values are < 0x10000 are guaranteed invalid. On modern Linux this is guaranteed as well, but older versions of Linux this is *not* (you can mmap VA 0x0, leading to a ton of fun EoP exploits) – Ana Betts Mar 06 '12 at 03:38
  • 3
    Well, the edited question states Linux rather than NT, but it's irrelevant either way. You should still fix the root cause rather than try to recover from the effects. – paxdiablo Mar 06 '12 at 03:42
  • +1 to that, don't try to do anything clever with checking the actual value of the pointer other than a null check – Ana Betts Mar 06 '12 at 03:45
  • Agreed, but I can see a situation where you wouldn't have control over the initial pointer. (should be rare but.. could happen) – mpontillo Mar 06 '12 at 04:07
  • @Mike, in that case, the client of your code has broken their part of the contract. It should be fixed there rather than trying to catch everything in your code. I'm concerned where that would end, with checking pointer values, content of strings to ensure they're not too long (an arbitrary thing) and so forth. I'll all for robust code but, at some point, you've just got to tell the callers: don't give me carp :-) – paxdiablo Mar 06 '12 at 04:26
  • `p == 0x1` is not valid C. You cannot mix pointers and integers (except for the integer constant expression 0, which doubles as a null pointer constant expression) as operands of arithmetic and comparison operators. – R.. GitHub STOP HELPING ICE Mar 06 '12 at 13:31
  • @R.. It's a warning, but it's valid. – Ana Betts Mar 07 '12 at 00:00
  • Not valid. There is no implicit conversion between pointer and integer types in C. If your compiler accepts it, the compiler is wrong. – R.. GitHub STOP HELPING ICE Mar 07 '12 at 01:43
  • 1
    Actually, I wasn't going to comment but, since you hijacked my answer :-), C99 states in 6.3.2.3: "An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, blah blah blah". So it's not disallowed, just implementation-defined. – paxdiablo Mar 07 '12 at 07:31
3

When you have violated the contract of your interfaces by passing a null pointer to a piece of code that does not assign a particular meaning to a null argument, there is no such thing as "recovering 'gracefully'". There's no limit to the amount of program state that could be invalid, and it's likely that you've already invoked undefined behavior somewhere.

Since I've already written a plenty on this topic on SO in the past, I'll just leave you a link to my treatise:

In either C or C++, should I check pointer parameters against NULL/nullptr?

Community
  • 1
  • 1
R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711