Coverage Report

Created: 2023-10-30 17:15

/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
}