2

consider the following:

int * i = malloc(sizeof(int));
free(i);

I am now in a scenario where i points to deallocated memory, but it is also non-zero; this is a common error in C programming, is there a way to tell that i is still a valid pointer before I go and do something like:

*i++; //probable EXC_BAD_ACCESS crash

I know that it is completely impossible for there to be a 100% reliable (no false positives) method, unless you never reused memory; but something that worked most of the time would be great for debugging.

edit

I am not arguing that you shouldn't set your pointers to NULL, I am just wondering if there is a portable (POSIXish) way to poke an address without catastrophic repercussions, I just have an interest in debugging complicated multithreaded problems that arise from time to time.

Grady Player
  • 14,399
  • 2
  • 48
  • 76
  • 9
    Always set `i` to `NULL` after a `free` and test if it is `NULL` before dereferencing. – Anthales Apr 18 '12 at 22:11
  • 6
    Simple Answer: Nope. Complex answer: Nope. – Richard J. Ross III Apr 18 '12 at 22:11
  • 1
    @Anthales that works as long as you only have one reference to the pointer, I note that this is specifically a programming error. – Grady Player Apr 18 '12 at 22:13
  • 1
    That may be true, but if you have multiple pointers to the same object, you need to think about all of the pointers anyways. So in this case Richards comment applies. – Anthales Apr 18 '12 at 22:17
  • possible duplicate of [Testing pointers for validity (C/C++)](http://stackoverflow.com/questions/551069/testing-pointers-for-validity-c-c) – HostileFork says dont trust SE Apr 18 '12 at 22:20
  • That argument is kind of like saying "even if I put oil in the car, I still need to worry about running out of gas. Ergo, I won't ever bother adding oil." No! Religiously set your pointers to NULL. You'll feel good about yourself, and you'll live a Happy and Prosperous life. Guaranteed ;) – paulsm4 Apr 18 '12 at 22:28
  • 1
    FWIW, I disagree with this "always set things to null" nonsense. Free pointers when the pointer goes out of scope, or when the structure that it's part of is being freed. Then it doesn't matter whether you set it to null or not, because you've designed your code so that you will not use it again anyway. Much safer than slinging around pointers that may or may not be null, that their users have to check all the time. The exception is when doing something like clearing a cache without destroying it -- then you want to free it, and set to null to indicate there's nothing there any more. – Steve Jessop Apr 19 '12 at 01:00
  • And for debugging purposes it's better to set to some eye-catcher value (perhaps platform-specific to avoid using the same eye-catcher as some other part of the system does), than null. There are all sorts of places zero bytes could come from when you see them in the debugger, but a value like `0xFEFEABAB` used only for pointers-whose-old-value-has-been-freed gives you a much better idea what the problem is. – Steve Jessop Apr 19 '12 at 01:04

5 Answers5

2

To get something that works for debugging you want to use valgrind's memcheck tool. You'll see an invalid read or an invalid write error when the access happens.

@Anthales is right, you need to set the pointer to NULL as soon as you free. If you have multiple references to the pointer, this gets more complicated. Without knowing the specifics of your situation, I can't say exactly how to do this, but a possible solution can be giving the different structs something that allows them to request the reference to that memory instead of a specific pointer.

dbeer
  • 6,963
  • 3
  • 31
  • 47
  • Setting the pointer to NULL is an excellent practice. On a number of different levels, for a number of different reasons. – paulsm4 Apr 18 '12 at 22:25
2

No.

Static analysis and live tools (e.g. valgrind and guard malloc) can help you with this problem. Altering the way you approach writing programs also helps understand ownership and lifetimes more easily.

If you really wanted this functionality in more detail, you could use a custom allocator -- but there are tools in existence which help greatly.

justin
  • 104,054
  • 14
  • 179
  • 226
1

There's no (portable) way to know if a non-NULL pointer value is valid from the pointer value itself. Similarly, there's no (portable) way to know if the pointer points to an object with auto, static, or dynamic extent. If you're intimately familiar with your platform's memory model you could probably make some educated guesses (i.e., 0x00000001 is probably not a valid memory location), but that's about it.

You'll have to track all that information separately from the pointer itself, or enforce some discipline in how you use pointers.

John Bode
  • 119,563
  • 19
  • 122
  • 198
0

All you can really do in C is pass around enough information to know whether i still points to something.

Philosophically, if you don't know at the point of *i++; whether i still points to something that can be safely incremented, how do you know its correct to increment it even if it does?

It's a similar situation to array usage in C: you get into the habit of passing around both a pointer to the data, and an accompanying size indicator. Or you wrap both of them into a structure.

Perhaps if you can give a larger example of how i is used, people can recommend an idiomatic way of adding the additional information you need at the deference point.

Edmund
  • 10,533
  • 3
  • 39
  • 57
0

Some people like to set the freed pointer to NULL right after free:

#define paranoid_free(ptr)    (free(ptr), (ptr) = NULL)

This has the advantage to avoid double-free issue as free(NULL) is defined in C (as a no-operation). But it will still not prevent you to dereference the pointer and invoke undefined behavior elsewhere in your program.

ouah
  • 142,963
  • 15
  • 272
  • 331
  • 1
    In the C89 reference I have (I don't recall where I got it from), the description of `free()` says: "If ptr is a null pointer, no action occurs." – pmg Apr 18 '12 at 22:40
  • @pmg Thanks to correct me, off the top of my head I thought this was the case. Apparently I should have double-checked because the behavior is indeed the same in C89. – ouah Apr 18 '12 at 22:44