Index: clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def =================================================================== --- clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def +++ clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def @@ -20,6 +20,7 @@ UNSAFE_GADGET(Increment) UNSAFE_GADGET(Decrement) +UNSAFE_GADGET(ArraySubscript) #undef SAFE_GADGET #undef UNSAFE_GADGET Index: clang/lib/Analysis/UnsafeBufferUsage.cpp =================================================================== --- clang/lib/Analysis/UnsafeBufferUsage.cpp +++ clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -149,6 +149,31 @@ const Stmt *getBaseStmt() const override { return Op; } }; + +/// Array subscript expressions on raw pointers as if they're arrays. Unsafe as +/// it doesn't have any bounds checks for the array. +class ArraySubscriptGadget : public UnsafeGadget { + const ArraySubscriptExpr *ASE; + +public: + ArraySubscriptGadget(const MatchFinder::MatchResult &Result) + : UnsafeGadget(Kind::ArraySubscript), + ASE(Result.Nodes.getNodeAs("arraySubscr")) {} + + static bool classof(const Gadget *G) { + return G->getKind() == Kind::ArraySubscript; + } + + static Matcher matcher() { + // FIXME: What if the index is integer literal 0? Should this be + // a safe gadget in this case? + return stmt( + arraySubscriptExpr(hasBase(ignoringParenImpCasts(hasPointerType()))) + .bind("arraySubscr")); + } + + const Stmt *getBaseStmt() const override { return ASE; } +}; } // namespace // Scan the function and return a list of gadgets found with provided kits. Index: clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp =================================================================== --- clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp +++ clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp @@ -6,3 +6,57 @@ --p; // expected-warning{{unchecked operation on raw buffer in expression}} p--; // expected-warning{{unchecked operation on raw buffer in expression}} } + +void foo(...); + +void * bar(void); +char * baz(void); + +void testArraySubscripts(int *p, int **pp) { + foo(p[0], // expected-warning{{unchecked operation on raw buffer in expression}} + pp[0][0], // expected-warning2{{unchecked operation on raw buffer in expression}} + 0[0[pp]], // expected-warning2{{unchecked operation on raw buffer in expression}} + 0[pp][0] // expected-warning2{{unchecked operation on raw buffer in expression}} + ); + + if (p[3]) { // expected-warning{{unchecked operation on raw buffer in expression}} + void * q = p; + + foo(((int*)q)[10]); // expected-warning{{unchecked operation on raw buffer in expression}} + } + + foo(((int*)bar())[3], // expected-warning{{unchecked operation on raw buffer in expression}} + 3[(int*)bar()], // expected-warning{{unchecked operation on raw buffer in expression}} + baz()[3], // expected-warning{{unchecked operation on raw buffer in expression}} + 3[baz()] // expected-warning{{unchecked operation on raw buffer in expression}} + ); + + int a[10], b[10][10]; + + // not to warn subscripts on arrays + foo(a[0], a[1], + 0[a], 1[a], + b[3][4], + 4[b][3], + 4[3[b]]); +} + +void testArraySubscriptsWithAuto(int *p, int **pp) { + int a[10]; + + auto ap1 = a; + + foo(ap1[0]); // expected-warning{{unchecked operation on raw buffer in expression}} + + auto ap2 = p; + + foo(ap2[0]); // expected-warning{{unchecked operation on raw buffer in expression}} + + auto ap3 = pp; + + foo(pp[0][0]); // expected-warning2{{unchecked operation on raw buffer in expression}} + + auto ap4 = *pp; + + foo(ap4[0]); // expected-warning{{unchecked operation on raw buffer in expression}} +}