-
Type:
Improvement
-
Resolution: Unresolved
-
Priority:
Major - P3
-
None
-
Affects Version/s: None
-
Component/s: Developer Productivity
-
None
-
Storage Engines - Foundations
-
129.627
-
None
-
None
Something that has gnawed on me for years is code like this:
WT_ERR(__wt_scr_alloc(session, n, &tmp)); /* more resource allocations */ err: __wt_scr_free(session, &tmp); /* more frees */
It can be scr alloc, or malloc, or lock acquisition. Sometimes we have early exits from functions - sometimes the early exits go to the err label, sometimes they unwind the few allocated resources so far and simply return. But it's hard to detect/verify all these early exits are complete. Yeah, ASAN, etc. but can we figure it out statically. And better, can we make it automatic. This is the biggest thing (in my mind) that C++ would give us.
But... there's a couple of ideas that could clean this up. gcc and maybe clang have this thing called _attribute_((cleanup (fcn))) that can be called within a function to force fcn to be called when the "caller" goes out of scope. And if that's not available, we could consider something like this: https://stackoverflow.com/questions/368385/implementing-raii-in-pure-c/368731#368731
That presumably creates a little stack of cleanup functions to call. We'd make modifications for our situation, of course, fixed size stack, check at API exit to make sure all the cleanups got called, hide it in macros. But I think it could look quite clean, maybe:
WT_ALLOC_BEGIN(); /* creates hidden __wt_alloc variable, our "stack" */ ... WT_RET(WT_SCR_ALLOC(session, n, &tmpa)); /* pushes onto __wt_alloc */ ... /* Maybe WT_RET is okay, as WT_SCR_ALLOC could do its own cleanup? */ WT_RET(WT_SCR_ALLOC(session, n, &tmpb)); ... if (bad) { WT_ALLOC_END(); /* explicitly call cleanup */ return; } WT_ERR(some_function()); err: WT_ALLOC_END();
That could all be done with a little stack (maybe WT_ALLOC_BEGIN takes a size for number of entries?). If the magic "cleanup" attribute is available, it could do (in diagnostic mode) a check to see if the WT_ALLOC_END got called.
And finally, it at least seems possible now to write a checker that a function that uses ALLOC_BEGIN could be checked for sane uses of ALLOC_END.
I guess the one serious downside to consider is that this probably implies function pointers. And if some of the deallocators are inline, perhaps we're slowing down the free. But: 1) what hot-paths are doing allocations 2) maybe the compiler can see that entry 0 is always a particular free function, and can inline it at usage.