llvm.org GIT mirror llvm / d4a4c08
Don't consider allocsize functions to be allocation functions. This patch fixes some ASAN unittest failures on FreeBSD. See the cfe-commits email thread for r290169 for more on those. According to the LangRef, the allocsize attribute only tells us about the number of bytes that exist at the memory location pointed to by the return value of a function. It does not necessarily mean that the function will only ever allocate. So, we need to be very careful about treating functions with allocsize as general allocation functions. This patch makes us fully conservative in this regard, though I suspect that we have room to be a bit more aggressive if we want. This has a FIXME that can be fixed by a relatively straightforward refactor; I just wanted to keep this patch minimal. If this sticks, I'll come back and fix it in a few days. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@290397 91177308-0d34-0410-b5e6-96231b3b80d8 George Burgess IV 2 years ago
3 changed file(s) with 79 addition(s) and 23 deletion(s). Raw diff Collapse all Expand all
108108 if (!Callee)
109109 return None;
110110
111 // If it has allocsize, we can skip checking if it's a known function.
112 //
113 // MallocLike is chosen here because allocsize makes no guarantees about the
114 // nullness of the result of the function, nor does it deal with strings, nor
115 // does it require that the memory returned is zeroed out.
116 const AllocType AllocSizeAllocTy = MallocLike;
117 if ((AllocTy & AllocSizeAllocTy) == AllocSizeAllocTy &&
118 Callee->hasFnAttribute(Attribute::AllocSize)) {
119 Attribute Attr = Callee->getFnAttribute(Attribute::AllocSize);
120 std::pair> Args = Attr.getAllocSizeArgs();
121
122 AllocFnsTy Result;
123 Result.AllocTy = AllocSizeAllocTy;
124 Result.NumParams = Callee->getNumOperands();
125 Result.FstParam = Args.first;
126 Result.SndParam = Args.second.getValueOr(-1);
127 return Result;
128 }
129
130111 // Make sure that the function is available.
131112 StringRef FnName = Callee->getName();
132113 LibFunc::Func TLIFn;
160141 FTy->getParamType(SndParam)->isIntegerTy(64)))
161142 return *FnData;
162143 return None;
144 }
145
146 static Optional getAllocationSize(const Value *V,
147 const TargetLibraryInfo *TLI) {
148 // Prefer to use existing information over allocsize. This will give us an
149 // accurate AllocTy.
150 if (Optional Data =
151 getAllocationData(V, AnyAlloc, TLI, /*LookThroughBitCast=*/false))
152 return Data;
153
154 // FIXME: Not calling getCalledFunction twice would be nice.
155 const Function *Callee = getCalledFunction(V, /*LookThroughBitCast=*/false);
156 if (!Callee || !Callee->hasFnAttribute(Attribute::AllocSize))
157 return None;
158
159 Attribute Attr = Callee->getFnAttribute(Attribute::AllocSize);
160 std::pair> Args = Attr.getAllocSizeArgs();
161
162 AllocFnsTy Result;
163 // Because allocsize only tells us how many bytes are allocated, we're not
164 // really allowed to assume anything, so we use MallocLike.
165 Result.AllocTy = MallocLike;
166 Result.NumParams = Callee->getNumOperands();
167 Result.FstParam = Args.first;
168 Result.SndParam = Args.second.getValueOr(-1);
169 return Result;
163170 }
164171
165172 static bool hasNoAliasAttr(const Value *V, bool LookThroughBitCast) {
504511 }
505512
506513 SizeOffsetType ObjectSizeOffsetVisitor::visitCallSite(CallSite CS) {
507 Optional FnData =
508 getAllocationData(CS.getInstruction(), AnyAlloc, TLI);
514 Optional FnData = getAllocationSize(CS.getInstruction(), TLI);
509515 if (!FnData)
510516 return unknown();
511517
764770 }
765771
766772 SizeOffsetEvalType ObjectSizeOffsetEvaluator::visitCallSite(CallSite CS) {
767 Optional FnData =
768 getAllocationData(CS.getInstruction(), AnyAlloc, TLI);
773 Optional FnData = getAllocationSize(CS.getInstruction(), TLI);
769774 if (!FnData)
770775 return unknown();
771776
1313 CGSCCPassManagerTest.cpp
1414 LazyCallGraphTest.cpp
1515 LoopPassManagerTest.cpp
16 MemoryBuiltinsTest.cpp
1617 ScalarEvolutionTest.cpp
1718 TBAATest.cpp
1819 ValueTrackingTest.cpp
0 //===- MemoryBuiltinsTest.cpp - Tests for utilities in MemoryBuiltins.h ---===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/Analysis/MemoryBuiltins.h"
10 #include "llvm/IR/Attributes.h"
11 #include "llvm/IR/Constants.h"
12 #include "llvm/IR/Function.h"
13 #include "llvm/IR/LLVMContext.h"
14 #include "llvm/IR/Module.h"
15 #include "gtest/gtest.h"
16
17 using namespace llvm;
18
19 namespace {
20 // allocsize should not imply that a function is a traditional allocation
21 // function (e.g. that can be optimized out/...); it just tells us how many
22 // bytes exist at the pointer handed back by the function.
23 TEST(AllocSize, AllocationBuiltinsTest) {
24 LLVMContext Context;
25 Module M("", Context);
26 IntegerType *ArgTy = Type::getInt32Ty(Context);
27
28 Function *AllocSizeFn = Function::Create(
29 FunctionType::get(Type::getInt8PtrTy(Context), {ArgTy}, false),
30 GlobalValue::ExternalLinkage, "F", &M);
31
32 AllocSizeFn->addFnAttr(Attribute::getWithAllocSizeArgs(Context, 1, None));
33
34 // 100 is arbitrary.
35 std::unique_ptr Caller(
36 CallInst::Create(AllocSizeFn, {ConstantInt::get(ArgTy, 100)}));
37
38 const TargetLibraryInfo *TLI = nullptr;
39 EXPECT_FALSE(isNoAliasFn(Caller.get(), TLI));
40 EXPECT_FALSE(isMallocLikeFn(Caller.get(), TLI));
41 EXPECT_FALSE(isCallocLikeFn(Caller.get(), TLI));
42 EXPECT_FALSE(isAllocLikeFn(Caller.get(), TLI));
43
44 // FIXME: We might be able to treat allocsize functions as general allocation
45 // functions. For the moment, being conservative seems better (and we'd have
46 // to plumb stuff around `isNoAliasFn`).
47 EXPECT_FALSE(isAllocationFn(Caller.get(), TLI));
48 }
49 }