/builds/2mk6rsew/0/parcoach/parcoach/src/aSSA/andersen/ExternalLibrary.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | #include "parcoach/andersen/Andersen.h" |
2 | | |
3 | | #include "llvm/ADT/STLExtras.h" |
4 | | #include "llvm/Analysis/ValueTracking.h" |
5 | | #include "llvm/IR/Module.h" |
6 | | #include "llvm/Support/raw_ostream.h" |
7 | | |
8 | | #include <cstring> |
9 | | |
10 | | using namespace llvm; |
11 | | |
12 | | static char const *noopFuncs[] = { |
13 | | "log", "log10", "exp", "exp2", "exp10", "strcmp", "strncmp", "strlen", |
14 | | "atoi", "atof", "atol", "atoll", "remove", "unlink", "rename", "memcmp", |
15 | | "free", "execl", "execlp", "execle", "execv", "execvp", "chmod", "puts", |
16 | | "write", "open", "create", "truncate", "chdir", "mkdir", "rmdir", "read", |
17 | | "pipe", "wait", "time", "stat", "fstat", "lstat", "strtod", "strtof", |
18 | | "strtold", "fopen", "fdopen", "fflush", "feof", "fileno", "clearerr", |
19 | | "rewind", "ftell", "ferror", "fgetc", "fgetc", "_IO_getc", "fwrite", |
20 | | "fread", "fgets", "ungetc", "fputc", "fputs", "putc", "ftell", "rewind", |
21 | | "_IO_putc", "fseek", "fgetpos", "fsetpos", "printf", "fprintf", "sprintf", |
22 | | "vprintf", "vfprintf", "vsprintf", "scanf", "fscanf", "sscanf", |
23 | | "__assert_fail", "modf", "putchar", "isalnum", "isalpha", "isascii", |
24 | | "isatty", "isblank", "iscntrl", "isdigit", "isgraph", "islower", "isprint", |
25 | | "ispunct", "isspace", "isupper", "iswalnum", "iswalpha", "iswctype", |
26 | | "iswdigit", "iswlower", "iswspace", "iswprint", "iswupper", "sin", "cos", |
27 | | "sinf", "cosf", "asin", "acos", "tan", "atan", "fabs", "pow", "floor", |
28 | | "ceil", "sqrt", "sqrtf", "hypot", "random", "tolower", "toupper", |
29 | | "towlower", "towupper", "system", "clock", "exit", "abort", "gettimeofday", |
30 | | "settimeofday", "sleep", "ctime", "strspn", "strcspn", "localtime", |
31 | | "strftime", "qsort", "popen", "pclose", "rand", "rand_r", "srand", "seed48", |
32 | | "drand48", "lrand48", "srand48", "__isoc99_sscanf", "__isoc99_fscanf", |
33 | | "fclose", "close", "perror", |
34 | | "strerror", // this function returns an extenal static pointer |
35 | | "__errno_location", "__ctype_b_loc", "abs", "difftime", "setbuf", "_ZdlPv", |
36 | | "_ZdaPv", // delete and delete[] |
37 | | "fesetround", "fegetround", "fetestexcept", "feraiseexcept", |
38 | | "feclearexcept", "llvm.bswap.i16", "llvm.bswap.i32", "llvm.ctlz.i64", |
39 | | "llvm.lifetime.start", "llvm.lifetime.end", "llvm.stackrestore", "memset", |
40 | | "llvm.memset.i32", "llvm.memset.p0i8.i32", "llvm.memset.i64", |
41 | | "llvm.memset.p0i8.i64", "llvm.va_end", |
42 | | // The following functions might not be NOOP. They need to be removed from |
43 | | // this list in the future |
44 | | "setrlimit", "getrlimit", nullptr}; |
45 | | |
46 | | static char const *mallocFuncs[] = {"malloc", |
47 | | "valloc", |
48 | | "calloc", |
49 | | "_Znwj", |
50 | | "_ZnwjRKSt9nothrow_t", |
51 | | "_Znwm", |
52 | | "_ZnwmRKSt9nothrow_t", |
53 | | "_Znaj", |
54 | | "_ZnajRKSt9nothrow_t", |
55 | | "_Znam", |
56 | | "_ZnamRKSt9nothrow_t", |
57 | | "strdup", |
58 | | "strndup", |
59 | | "getenv", |
60 | | "memalign", |
61 | | "posix_memalign", |
62 | | nullptr}; |
63 | | |
64 | | static char const *reallocFuncs[] = {"realloc", "strtok", "strtok_r", nullptr}; |
65 | | |
66 | | static char const *retArg0Funcs[] = { |
67 | | "fgets", "gets", "stpcpy", "strcat", "strchr", |
68 | | "strcpy", "strerror_r", "strncat", "strncpy", "strpbrk", |
69 | | "strptime", "strrchr", "strstr", "getcwd", nullptr}; |
70 | | |
71 | | static char const *retArg1Funcs[] = { |
72 | | // Actually the return value of signal() will NOT alias its second argument, |
73 | | // but if you call it twice the return values may alias. We're making |
74 | | // conservative assumption here |
75 | | "signal", nullptr}; |
76 | | |
77 | | static char const *retArg2Funcs[] = {"freopen", nullptr}; |
78 | | |
79 | | static char const *memcpyFuncs[] = {"llvm.memcpy.i32", |
80 | | "llvm.memcpy.p0i8.p0i8.i32", |
81 | | "llvm.memcpy.i64", |
82 | | "llvm.memcpy.p0i8.p0i8.i64", |
83 | | "llvm.memmove.i32", |
84 | | "llvm.memmove.p0i8.p0i8.i32", |
85 | | "llvm.memmove.i64", |
86 | | "llvm.memmove.p0i8.p0i8.i64", |
87 | | "memccpy", |
88 | | "memmove", |
89 | | "bcopy", |
90 | | nullptr}; |
91 | | |
92 | | static char const *convertFuncs[] = {"strtod", "strtof", "strtol", "strtold", |
93 | | "strtoll", "strtoul", nullptr}; |
94 | | |
95 | 366k | static bool lookupName(char const *table[], char const *str) { |
96 | 11.0M | for (unsigned i = 0; table[i] != nullptr; ++i) { |
97 | 10.7M | if (strcmp(table[i], str) == 0) |
98 | 10.2k | return true; |
99 | 10.7M | } |
100 | 356k | return false; |
101 | 366k | } |
102 | | |
103 | | // This function identifies if the external callsite is a library function call, |
104 | | // and add constraint correspondingly If this is a call to a "known" function, |
105 | | // add the constraints and return true. If this is a call to an unknown |
106 | | // function, return false. |
107 | | bool Andersen::addConstraintForExternalLibrary(CallBase const &cs, |
108 | 54.1k | Function const *f) { |
109 | 54.1k | assert(f != nullptr && "called function is nullptr!"); |
110 | 54.1k | assert((f->isDeclaration() || f->isIntrinsic()) && |
111 | 54.1k | "Not an external function!"); |
112 | | |
113 | | // These functions don't induce any points-to constraints |
114 | 54.1k | if (lookupName(noopFuncs, f->getName().data())) |
115 | 7.72k | return true; |
116 | | |
117 | | // Realloc-like library is a little different: if the first argument is |
118 | | // nullptr, then it behaves like retArg0Funcs; otherwise, it behaves like |
119 | | // mallocFuncs |
120 | 46.4k | bool isReallocLike = lookupName(reallocFuncs, f->getName().data()); |
121 | | |
122 | | // Library calls that might allocate memory. |
123 | 46.4k | if (lookupName(mallocFuncs, f->getName().data()) || |
124 | 46.4k | (isReallocLike && !isa<ConstantPointerNull>(cs.getArgOperand(0)))) { |
125 | 2.54k | Instruction const *inst = &cs; |
126 | | |
127 | | // Create the obj node |
128 | 2.54k | NodeIndex objIndex = nodeFactory.createObjectNode(inst); |
129 | | |
130 | | // Get the pointer node |
131 | 2.54k | NodeIndex ptrIndex = nodeFactory.getValueNodeFor(inst); |
132 | 2.54k | if (ptrIndex == AndersNodeFactory::InvalidIndex) { |
133 | | // Must be something like posix_memalign() |
134 | 0 | if (f->getName() == "posix_memalign") { |
135 | 0 | ptrIndex = nodeFactory.getValueNodeFor(cs.getArgOperand(0)); |
136 | 0 | assert(ptrIndex != AndersNodeFactory::InvalidIndex && |
137 | 0 | "Failed to find arg0 node"); |
138 | 0 | constraints.emplace_back(AndersConstraint::STORE, ptrIndex, objIndex); |
139 | 0 | } else { |
140 | 0 | errs() << f->getName() << '\n'; |
141 | 0 | assert(false && "unrecognized malloc call"); |
142 | 0 | } |
143 | 2.54k | } else { |
144 | | // Normal malloc-like call |
145 | 2.54k | constraints.emplace_back(AndersConstraint::ADDR_OF, ptrIndex, objIndex); |
146 | 2.54k | } |
147 | | |
148 | 2.54k | return true; |
149 | 2.54k | } |
150 | | |
151 | 43.8k | if (lookupName(retArg0Funcs, f->getName().data()) || |
152 | 43.8k | (isReallocLike && isa<ConstantPointerNull>(cs.getArgOperand(0)))) { |
153 | 0 | NodeIndex retIndex = nodeFactory.getValueNodeFor(&cs); |
154 | 0 | if (retIndex != AndersNodeFactory::InvalidIndex) { |
155 | 0 | NodeIndex arg0Index = nodeFactory.getValueNodeFor(cs.getArgOperand(0)); |
156 | 0 | assert(arg0Index != AndersNodeFactory::InvalidIndex && |
157 | 0 | "Failed to find arg0 node"); |
158 | 0 | constraints.emplace_back(AndersConstraint::COPY, retIndex, arg0Index); |
159 | 0 | } |
160 | |
|
161 | 0 | return true; |
162 | 0 | } |
163 | | |
164 | 43.8k | if (lookupName(retArg1Funcs, f->getName().data())) { |
165 | 0 | NodeIndex retIndex = nodeFactory.getValueNodeFor(&cs); |
166 | 0 | assert(retIndex != AndersNodeFactory::InvalidIndex && |
167 | 0 | "Failed to find call site node"); |
168 | 0 | NodeIndex arg1Index = nodeFactory.getValueNodeFor(cs.getArgOperand(1)); |
169 | 0 | assert(arg1Index != AndersNodeFactory::InvalidIndex && |
170 | 0 | "Failed to find arg1 node"); |
171 | 0 | constraints.emplace_back(AndersConstraint::COPY, retIndex, arg1Index); |
172 | 0 | return true; |
173 | 0 | } |
174 | | |
175 | 43.8k | if (lookupName(retArg2Funcs, f->getName().data())) { |
176 | 0 | NodeIndex retIndex = nodeFactory.getValueNodeFor(&cs); |
177 | 0 | assert(retIndex != AndersNodeFactory::InvalidIndex && |
178 | 0 | "Failed to find call site node"); |
179 | 0 | NodeIndex arg2Index = nodeFactory.getValueNodeFor(cs.getArgOperand(2)); |
180 | 0 | assert(arg2Index != AndersNodeFactory::InvalidIndex && |
181 | 0 | "Failed to find arg2 node"); |
182 | 0 | constraints.emplace_back(AndersConstraint::COPY, retIndex, arg2Index); |
183 | 0 | return true; |
184 | 0 | } |
185 | | |
186 | 43.8k | if (lookupName(memcpyFuncs, f->getName().data())) { |
187 | 1 | NodeIndex arg0Index = nodeFactory.getValueNodeFor(cs.getArgOperand(0)); |
188 | 1 | assert(arg0Index != AndersNodeFactory::InvalidIndex && |
189 | 1 | "Failed to find arg0 node"); |
190 | 1 | NodeIndex arg1Index = nodeFactory.getValueNodeFor(cs.getArgOperand(1)); |
191 | 1 | assert(arg1Index != AndersNodeFactory::InvalidIndex && |
192 | 1 | "Failed to find arg1 node"); |
193 | | |
194 | 1 | NodeIndex tempIndex = nodeFactory.createValueNode(); |
195 | 1 | constraints.emplace_back(AndersConstraint::LOAD, tempIndex, arg1Index); |
196 | 1 | constraints.emplace_back(AndersConstraint::STORE, arg0Index, tempIndex); |
197 | | |
198 | | // Don't forget the return value |
199 | 1 | NodeIndex retIndex = nodeFactory.getValueNodeFor(&cs); |
200 | 1 | if (retIndex != AndersNodeFactory::InvalidIndex) |
201 | 1 | constraints.emplace_back(AndersConstraint::COPY, retIndex, arg0Index); |
202 | | |
203 | 1 | return true; |
204 | 1 | } |
205 | | |
206 | 43.8k | if (lookupName(convertFuncs, f->getName().data())) { |
207 | 0 | if (!isa<ConstantPointerNull>(cs.getArgOperand(1))) { |
208 | 0 | NodeIndex arg0Index = nodeFactory.getValueNodeFor(cs.getArgOperand(0)); |
209 | 0 | assert(arg0Index != AndersNodeFactory::InvalidIndex && |
210 | 0 | "Failed to find arg0 node"); |
211 | 0 | NodeIndex arg1Index = nodeFactory.getValueNodeFor(cs.getArgOperand(1)); |
212 | 0 | assert(arg1Index != AndersNodeFactory::InvalidIndex && |
213 | 0 | "Failed to find arg1 node"); |
214 | 0 | constraints.emplace_back(AndersConstraint::STORE, arg0Index, arg1Index); |
215 | 0 | } |
216 | |
|
217 | 0 | return true; |
218 | 0 | } |
219 | | |
220 | 43.8k | if (f->getName() == "llvm.va_start") { |
221 | 0 | Instruction const *inst = &cs; |
222 | 0 | Function const *parentF = inst->getParent()->getParent(); |
223 | 0 | assert(parentF->getFunctionType()->isVarArg()); |
224 | 0 | NodeIndex arg0Index = nodeFactory.getValueNodeFor(cs.getArgOperand(0)); |
225 | 0 | assert(arg0Index != AndersNodeFactory::InvalidIndex && |
226 | 0 | "Failed to find arg0 node"); |
227 | 0 | NodeIndex vaIndex = nodeFactory.getVarargNodeFor(parentF); |
228 | 0 | assert(vaIndex != AndersNodeFactory::InvalidIndex && |
229 | 0 | "Failed to find va node"); |
230 | 0 | constraints.emplace_back(AndersConstraint::ADDR_OF, arg0Index, vaIndex); |
231 | |
|
232 | 0 | return true; |
233 | 0 | } |
234 | | |
235 | 43.8k | return false; |
236 | 43.8k | } |