@@ -1103,16 +1103,20 @@ static bool areEqualIntegers(const Expr *E1, const Expr *E2, ASTContext &Ctx) {
1103
1103
// 4. `std::span<T>{a, n}`, where `a` is of an array-of-T with constant size
1104
1104
// `n`
1105
1105
// 5. `std::span<T>{any, 0}`
1106
- // 6. `std::span<T>{p, n}`, where `p` is a __counted_by(`n`)/__sized_by(`n`)
1107
- // pointer OR `std::span<char>{(char*)p, n}`, where `p` is a __sized_by(`n`)
1108
- // pointer.
1109
- // 7. `std::span<char>{p, strlen(p)}` or `std::span<wchar_t>{p, wcslen(p)}`
1110
- // 8. `std::span<T>{ (char *)f(args), args[N] * arg*[M]}`, where
1106
+ // 6. `std::span<char>{p, strlen(p)}` or `std::span<wchar_t>{p, wcslen(p)}`
1107
+ // 7. `std::span<T>{ (char *)f(args), args[N] * arg*[M]}`, where
1111
1108
// `f` is a function with attribute `alloc_size(N, M)`;
1112
1109
// `args` represents the list of arguments;
1113
1110
// `N, M` are parameter indexes to the allocating element number and size.
1114
1111
// Sometimes, there is only one parameter index representing the total
1115
1112
// size.
1113
+ // TO_UPSTREAM(BoundsSafetyInterop) ON
1114
+ // Interop Pattern:
1115
+ // `std::span<T>{p, n}`, where `p` is a __counted_by(`n`)/__sized_by(`n`)
1116
+ // pointer OR `std::span<char>{(char*)p, n}`, where `p` is a
1117
+ // __sized_by(`n`) pointer. (This pattern is not in upstream, so try it
1118
+ // last to avoid possible conflicts.)
1119
+ // // TO_UPSTREAM(BoundsSafetyInterop) OFF
1116
1120
AST_MATCHER (CXXConstructExpr, isSafeSpanTwoParamConstruct) {
1117
1121
assert (Node.getNumArgs () == 2 &&
1118
1122
" expecting a two-parameter std::span constructor" );
@@ -1184,6 +1188,52 @@ AST_MATCHER(CXXConstructExpr, isSafeSpanTwoParamConstruct) {
1184
1188
}
1185
1189
1186
1190
// Check form 6:
1191
+ if (const auto *Call = dyn_cast<CallExpr>(Arg1);
1192
+ Call && Call->getNumArgs () == 1 ) {
1193
+ if (const FunctionDecl *FD = Call->getDirectCallee ();
1194
+ FD && FD->getIdentifier ()) {
1195
+ StringRef FName = FD->getName ();
1196
+ const Expr *CallArg = Call->getArg (0 )->IgnoreParenImpCasts ();
1197
+
1198
+ // TODO: we can re-use `LibcFunNamePrefixSuffixParser` to support more
1199
+ // variants, e.g., `strlen_s`
1200
+ return (FName == " strlen" || FName == " wcslen" ) &&
1201
+ AreSameDRE (Arg0, CallArg);
1202
+ }
1203
+ }
1204
+
1205
+ // Check form 7:
1206
+ if (auto CCast = dyn_cast<CStyleCastExpr>(Arg0)) {
1207
+ if (!CCast->getType ()->isPointerType ())
1208
+ return false ;
1209
+
1210
+ QualType PteTy = CCast->getType ()->getPointeeType ();
1211
+
1212
+ if (!(PteTy->isConstantSizeType () && Ctx.getTypeSizeInChars (PteTy).isOne ()))
1213
+ return false ;
1214
+
1215
+ if (const auto *Call = dyn_cast<CallExpr>(CCast->getSubExpr ())) {
1216
+ if (const FunctionDecl *FD = Call->getDirectCallee ())
1217
+ if (auto *AllocAttr = FD->getAttr <AllocSizeAttr>()) {
1218
+ const Expr *EleSizeExpr =
1219
+ Call->getArg (AllocAttr->getElemSizeParam ().getASTIndex ());
1220
+ // NumElemIdx is invalid if AllocSizeAttr has 1 argument:
1221
+ ParamIdx NumElemIdx = AllocAttr->getNumElemsParam ();
1222
+
1223
+ if (!NumElemIdx.isValid ())
1224
+ return areEqualIntegers (Arg1, EleSizeExpr, Ctx);
1225
+
1226
+ const Expr *NumElesExpr = Call->getArg (NumElemIdx.getASTIndex ());
1227
+
1228
+ if (auto BO = dyn_cast<BinaryOperator>(Arg1))
1229
+ return areEqualIntegralBinaryOperators (BO, NumElesExpr, BO_Mul,
1230
+ EleSizeExpr, Ctx);
1231
+ }
1232
+ }
1233
+ }
1234
+
1235
+ /* TO_UPSTREAM(BoundsSafetyInterop) ON */
1236
+ // Check interop pattern:
1187
1237
bool isArg0CastToBytePtrType = false ;
1188
1238
1189
1239
if (auto *CE = dyn_cast<CastExpr>(Arg0)) {
@@ -1229,50 +1279,7 @@ AST_MATCHER(CXXConstructExpr, isSafeSpanTwoParamConstruct) {
1229
1279
/* DependentValues=*/ nullptr ,
1230
1280
Finder->getASTContext ());
1231
1281
}
1232
- // Check form 7:
1233
- if (const auto *Call = dyn_cast<CallExpr>(Arg1);
1234
- Call && Call->getNumArgs () == 1 ) {
1235
- if (const FunctionDecl *FD = Call->getDirectCallee ();
1236
- FD && FD->getIdentifier ()) {
1237
- StringRef FName = FD->getName ();
1238
- const Expr *CallArg = Call->getArg (0 )->IgnoreParenImpCasts ();
1239
-
1240
- // TODO: we can re-use `LibcFunNamePrefixSuffixParser` to support more
1241
- // variants, e.g., `strlen_s`
1242
- return (FName == " strlen" || FName == " wcslen" ) &&
1243
- AreSameDRE (Arg0, CallArg);
1244
- }
1245
- }
1246
-
1247
- // Check form 8:
1248
- if (auto CCast = dyn_cast<CStyleCastExpr>(Arg0)) {
1249
- if (!CCast->getType ()->isPointerType ())
1250
- return false ;
1251
-
1252
- QualType PteTy = CCast->getType ()->getPointeeType ();
1253
-
1254
- if (!(PteTy->isConstantSizeType () && Ctx.getTypeSizeInChars (PteTy).isOne ()))
1255
- return false ;
1256
-
1257
- if (const auto *Call = dyn_cast<CallExpr>(CCast->getSubExpr ())) {
1258
- if (const FunctionDecl *FD = Call->getDirectCallee ())
1259
- if (auto *AllocAttr = FD->getAttr <AllocSizeAttr>()) {
1260
- const Expr *EleSizeExpr =
1261
- Call->getArg (AllocAttr->getElemSizeParam ().getASTIndex ());
1262
- // NumElemIdx is invalid if AllocSizeAttr has 1 argument:
1263
- ParamIdx NumElemIdx = AllocAttr->getNumElemsParam ();
1264
-
1265
- if (!NumElemIdx.isValid ())
1266
- return areEqualIntegers (Arg1, EleSizeExpr, Ctx);
1267
-
1268
- const Expr *NumElesExpr = Call->getArg (NumElemIdx.getASTIndex ());
1269
-
1270
- if (auto BO = dyn_cast<BinaryOperator>(Arg1))
1271
- return areEqualIntegralBinaryOperators (BO, NumElesExpr, BO_Mul,
1272
- EleSizeExpr, Ctx);
1273
- }
1274
- }
1275
- }
1282
+ /* TO_UPSTREAM(BoundsSafetyInterop) OFF */
1276
1283
return false ;
1277
1284
}
1278
1285
0 commit comments