Repository navigation
Redesign IsDeallocator to obtain deallocation behaviour per param - #1121
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1121 +/- ##
==========================================
+ Coverage 88.52% 88.63% +0.10%
==========================================
Files 24 24
Lines 6851 6908 +57
==========================================
+ Hits 6065 6123 +58
+ Misses 786 785 -1
🚀 New features to boost your workflow:
|
| // does not have self 0th index will be DeallocType::None. | ||
| // So actual first parameter is located at 1st index it is | ||
| // also compatible with Clang convension. | ||
| std::vector<DeallocType> IsDeallocator(ConstFuncRef Fn) { |
There was a problem hiding this comment.
warning: no header providing "Cpp::DeallocType" is directly included [misc-include-cleaner]
h Clang convension.
^57c0f0d to
f229cff
Compare
Vipul-Cariappa
left a comment
There was a problem hiding this comment.
Initial round of review:
I should still look at the tests.
| else if (attrName == "cppDeallocNone") | ||
| kind = DeallocType::None; |
There was a problem hiding this comment.
| else if (attrName == "cppDeallocNone") | |
| kind = DeallocType::None; |
I believe this is safe.
There was a problem hiding this comment.
The reason I put None for both cppAlloc and cppDealloc is, if there is a vulnerability in analyzer and it causes a UB, analyzer can be supressed until it is fixed
| } else if (token.consume_front("cppDeallocNone_")) { | ||
| unsigned index; | ||
| if (!token.getAsInteger(10, index) && index < VPP.size()) | ||
| VPP[index] = DeallocType::None; |
There was a problem hiding this comment.
| } else if (token.consume_front("cppDeallocNone_")) { | |
| unsigned index; | |
| if (!token.getAsInteger(10, index) && index < VPP.size()) | |
| VPP[index] = DeallocType::None; |
I believe this is safe to remove.
There was a problem hiding this comment.
if (!token.getAsInteger(10, index)This is necessary, because we know that an integer comes after CppDeallocDelete_ via getAsInteger, but
&& index < VPP.size()may be removed, but i still prefer to not
There was a problem hiding this comment.
I did not remove these checks, I believe having bound checks are necessary
f229cff to
75a4ff2
Compare
| // cppDeallocDelete_2 to labeling first actual parameter, also it is not allowed | ||
| // to label implicit `this`. So actual first parameter is located at 1st index, | ||
| // if implicit `this` exists. | ||
| bool IsDeallocator(ConstFuncRef Fn, std::vector<DeallocType>& VPP) { |
There was a problem hiding this comment.
warning: no header providing "Cpp::DeallocType" is directly included [misc-include-cleaner]
icit `this` exists.
^75a4ff2 to
dd4ff85
Compare
| if (VPP.size() != numParam + hasImplicitThis) | ||
| return INTEROP_RETURN(false); |
There was a problem hiding this comment.
We should not rewrite existing elements.
| if (index < 0 || (uint64_t)(index - 1) >= VPP.size() || | ||
| (index == 1 && hasImplicitThis)) | ||
| continue; |
There was a problem hiding this comment.
| if (index < 0 || (uint64_t)(index - 1) >= VPP.size() || | |
| (index == 1 && hasImplicitThis)) | |
| continue; | |
| if (index <= 0 || index > VPP.size() || | |
| (index == 1 && hasImplicitThis)) | |
| continue; |
?
| if (!token.consume_front("_") || token.getAsInteger(10, index) || | ||
| index < 1 || index - 1 >= VPP.size() || | ||
| (hasImplicitThis && index == 1)) | ||
| continue; |
There was a problem hiding this comment.
Cross-check this...
| - Name: releaseBoth | ||
| SwiftReturnOwnership: "cppDeallocDelete_1 cppDeallocFree_2" | ||
| - Name: releaseBare | ||
| SwiftReturnOwnership: cppDeallocDelete No newline at end of file |
There was a problem hiding this comment.
Add a newline here.
2c2c688 to
4a53d07
Compare
IsDeallocator used to answer a single bool for the whole function, which
could not say *which* argument is released, nor with which operation. It
now appends one DeallocType per parameter to the given vector, preceded
by one entry for the object parameter when the function has an implicit
this. Whatever the vector already holds is left untouched, so the results
of several functions can be collected into one vector.
A slot carries the value of clang's source index one above it, following
the convention of the ownership attributes: indexes are 1 based and count
the implicit this. Labelling the implicit this is not supported, and such
a label is ignored rather than diagnosed, as is an out of range one. The
index may also be omitted, in which case the first actual parameter is
meant.
A parameter carrying no deallocation attribute is reported as Opaque
rather than None, so that a later analyzer pass can tell "no information"
apart from "labelled cppDeallocNone" and merge the two sources.
False is returned only when the given declaration is not a function, in
which case the vector is not modified at all.
Three attribute channels feed the vector:
- ownership_takes/holds: clang's own ParamIdx, read through
getLLVMIndex(), which is the same zero origin encoding counting the
implicit this. Sema validates these indexes, so no range check is
needed here.
- annotate("cppDeallocFree"/"Delete"/"DeleteArr"/"None"[, i...]): Sema
does not validate the indexes, so out of range, zero, negative and
non-integral arguments are dropped here.
- swift_attr with space separated "cppDeallocFree[_1]" style tokens,
which is the only shape API Notes can express through its single
SwiftReturnOwnership string.
On a conflicting index the last matching attribute wins.
4a53d07 to
0866403
Compare
| // Function appends a DeallocType to the vector taken, for every argument in | ||
| // the function including implicit this. If an argument does not have an | ||
| // deallocation ownership, Opaque value is added. | ||
| bool IsDeallocator(ConstFuncRef Fn, std::vector<DeallocType>& VPP) { |
There was a problem hiding this comment.
warning: no header providing "Cpp::DeallocType" is directly included [misc-include-cleaner]
que value is added.
^| std::vector<DeallocType> newVPP(numParam + hasImplicitThis, | ||
| DeallocType::Opaque); | ||
| if (FD->getBuiltinID() == Builtin::ID::BIfree) { | ||
| VPP.push_back(DeallocType::Free); | ||
| return INTEROP_RETURN(true); | ||
| } |
There was a problem hiding this comment.
| std::vector<DeallocType> newVPP(numParam + hasImplicitThis, | |
| DeallocType::Opaque); | |
| if (FD->getBuiltinID() == Builtin::ID::BIfree) { | |
| VPP.push_back(DeallocType::Free); | |
| return INTEROP_RETURN(true); | |
| } | |
| if (FD->getBuiltinID() == Builtin::ID::BIfree) { | |
| VPP.push_back(DeallocType::Free); | |
| return INTEROP_RETURN(true); | |
| } | |
| std::vector<DeallocType> newVPP(numParam + hasImplicitThis, | |
| DeallocType::Opaque); |
The vector can be create after this if
I would rather get this PR merged and rewrite compiler-research/cppjit#114
The former version of IsDeallocator was just looking for Clang attributes and ID check for free and returning a bool so index information was disappearing, but now it recognizes our keyword similar to IsAllocator:
for both annotation and APINotes, and also recognizes which index is given by ownership_attrs. And returns a bool which indicates whether attribute lookup was successful or not, and writes to the vector parameter it takes.
Details for usage:
Clang's convention of ownership attributes are followed, parameters are 1-indexed, therefore if user wants to label first parameter it should write
cppDeallocDelete_1If the function has an implicit this first parameter is
this, therefore user should writecppDeallocDelete_2to label first actual parameter. Also it is not allowed to labelthisparameter.If user did not indicate the index for attribute, the attribute is assumed to be for first index
I am still not able to use modules in Cling, therefore APINotes tests are skipped for cling
Also only missing thing will be custom allocator-deallocator pairing after this one is merged, so we are close to have a properly working design :)