C++: Support operator new and operator delete in models library#3173
Conversation
|
|
||
| override int getSizeArg() { result = 0 } | ||
|
|
||
| override predicate requiresDealloc() { not exists(getPlacementArgument()) } |
There was a problem hiding this comment.
For the overloads where this predicate holds (9 and 10 in https://en.cppreference.com/w/cpp/memory/new/operator_new), I don't think they should be AllocationFunctions. They are merely identity functions. The IR alias analysis assumes that an allocation function returns a fresh memory location that doesn't alias anything else reachable, and that's also my own understanding of what an allocation function is.
The requiresDealloc predicate is currently overridden by alloca, and that makes sense to me: it returns fresh memory but doesn't require deallocation. In the AllocationExpr hierarchy, requiresDealloc is overridden by NewAllocationExpr and NewArrayAllocationExpr, and I think the placement versions of those expressions should not be AllocationExprs for the same reasons. Unless the allocation classes are used in other queries where we do want to include the placement versions.
Functions that always return their parameter can instead be modelled as AliasFunction.
There may be some C++ standard rules about how it's forbidden to reference an old pointer value that's passed through placement new, which effectively means it behaves like it's allocating fresh memory, but I don't think programmers obey that rule. I also couldn't find the rule on https://en.cppreference.com/w/cpp/language/new, so I may be misremembering.
There was a problem hiding this comment.
The IR alias analysis assumes that an allocation function returns a fresh memory location that doesn't alias anything else reachable
That's a slightly dubious assumption when you're looking inside the implementation of an operator new, which presumably needs to keep hold of some data about the allocation for bookkeeping purposes (I'm not sure exactly how modern non-toy implementations do this). But that data should be well compartmentalized from user code, so I doubt this is something we need to model.
Functions that always return their parameter can instead be modelled as AliasFunction.
Good idea. On balance, I think your distinction is clearer than mine (which is roughly 'Does this thing claim to be an allocator? Then it is one.').
However due to the existing behaviour in AllocationExpr (which is fairly widely used), I'd rather address this concern in a follow-up PR and give it the care and attention it deserves.
There may be some C++ standard rules about how it's forbidden to reference an old pointer value that's passed through placement new
It seems like you should be able to keep a reference for memory management purposes, e.g.
char *data = new char[BIG_NUMBER];
MyObject *myObject1 = new (data) MyObject();
MyObject *myObject2 = new (data + sizeof(MyObject)) MyObject();
...
delete [] data;
There was a problem hiding this comment.
However due to the existing behaviour in AllocationExpr (which is fairly widely used), I'd rather address this concern in a follow-up PR and give it the care and attention it deserves.
Okay.
It seems like you should be able to keep a reference for memory management purposes
That sounds right.
|
As far as I can tell, this doesn't seem to introduce any semantic conflicts with #3171. #3171 assumes that This PR also merges cleanly with mine. |
|
There are test failures in the IR sanity queries. I took a quick look, and my guess is that they appear because we don't translate allocator calls but now we translate a side effect of those calls. |
|
Fixes:
The expected result is one test failure remains on this PR (the MISRA test), and none on the corresponding PR (when that goes green, both can be merged at the same time). |
AllocationExprdirectly supportsnew, but for various reasons we also want to modeloperator newas anAllocationFunction. Same foroperator new[],operator deleteandoperator delete[].