@@ -73,7 +73,38 @@ class CStringChecker : public Checker< eval::Call,
73
73
74
74
typedef void (CStringChecker::*FnCheck)(CheckerContext &,
75
75
const CallExpr *) const ;
76
+ CallDescriptionMap<FnCheck> Callbacks = {
77
+ {{CDF_MaybeBuiltin, " memcpy" , 3 }, &CStringChecker::evalMemcpy},
78
+ {{CDF_MaybeBuiltin, " mempcpy" , 3 }, &CStringChecker::evalMempcpy},
79
+ {{CDF_MaybeBuiltin, " memcmp" , 3 }, &CStringChecker::evalMemcmp},
80
+ {{CDF_MaybeBuiltin, " memmove" , 3 }, &CStringChecker::evalMemmove},
81
+ {{CDF_MaybeBuiltin, " memset" , 3 }, &CStringChecker::evalMemset},
82
+ {{CDF_MaybeBuiltin, " explicit_memset" , 3 }, &CStringChecker::evalMemset},
83
+ {{CDF_MaybeBuiltin, " strcpy" , 2 }, &CStringChecker::evalStrcpy},
84
+ {{CDF_MaybeBuiltin, " strncpy" , 3 }, &CStringChecker::evalStrncpy},
85
+ {{CDF_MaybeBuiltin, " stpcpy" , 2 }, &CStringChecker::evalStpcpy},
86
+ {{CDF_MaybeBuiltin, " strlcpy" , 3 }, &CStringChecker::evalStrlcpy},
87
+ {{CDF_MaybeBuiltin, " strcat" , 2 }, &CStringChecker::evalStrcat},
88
+ {{CDF_MaybeBuiltin, " strncat" , 3 }, &CStringChecker::evalStrncat},
89
+ {{CDF_MaybeBuiltin, " strlcat" , 3 }, &CStringChecker::evalStrlcat},
90
+ {{CDF_MaybeBuiltin, " strlen" , 1 }, &CStringChecker::evalstrLength},
91
+ {{CDF_MaybeBuiltin, " strnlen" , 2 }, &CStringChecker::evalstrnLength},
92
+ {{CDF_MaybeBuiltin, " strcmp" , 2 }, &CStringChecker::evalStrcmp},
93
+ {{CDF_MaybeBuiltin, " strncmp" , 3 }, &CStringChecker::evalStrncmp},
94
+ {{CDF_MaybeBuiltin, " strcasecmp" , 2 }, &CStringChecker::evalStrcasecmp},
95
+ {{CDF_MaybeBuiltin, " strncasecmp" , 3 }, &CStringChecker::evalStrncasecmp},
96
+ {{CDF_MaybeBuiltin, " strsep" , 2 }, &CStringChecker::evalStrsep},
97
+ {{CDF_MaybeBuiltin, " bcopy" , 3 }, &CStringChecker::evalBcopy},
98
+ {{CDF_MaybeBuiltin, " bcmp" , 3 }, &CStringChecker::evalMemcmp},
99
+ {{CDF_MaybeBuiltin, " bzero" , 2 }, &CStringChecker::evalBzero},
100
+ {{CDF_MaybeBuiltin, " explicit_bzero" , 2 }, &CStringChecker::evalBzero},
101
+ };
102
+
103
+ // These require a bit of special handling.
104
+ CallDescription StdCopy{{" std" , " copy" }, 3 },
105
+ StdCopyBackward{{" std" , " copy_backward" }, 3 };
76
106
107
+ FnCheck identifyCall (const CallEvent &Call, CheckerContext &C) const ;
77
108
void evalMemcpy (CheckerContext &C, const CallExpr *CE) const ;
78
109
void evalMempcpy (CheckerContext &C, const CallExpr *CE) const ;
79
110
void evalMemmove (CheckerContext &C, const CallExpr *CE) const ;
@@ -1201,9 +1232,6 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
1201
1232
1202
1233
1203
1234
void CStringChecker::evalMemcpy (CheckerContext &C, const CallExpr *CE) const {
1204
- if (CE->getNumArgs () < 3 )
1205
- return ;
1206
-
1207
1235
// void *memcpy(void *restrict dst, const void *restrict src, size_t n);
1208
1236
// The return value is the address of the destination buffer.
1209
1237
const Expr *Dest = CE->getArg (0 );
@@ -1213,9 +1241,6 @@ void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const {
1213
1241
}
1214
1242
1215
1243
void CStringChecker::evalMempcpy (CheckerContext &C, const CallExpr *CE) const {
1216
- if (CE->getNumArgs () < 3 )
1217
- return ;
1218
-
1219
1244
// void *mempcpy(void *restrict dst, const void *restrict src, size_t n);
1220
1245
// The return value is a pointer to the byte following the last written byte.
1221
1246
const Expr *Dest = CE->getArg (0 );
@@ -1225,9 +1250,6 @@ void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const {
1225
1250
}
1226
1251
1227
1252
void CStringChecker::evalMemmove (CheckerContext &C, const CallExpr *CE) const {
1228
- if (CE->getNumArgs () < 3 )
1229
- return ;
1230
-
1231
1253
// void *memmove(void *dst, const void *src, size_t n);
1232
1254
// The return value is the address of the destination buffer.
1233
1255
const Expr *Dest = CE->getArg (0 );
@@ -1237,18 +1259,12 @@ void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const {
1237
1259
}
1238
1260
1239
1261
void CStringChecker::evalBcopy (CheckerContext &C, const CallExpr *CE) const {
1240
- if (CE->getNumArgs () < 3 )
1241
- return ;
1242
-
1243
1262
// void bcopy(const void *src, void *dst, size_t n);
1244
1263
evalCopyCommon (C, CE, C.getState (),
1245
1264
CE->getArg (2 ), CE->getArg (1 ), CE->getArg (0 ));
1246
1265
}
1247
1266
1248
1267
void CStringChecker::evalMemcmp (CheckerContext &C, const CallExpr *CE) const {
1249
- if (CE->getNumArgs () < 3 )
1250
- return ;
1251
-
1252
1268
// int memcmp(const void *s1, const void *s2, size_t n);
1253
1269
CurrentFunctionDescription = " memory comparison function" ;
1254
1270
@@ -1323,18 +1339,12 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
1323
1339
1324
1340
void CStringChecker::evalstrLength (CheckerContext &C,
1325
1341
const CallExpr *CE) const {
1326
- if (CE->getNumArgs () < 1 )
1327
- return ;
1328
-
1329
1342
// size_t strlen(const char *s);
1330
1343
evalstrLengthCommon (C, CE, /* IsStrnlen = */ false );
1331
1344
}
1332
1345
1333
1346
void CStringChecker::evalstrnLength (CheckerContext &C,
1334
1347
const CallExpr *CE) const {
1335
- if (CE->getNumArgs () < 2 )
1336
- return ;
1337
-
1338
1348
// size_t strnlen(const char *s, size_t maxlen);
1339
1349
evalstrLengthCommon (C, CE, /* IsStrnlen = */ true );
1340
1350
}
@@ -1459,9 +1469,6 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
1459
1469
}
1460
1470
1461
1471
void CStringChecker::evalStrcpy (CheckerContext &C, const CallExpr *CE) const {
1462
- if (CE->getNumArgs () < 2 )
1463
- return ;
1464
-
1465
1472
// char *strcpy(char *restrict dst, const char *restrict src);
1466
1473
evalStrcpyCommon (C, CE,
1467
1474
/* returnEnd = */ false ,
@@ -1470,9 +1477,6 @@ void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) const {
1470
1477
}
1471
1478
1472
1479
void CStringChecker::evalStrncpy (CheckerContext &C, const CallExpr *CE) const {
1473
- if (CE->getNumArgs () < 3 )
1474
- return ;
1475
-
1476
1480
// char *strncpy(char *restrict dst, const char *restrict src, size_t n);
1477
1481
evalStrcpyCommon (C, CE,
1478
1482
/* returnEnd = */ false ,
@@ -1481,9 +1485,6 @@ void CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) const {
1481
1485
}
1482
1486
1483
1487
void CStringChecker::evalStpcpy (CheckerContext &C, const CallExpr *CE) const {
1484
- if (CE->getNumArgs () < 2 )
1485
- return ;
1486
-
1487
1488
// char *stpcpy(char *restrict dst, const char *restrict src);
1488
1489
evalStrcpyCommon (C, CE,
1489
1490
/* returnEnd = */ true ,
@@ -1492,9 +1493,6 @@ void CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) const {
1492
1493
}
1493
1494
1494
1495
void CStringChecker::evalStrlcpy (CheckerContext &C, const CallExpr *CE) const {
1495
- if (CE->getNumArgs () < 3 )
1496
- return ;
1497
-
1498
1496
// char *strlcpy(char *dst, const char *src, size_t n);
1499
1497
evalStrcpyCommon (C, CE,
1500
1498
/* returnEnd = */ true ,
@@ -1504,9 +1502,6 @@ void CStringChecker::evalStrlcpy(CheckerContext &C, const CallExpr *CE) const {
1504
1502
}
1505
1503
1506
1504
void CStringChecker::evalStrcat (CheckerContext &C, const CallExpr *CE) const {
1507
- if (CE->getNumArgs () < 2 )
1508
- return ;
1509
-
1510
1505
// char *strcat(char *restrict s1, const char *restrict s2);
1511
1506
evalStrcpyCommon (C, CE,
1512
1507
/* returnEnd = */ false ,
@@ -1515,9 +1510,6 @@ void CStringChecker::evalStrcat(CheckerContext &C, const CallExpr *CE) const {
1515
1510
}
1516
1511
1517
1512
void CStringChecker::evalStrncat (CheckerContext &C, const CallExpr *CE) const {
1518
- if (CE->getNumArgs () < 3 )
1519
- return ;
1520
-
1521
1513
// char *strncat(char *restrict s1, const char *restrict s2, size_t n);
1522
1514
evalStrcpyCommon (C, CE,
1523
1515
/* returnEnd = */ false ,
@@ -1526,9 +1518,6 @@ void CStringChecker::evalStrncat(CheckerContext &C, const CallExpr *CE) const {
1526
1518
}
1527
1519
1528
1520
void CStringChecker::evalStrlcat (CheckerContext &C, const CallExpr *CE) const {
1529
- if (CE->getNumArgs () < 3 )
1530
- return ;
1531
-
1532
1521
// FIXME: strlcat() uses a different rule for bound checking, i.e. 'n' means
1533
1522
// a different thing as compared to strncat(). This currently causes
1534
1523
// false positives in the alpha string bound checker.
@@ -1885,35 +1874,23 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
1885
1874
}
1886
1875
1887
1876
void CStringChecker::evalStrcmp (CheckerContext &C, const CallExpr *CE) const {
1888
- if (CE->getNumArgs () < 2 )
1889
- return ;
1890
-
1891
1877
// int strcmp(const char *s1, const char *s2);
1892
1878
evalStrcmpCommon (C, CE, /* isBounded = */ false , /* ignoreCase = */ false );
1893
1879
}
1894
1880
1895
1881
void CStringChecker::evalStrncmp (CheckerContext &C, const CallExpr *CE) const {
1896
- if (CE->getNumArgs () < 3 )
1897
- return ;
1898
-
1899
1882
// int strncmp(const char *s1, const char *s2, size_t n);
1900
1883
evalStrcmpCommon (C, CE, /* isBounded = */ true , /* ignoreCase = */ false );
1901
1884
}
1902
1885
1903
1886
void CStringChecker::evalStrcasecmp (CheckerContext &C,
1904
1887
const CallExpr *CE) const {
1905
- if (CE->getNumArgs () < 2 )
1906
- return ;
1907
-
1908
1888
// int strcasecmp(const char *s1, const char *s2);
1909
1889
evalStrcmpCommon (C, CE, /* isBounded = */ false , /* ignoreCase = */ true );
1910
1890
}
1911
1891
1912
1892
void CStringChecker::evalStrncasecmp (CheckerContext &C,
1913
1893
const CallExpr *CE) const {
1914
- if (CE->getNumArgs () < 3 )
1915
- return ;
1916
-
1917
1894
// int strncasecmp(const char *s1, const char *s2, size_t n);
1918
1895
evalStrcmpCommon (C, CE, /* isBounded = */ true , /* ignoreCase = */ true );
1919
1896
}
@@ -2047,9 +2024,6 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
2047
2024
2048
2025
void CStringChecker::evalStrsep (CheckerContext &C, const CallExpr *CE) const {
2049
2026
// char *strsep(char **stringp, const char *delim);
2050
- if (CE->getNumArgs () < 2 )
2051
- return ;
2052
-
2053
2027
// Sanity: does the search string parameter match the return type?
2054
2028
const Expr *SearchStrPtr = CE->getArg (0 );
2055
2029
QualType CharPtrTy = SearchStrPtr->getType ()->getPointeeType ();
@@ -2118,7 +2092,7 @@ void CStringChecker::evalStdCopyBackward(CheckerContext &C,
2118
2092
2119
2093
void CStringChecker::evalStdCopyCommon (CheckerContext &C,
2120
2094
const CallExpr *CE) const {
2121
- if (CE->getNumArgs () < 3 )
2095
+ if (! CE->getArg ( 2 )-> getType ()-> isPointerType () )
2122
2096
return ;
2123
2097
2124
2098
ProgramStateRef State = C.getState ();
@@ -2145,9 +2119,6 @@ void CStringChecker::evalStdCopyCommon(CheckerContext &C,
2145
2119
}
2146
2120
2147
2121
void CStringChecker::evalMemset (CheckerContext &C, const CallExpr *CE) const {
2148
- if (CE->getNumArgs () != 3 )
2149
- return ;
2150
-
2151
2122
CurrentFunctionDescription = " memory set function" ;
2152
2123
2153
2124
const Expr *Mem = CE->getArg (0 );
@@ -2196,9 +2167,6 @@ void CStringChecker::evalMemset(CheckerContext &C, const CallExpr *CE) const {
2196
2167
}
2197
2168
2198
2169
void CStringChecker::evalBzero (CheckerContext &C, const CallExpr *CE) const {
2199
- if (CE->getNumArgs () != 2 )
2200
- return ;
2201
-
2202
2170
CurrentFunctionDescription = " memory clearance function" ;
2203
2171
2204
2172
const Expr *Mem = CE->getArg (0 );
@@ -2241,110 +2209,53 @@ void CStringChecker::evalBzero(CheckerContext &C, const CallExpr *CE) const {
2241
2209
C.addTransition (State);
2242
2210
}
2243
2211
2244
- static bool isCPPStdLibraryFunction (const FunctionDecl *FD, StringRef Name) {
2245
- IdentifierInfo *II = FD->getIdentifier ();
2246
- if (!II)
2247
- return false ;
2248
-
2249
- if (!AnalysisDeclContext::isInStdNamespace (FD))
2250
- return false ;
2251
-
2252
- if (II->getName ().equals (Name))
2253
- return true ;
2254
-
2255
- return false ;
2256
- }
2257
2212
// ===----------------------------------------------------------------------===//
2258
2213
// The driver method, and other Checker callbacks.
2259
2214
// ===----------------------------------------------------------------------===//
2260
2215
2261
- static CStringChecker::FnCheck identifyCall (const CallExpr *CE,
2262
- CheckerContext &C) {
2263
- const FunctionDecl *FDecl = C.getCalleeDecl (CE);
2264
- if (!FDecl)
2216
+ CStringChecker::FnCheck CStringChecker::identifyCall (const CallEvent &Call,
2217
+ CheckerContext &C) const {
2218
+ const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr ());
2219
+ if (!CE)
2220
+ return nullptr ;
2221
+
2222
+ const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl ());
2223
+ if (!FD)
2265
2224
return nullptr ;
2266
2225
2226
+ if (Call.isCalled (StdCopy)) {
2227
+ return &CStringChecker::evalStdCopy;
2228
+ } else if (Call.isCalled (StdCopyBackward)) {
2229
+ return &CStringChecker::evalStdCopyBackward;
2230
+ }
2231
+
2267
2232
// Pro-actively check that argument types are safe to do arithmetic upon.
2268
2233
// We do not want to crash if someone accidentally passes a structure
2269
- // into, say, a C++ overload of any of these functions.
2270
- if (isCPPStdLibraryFunction (FDecl, " copy" )) {
2271
- if (CE->getNumArgs () < 3 || !CE->getArg (2 )->getType ()->isPointerType ())
2272
- return nullptr ;
2273
- return &CStringChecker::evalStdCopy;
2274
- } else if (isCPPStdLibraryFunction (FDecl, " copy_backward" )) {
2275
- if (CE->getNumArgs () < 3 || !CE->getArg (2 )->getType ()->isPointerType ())
2234
+ // into, say, a C++ overload of any of these functions. We could not check
2235
+ // that for std::copy because they may have arguments of other types.
2236
+ for (auto I : CE->arguments ()) {
2237
+ QualType T = I->getType ();
2238
+ if (!T->isIntegralOrEnumerationType () && !T->isPointerType ())
2276
2239
return nullptr ;
2277
- return &CStringChecker::evalStdCopyBackward;
2278
- } else {
2279
- // An umbrella check for all C library functions.
2280
- for (auto I: CE->arguments ()) {
2281
- QualType T = I->getType ();
2282
- if (!T->isIntegralOrEnumerationType () && !T->isPointerType ())
2283
- return nullptr ;
2284
- }
2285
2240
}
2286
2241
2287
- // FIXME: Poorly-factored string switches are slow.
2288
- if (C.isCLibraryFunction (FDecl, " memcpy" ))
2289
- return &CStringChecker::evalMemcpy;
2290
- else if (C.isCLibraryFunction (FDecl, " mempcpy" ))
2291
- return &CStringChecker::evalMempcpy;
2292
- else if (C.isCLibraryFunction (FDecl, " memcmp" ))
2293
- return &CStringChecker::evalMemcmp;
2294
- else if (C.isCLibraryFunction (FDecl, " memmove" ))
2295
- return &CStringChecker::evalMemmove;
2296
- else if (C.isCLibraryFunction (FDecl, " memset" ) ||
2297
- C.isCLibraryFunction (FDecl, " explicit_memset" ))
2298
- return &CStringChecker::evalMemset;
2299
- else if (C.isCLibraryFunction (FDecl, " strcpy" ))
2300
- return &CStringChecker::evalStrcpy;
2301
- else if (C.isCLibraryFunction (FDecl, " strncpy" ))
2302
- return &CStringChecker::evalStrncpy;
2303
- else if (C.isCLibraryFunction (FDecl, " stpcpy" ))
2304
- return &CStringChecker::evalStpcpy;
2305
- else if (C.isCLibraryFunction (FDecl, " strlcpy" ))
2306
- return &CStringChecker::evalStrlcpy;
2307
- else if (C.isCLibraryFunction (FDecl, " strcat" ))
2308
- return &CStringChecker::evalStrcat;
2309
- else if (C.isCLibraryFunction (FDecl, " strncat" ))
2310
- return &CStringChecker::evalStrncat;
2311
- else if (C.isCLibraryFunction (FDecl, " strlcat" ))
2312
- return &CStringChecker::evalStrlcat;
2313
- else if (C.isCLibraryFunction (FDecl, " strlen" ))
2314
- return &CStringChecker::evalstrLength;
2315
- else if (C.isCLibraryFunction (FDecl, " strnlen" ))
2316
- return &CStringChecker::evalstrnLength;
2317
- else if (C.isCLibraryFunction (FDecl, " strcmp" ))
2318
- return &CStringChecker::evalStrcmp;
2319
- else if (C.isCLibraryFunction (FDecl, " strncmp" ))
2320
- return &CStringChecker::evalStrncmp;
2321
- else if (C.isCLibraryFunction (FDecl, " strcasecmp" ))
2322
- return &CStringChecker::evalStrcasecmp;
2323
- else if (C.isCLibraryFunction (FDecl, " strncasecmp" ))
2324
- return &CStringChecker::evalStrncasecmp;
2325
- else if (C.isCLibraryFunction (FDecl, " strsep" ))
2326
- return &CStringChecker::evalStrsep;
2327
- else if (C.isCLibraryFunction (FDecl, " bcopy" ))
2328
- return &CStringChecker::evalBcopy;
2329
- else if (C.isCLibraryFunction (FDecl, " bcmp" ))
2330
- return &CStringChecker::evalMemcmp;
2331
- else if (C.isCLibraryFunction (FDecl, " bzero" ) ||
2332
- C.isCLibraryFunction (FDecl, " explicit_bzero" ))
2333
- return &CStringChecker::evalBzero;
2242
+ const FnCheck *Callback = Callbacks.lookup (Call);
2243
+ if (Callback)
2244
+ return *Callback;
2334
2245
2335
2246
return nullptr ;
2336
2247
}
2337
2248
2338
2249
bool CStringChecker::evalCall (const CallEvent &Call, CheckerContext &C) const {
2339
- const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr ());
2340
- FnCheck evalFunction = identifyCall (CE, C);
2250
+ FnCheck Callback = identifyCall (Call, C);
2341
2251
2342
2252
// If the callee isn't a string function, let another checker handle it.
2343
- if (!evalFunction )
2253
+ if (!Callback )
2344
2254
return false ;
2345
2255
2346
2256
// Check and evaluate the call.
2347
- (this ->*evalFunction)(C, CE);
2257
+ const auto *CE = cast<CallExpr>(Call.getOriginExpr ());
2258
+ (this ->*Callback)(C, CE);
2348
2259
2349
2260
// If the evaluate call resulted in no change, chain to the next eval call
2350
2261
// handler.
0 commit comments