diff --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp --- a/llvm/lib/Analysis/MemoryBuiltins.cpp +++ b/llvm/lib/Analysis/MemoryBuiltins.cpp @@ -271,15 +271,42 @@ return Result; } +static AllocFnKind getAllocFnKind(const Value *V) { + if (const auto *CB = dyn_cast(V)) { + Attribute Attr = CB->getFnAttr(Attribute::AllocKind); + if (Attr.isValid()) + return AllocFnKind(Attr.getValueAsInt()); + } + return AllocFnKind::Unknown; +} + +static AllocFnKind getAllocFnKind(const Function *F) { + Attribute Attr = F->getFnAttribute(Attribute::AllocKind); + if (Attr.isValid()) + return AllocFnKind(Attr.getValueAsInt()); + return AllocFnKind::Unknown; +} + +static bool checkFnAllocKind(const Value *V, AllocFnKind Wanted) { + return (getAllocFnKind(V) & Wanted) != AllocFnKind::Unknown; +} + +static bool checkFnAllocKind(const Function *F, AllocFnKind Wanted) { + return (getAllocFnKind(F) & Wanted) != AllocFnKind::Unknown; +} + /// Tests if a value is a call or invoke to a library function that /// allocates or reallocates memory (either malloc, calloc, realloc, or strdup /// like). bool llvm::isAllocationFn(const Value *V, const TargetLibraryInfo *TLI) { - return getAllocationData(V, AnyAlloc, TLI).has_value(); + return getAllocationData(V, AnyAlloc, TLI).has_value() || + checkFnAllocKind(V, AllocFnKind::Alloc | AllocFnKind::Realloc); } bool llvm::isAllocationFn( - const Value *V, function_ref GetTLI) { - return getAllocationData(V, AnyAlloc, GetTLI).has_value(); + const Value *V, + function_ref GetTLI) { + return getAllocationData(V, AnyAlloc, GetTLI).has_value() || + checkFnAllocKind(V, AllocFnKind::Alloc | AllocFnKind::Realloc); } /// Tests if a value is a call or invoke to a library function that @@ -309,13 +336,15 @@ /// Tests if a value is a call or invoke to a library function that /// allocates memory (either malloc, calloc, or strdup like). bool llvm::isAllocLikeFn(const Value *V, const TargetLibraryInfo *TLI) { - return getAllocationData(V, AllocLike, TLI).has_value(); + return getAllocationData(V, AllocLike, TLI).has_value() || + checkFnAllocKind(V, AllocFnKind::Alloc); } /// Tests if a functions is a call or invoke to a library function that /// reallocates memory (e.g., realloc). bool llvm::isReallocLikeFn(const Function *F, const TargetLibraryInfo *TLI) { - return getAllocationDataForFunction(F, ReallocLike, TLI).has_value(); + return getAllocationDataForFunction(F, ReallocLike, TLI).has_value() || + checkFnAllocKind(F, AllocFnKind::Realloc); } Value *llvm::getReallocatedOperand(const CallBase *CB, @@ -324,6 +353,8 @@ // All currently supported realloc functions reallocate the first argument. return CB->getArgOperand(0); } + if (checkFnAllocKind(CB, AllocFnKind::Realloc)) + return CB->getArgOperandWithAttribute(Attribute::AllocatedPointer); return nullptr; } @@ -440,6 +471,12 @@ if (isCallocLikeFn(Alloc, TLI)) return Constant::getNullValue(Ty); + AllocFnKind AK = getAllocFnKind(Alloc); + if ((AK & AllocFnKind::Uninitialized) != AllocFnKind::Unknown) + return UndefValue::get(Ty); + if ((AK & AllocFnKind::Zeroed) != AllocFnKind::Unknown) + return Constant::getNullValue(Ty); + return nullptr; } @@ -511,6 +548,12 @@ const auto FreeData = getFreeFunctionDataForFunction(Callee, TLIFn); if (FreeData) return mangledNameForMallocFamily(FreeData.value().Family); + if (checkFnAllocKind(I, AllocFnKind::Free | AllocFnKind::Alloc | + AllocFnKind::Realloc)) { + Attribute Attr = cast(I)->getFnAttr("alloc-family"); + if (Attr.isValid()) + return Attr.getValueAsString(); + } return None; } @@ -518,7 +561,7 @@ bool llvm::isLibFreeFunction(const Function *F, const LibFunc TLIFn) { Optional FnData = getFreeFunctionDataForFunction(F, TLIFn); if (!FnData) - return false; + return checkFnAllocKind(F, AllocFnKind::Free); // Check free prototype. // FIXME: workaround for PR5130, this will be obsolete when a nobuiltin @@ -547,6 +590,9 @@ return CB->getArgOperand(0); } + if (checkFnAllocKind(CB, AllocFnKind::Free)) + return CB->getArgOperandWithAttribute(Attribute::AllocatedPointer); + return nullptr; }