Traceability of Dynamic Memory Allocation Faults
-
My problem is that as I write larger and more complicated (C) programs, errors in manual memory management become much harder to find and more catastrophic, particularly if caused by memory corruption. I'd like to detect any DMA related errors as quickly as possible perhaps only when a debug flag is #defined. I pass a pointer to a pointer to the create and destroy object functions. Create will fail if a pointer to non NULL memory is passed which prevents doubly allocating. I am thinking of storing pointers to all allocated objects in a balanced BST, which would enable me to tell if a pointer is valid before free()in it. After Free() I can write NULL to prevent it's use and to prepare it for allocation again. Any function that wants to check if an object pointer is valid can then call a check of the BST inventory. Further I was thinking of tagging each entry with a scope of some sort so that I can check for missed Free() as soon as the object is no longer used: StartScope(foobar) CreateObj(data) Do work;;; FreeObj(data) EndScope(foobar) That way I can check at EndScope that all foobar scoped objects were freed. This would enable me to make objects that were dynamically allocated have a stack based/automatic scope for example, if they are not going to be used after the function exits. If using scopes for 'automatic' object allocation and nesting them in a stack, an error can be detected if a higher level scope is ended before a lower one. These mechanisms are all intended to trigger errors as quickly as a problem can be detected and before it worsens. And furthermore to do so with the most minimal burden on the user. I couldn't find a standard practice because garbage collection does not seem to be the same concept as detecting errors in memory management. Is this good? Is there a better way of doing it / standard practice?
-
My problem is that as I write larger and more complicated (C) programs, errors in manual memory management become much harder to find and more catastrophic, particularly if caused by memory corruption. I'd like to detect any DMA related errors as quickly as possible perhaps only when a debug flag is #defined. I pass a pointer to a pointer to the create and destroy object functions. Create will fail if a pointer to non NULL memory is passed which prevents doubly allocating. I am thinking of storing pointers to all allocated objects in a balanced BST, which would enable me to tell if a pointer is valid before free()in it. After Free() I can write NULL to prevent it's use and to prepare it for allocation again. Any function that wants to check if an object pointer is valid can then call a check of the BST inventory. Further I was thinking of tagging each entry with a scope of some sort so that I can check for missed Free() as soon as the object is no longer used: StartScope(foobar) CreateObj(data) Do work;;; FreeObj(data) EndScope(foobar) That way I can check at EndScope that all foobar scoped objects were freed. This would enable me to make objects that were dynamically allocated have a stack based/automatic scope for example, if they are not going to be used after the function exits. If using scopes for 'automatic' object allocation and nesting them in a stack, an error can be detected if a higher level scope is ended before a lower one. These mechanisms are all intended to trigger errors as quickly as a problem can be detected and before it worsens. And furthermore to do so with the most minimal burden on the user. I couldn't find a standard practice because garbage collection does not seem to be the same concept as detecting errors in memory management. Is this good? Is there a better way of doing it / standard practice?
When you code reaches a certain complexity you have to stop and implement test benches on each unit file .. I take it you are not doing so. At the moment you are treating the symptoms not the cause. Put simply your
CreateObj(data)
Do work;;;
FreeObj(data)Should be known to work bug free because it passes your benchtest unit with clear use guideline API One of the things writing the bench test unit does is makes you stop and think about possible errors because you try to bench test the errors. Your bench test code should obviously include malloc failing and all memory writes should be checked for size in the benchtest. So put bluntly your code is failing because you are failing to test properly. For even larger projects especially if threaded it often becomes necessary to use a MOCK framework to actually cross test the units together. Typical test frameworks are listed in the C section of List of unit testing frameworks - Wikipedia[^] The more common ones are CMock, Ceedling and Unity. If you have never run across this before it is worth a look at a good tutorial like Unit-testing (embedded) C applications with Ceedling [Dmitry Frank][^]
In vino veritas
-
My problem is that as I write larger and more complicated (C) programs, errors in manual memory management become much harder to find and more catastrophic, particularly if caused by memory corruption. I'd like to detect any DMA related errors as quickly as possible perhaps only when a debug flag is #defined. I pass a pointer to a pointer to the create and destroy object functions. Create will fail if a pointer to non NULL memory is passed which prevents doubly allocating. I am thinking of storing pointers to all allocated objects in a balanced BST, which would enable me to tell if a pointer is valid before free()in it. After Free() I can write NULL to prevent it's use and to prepare it for allocation again. Any function that wants to check if an object pointer is valid can then call a check of the BST inventory. Further I was thinking of tagging each entry with a scope of some sort so that I can check for missed Free() as soon as the object is no longer used: StartScope(foobar) CreateObj(data) Do work;;; FreeObj(data) EndScope(foobar) That way I can check at EndScope that all foobar scoped objects were freed. This would enable me to make objects that were dynamically allocated have a stack based/automatic scope for example, if they are not going to be used after the function exits. If using scopes for 'automatic' object allocation and nesting them in a stack, an error can be detected if a higher level scope is ended before a lower one. These mechanisms are all intended to trigger errors as quickly as a problem can be detected and before it worsens. And furthermore to do so with the most minimal burden on the user. I couldn't find a standard practice because garbage collection does not seem to be the same concept as detecting errors in memory management. Is this good? Is there a better way of doing it / standard practice?
Many memory problems come from inherent issue with pointers that lets you copy the reference to an allocated object without restriction, but then doesn't let these references track when someone deletes it. Neither indirection nor garbage collection can solve that. Instead, use smart pointers! Smart pointers behave for the most part like normal pointers, but they also make sure that the allocated objects get released when they are no longer referenced. And not earlier! You can check your preferred search engine on this topic or just take the first hit: c++ - What is a smart pointer and when should I use one? - Stack Overflow[^]
GOTOs are a bit like wire coat hangers: they tend to breed in the darkness, such that where there once were few, eventually there are many, and the program's architecture collapses beneath them. (Fran Poretto)
-
My problem is that as I write larger and more complicated (C) programs, errors in manual memory management become much harder to find and more catastrophic, particularly if caused by memory corruption. I'd like to detect any DMA related errors as quickly as possible perhaps only when a debug flag is #defined. I pass a pointer to a pointer to the create and destroy object functions. Create will fail if a pointer to non NULL memory is passed which prevents doubly allocating. I am thinking of storing pointers to all allocated objects in a balanced BST, which would enable me to tell if a pointer is valid before free()in it. After Free() I can write NULL to prevent it's use and to prepare it for allocation again. Any function that wants to check if an object pointer is valid can then call a check of the BST inventory. Further I was thinking of tagging each entry with a scope of some sort so that I can check for missed Free() as soon as the object is no longer used: StartScope(foobar) CreateObj(data) Do work;;; FreeObj(data) EndScope(foobar) That way I can check at EndScope that all foobar scoped objects were freed. This would enable me to make objects that were dynamically allocated have a stack based/automatic scope for example, if they are not going to be used after the function exits. If using scopes for 'automatic' object allocation and nesting them in a stack, an error can be detected if a higher level scope is ended before a lower one. These mechanisms are all intended to trigger errors as quickly as a problem can be detected and before it worsens. And furthermore to do so with the most minimal burden on the user. I couldn't find a standard practice because garbage collection does not seem to be the same concept as detecting errors in memory management. Is this good? Is there a better way of doing it / standard practice?
HS_C_Student wrote:
My problem is that as I write larger and more complicated (C) programs, errors in manual memory management become much harder to find and more catastrophic, particularly if caused by memory corruption....I couldn't find a standard practice
Err...because you are going at it from the wrong end. You are trying to fix it after it happens rather than stopping it before it occurs. You do the latter by strict care in your design and implementation. Create design that strictly specify where allocations occur and where they are cleaned up. Implement code that follows that and if you allocate something then BEFORE you do anything else implement, strictly, how it is cleaned up. That also applies to how you use each pointer also. If you are code a piece of code and your are not sure how to use it, whether it is defined or what you can put in it, then you have already done something wrong.