-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[LifetimeSafety] Add implicit tracking for STL functions #170005
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: users/usx95/11-17-lifetime-safety-multi-origin
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -71,6 +71,88 @@ bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD) { | |
| return isNormalAssignmentOperator(FD); | ||
| } | ||
|
|
||
| // Decl::isInStdNamespace will return false for iterators in some STL | ||
| // implementations due to them being defined in a namespace outside of the std | ||
| // namespace. | ||
| static bool isInStlNamespace(const Decl *D) { | ||
| const DeclContext *DC = D->getDeclContext(); | ||
| if (!DC) | ||
| return false; | ||
| if (const auto *ND = dyn_cast<NamespaceDecl>(DC)) | ||
| if (const IdentifierInfo *II = ND->getIdentifier()) { | ||
| StringRef Name = II->getName(); | ||
| if (Name.size() >= 2 && Name.front() == '_' && | ||
| (Name[1] == '_' || isUppercase(Name[1]))) | ||
| return true; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. probably an off-topic comment: the code looks suspicious to me, if a namespace name with the prefix
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think (at least in some version of) libstdc++ there were some types that were not part of the top level |
||
| } | ||
|
|
||
| return DC->isStdNamespace(); | ||
| } | ||
|
|
||
| static bool isPointerLikeType(QualType QT) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same for this function, we have two instances. |
||
| return isGslPointerType(QT) || QT->isPointerType() || QT->isNullPtrType(); | ||
| } | ||
|
|
||
| bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) { | ||
| if (auto *Conv = dyn_cast_or_null<CXXConversionDecl>(Callee)) | ||
| if (isGslPointerType(Conv->getConversionType()) && | ||
| Callee->getParent()->hasAttr<OwnerAttr>()) | ||
| return true; | ||
| if (!isInStlNamespace(Callee->getParent())) | ||
| return false; | ||
| if (!isGslPointerType(Callee->getFunctionObjectParameterType()) && | ||
| !isGslOwnerType(Callee->getFunctionObjectParameterType())) | ||
| return false; | ||
| if (isPointerLikeType(Callee->getReturnType())) { | ||
| if (!Callee->getIdentifier()) | ||
| return false; | ||
| return llvm::StringSwitch<bool>(Callee->getName()) | ||
| .Cases({"begin", "rbegin", "cbegin", "crbegin"}, true) | ||
| .Cases({"end", "rend", "cend", "crend"}, true) | ||
| .Cases({"c_str", "data", "get"}, true) | ||
| // Map and set types. | ||
| .Cases({"find", "equal_range", "lower_bound", "upper_bound"}, true) | ||
| .Default(false); | ||
| } | ||
| if (Callee->getReturnType()->isReferenceType()) { | ||
| if (!Callee->getIdentifier()) { | ||
| auto OO = Callee->getOverloadedOperator(); | ||
| if (!Callee->getParent()->hasAttr<OwnerAttr>()) | ||
| return false; | ||
| return OO == OverloadedOperatorKind::OO_Subscript || | ||
| OO == OverloadedOperatorKind::OO_Star; | ||
| } | ||
| return llvm::StringSwitch<bool>(Callee->getName()) | ||
| .Cases({"front", "back", "at", "top", "value"}, true) | ||
| .Default(false); | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| bool shouldTrackFirstArgument(const FunctionDecl *FD) { | ||
| if (!FD->getIdentifier() || FD->getNumParams() != 1) | ||
| return false; | ||
| const auto *RD = FD->getParamDecl(0)->getType()->getPointeeCXXRecordDecl(); | ||
| if (!FD->isInStdNamespace() || !RD || !RD->isInStdNamespace()) | ||
| return false; | ||
| if (!RD->hasAttr<PointerAttr>() && !RD->hasAttr<OwnerAttr>()) | ||
| return false; | ||
| if (FD->getReturnType()->isPointerType() || | ||
| isGslPointerType(FD->getReturnType())) { | ||
| return llvm::StringSwitch<bool>(FD->getName()) | ||
| .Cases({"begin", "rbegin", "cbegin", "crbegin"}, true) | ||
| .Cases({"end", "rend", "cend", "crend"}, true) | ||
| .Case("data", true) | ||
| .Default(false); | ||
| } | ||
| if (FD->getReturnType()->isReferenceType()) { | ||
| return llvm::StringSwitch<bool>(FD->getName()) | ||
| .Cases({"get", "any_cast"}, true) | ||
| .Default(false); | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| template <typename T> static bool isRecordWithAttr(QualType Type) { | ||
| auto *RD = Type->getAsCXXRecordDecl(); | ||
| if (!RD) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: we seem to have this exact function at two locations now. Should we deduplicate this as well?