4 ms·
I've always wondered why there isn't a `free_all()` function (that I'm aware of) for exactly ensuring that handles this. Or why you can't probe memory, with som
by bArray 4y ago
I've always wondered why there isn't a `free_all()` function (that I'm aware of) for exactly ensuring that handles this. Or why you can't probe memory, with something like `is_alloc()` (is allocated).
I usually define my own version of `free()` to check whether the pointer is NULL, free the memory if not, and then set the pointer to NULL. That way if your pointer isn't NULL, it should be pointing somewhere. I believe there are some caveats though, specifically around OOM allocations as memory isn't truly allocated until you go to access it.
C memory is generally quite cool to work with, but those tripping points really will trip you up. It's exceptionally easy to have stuff lingering around indefinitely, even worse when it happens in a loop.
- mike_hock 4y agololwat? How would you ever use that in a sane way? is_alloc: If you have to call is_alloc because you don't know and you get `true` back, you still don't know anything, it could be your memory is live or it could be something else was allocated over your stale pointer. free_all: This is just ridiculous. Now the heap is completely unusable because your memory could be freed from under you at any time by a concurrent free_all.
- naniwaduni 4y agoOn modern OSes, of course, there is a free_all: it's called _Exit, and sensibly prevents your program from doing any further work.
- bArray 4y ago> is_alloc: If you have to call is_alloc because you don't know and you get `true` back, you still don't know anything, it could be your memory is live or it could be something else was allocated over your stale pointer. The answer I want is a simple one - is _this_ pointer currently pointing to somewhere with allocated memory? The goal would be to avoid double free, or double allocating (and therefore memory leaks). > free_all: This is just ridiculous. Now the heap is completely unusable because your memory could be freed from under you at any time by a concurrent free_all. I think you misunderstand. You could have a (contrived) structure like: typedef struct{ char* a, char** b } s; You then have the following allocations (not tested): s* data = (s*)malloc(sizeof(s)); data->a = (char*)malloc(n * sizeof(char)); data->b = (char**)malloc(l * sizeof(char*)); for(int x = 0; x < l; x++) data->b[x] = (char*)malloc(n * sizeof(char)); Rather than free each of these allocations individually, you would instead have `free_all(data)` (might not be a great name). At compile time the compiler would look at the structure and expand out to be all the free operations as required. Of course you would need the `is_alloc` to test if somebody actually did allocate memory. I would then imagine a common pattern would be: s* data = NULL; // Indicate we point to nothing /* Allocate */ free_all(data); // Free associated memory data = NULL; // Indicate no memory allocated Of course one trap would be: s* data = (s*)malloc(sizeof(s)); data->a = y; data->b = z; free_all(data); Then one would have to consider whether y and z and free'd or not.
- mike_hock 4y ago> is _this_ pointer currently pointing to somewhere with allocated memory? The goal would be to avoid double free, or double allocating This doesn't work because you don't know who allocated that memory. Thread A: free(p) Thread B: malloc(...) -> p (happens to get the same address) Thread A: is_alloc(p) -> true Thread A: free(p) thinking it's not a double free because is_alloc returned true This scenario is possible because if it wasn't, you wouldn't need is_alloc in the first place. You only "need" it if you've lost track of your memory and have no clue what is allocated and what isn't and you're trying to solve the problem (the wrong way) with these runtime checks. > I think you misunderstand. You could have a (contrived) structure like: [...] > Rather than free each of these allocations individually, you would instead have `free_all(data)` (might not be a great name). At compile time the compiler would look at the structure and expand out to be all the free operations as required. Of course you would need the `is_alloc` to test if somebody actually did allocate memory. If you're going to change the language anyway (changing what the compiler does), just use C++ with unique_ptrs and they do precisely that without is_alloc. If pointer cycles are a concern (since we're only doing this to avoid proper pointer hygiene in the first place), you could allocate everything within `s` from a private arena and just free the arena.
- bArray 4y ago> This doesn't work because you don't know who allocated that memory. I obviously haven't fully fleshed it out (I'm not writing an RFC here), but address re-use would be a consideration as you mention. > You only "need" it if you've lost track of your memory and have no clue what is allocated and what isn't and you're trying to solve the problem (the wrong way) with these runtime checks. No, you can do: char* a = (char*)malloc(/**/); if(a == NULL) printf("error"); // Never runs /* Any other checks you want to perform */ /* Some processing later */ a[0] = 'a'; // Crash here In this case you have done nothing wrong. At the time of requesting memory there was enough space and the kernel said that you could have it. It's only when you come to actually access it did you find that it wasn't really allocated yet and there was no longer enough memory there for it. > If you're going to change the language anyway (changing what the compiler does), just use C++ with unique_ptrs and they do precisely that without is_alloc. You don't have to change the way in which the compiler works. You can likely do this with some macros. You would need some way to probe memory allocations though.