================ @@ -1025,6 +1421,92 @@ class DataInvocationGadget : public WarningGadget { DeclUseList getClaimedVarUseSites() const override { return {}; } }; +class UnsafeLibcFunctionCallGadget : public WarningGadget { + const CallExpr *const Call; + constexpr static const char *const Tag = "UnsafeLibcFunctionCall"; + // Extra tags for additional information: + constexpr static const char *const UnsafeSprintfTag = + "UnsafeLibcFunctionCall_sprintf"; + constexpr static const char *const UnsafeSizedByTag = + "UnsafeLibcFunctionCall_sized_by"; + constexpr static const char *const UnsafeStringTag = + "UnsafeLibcFunctionCall_string"; + constexpr static const char *const UnsafeVaListTag = + "UnsafeLibcFunctionCall_va_list"; + + enum UnsafeKind { + OTHERS = 0, // no specific information, the callee function is unsafe + SPRINTF = 1, // never call `-sprintf`s, call `-snprintf`s instead. + SIZED_BY = 2, // a pair of function arguments have "__sized_by" relation but + // they do not conform to safe patterns + STRING = 3, // an argument is a pointer-to-char-as-string but does not + // guarantee null-termination + VA_LIST = 4, // one of the `-printf`s function that take va_list, which is + // considered unsafe as it is not compile-time check + } WarnedFunKind = OTHERS; + +public: + UnsafeLibcFunctionCallGadget(const MatchFinder::MatchResult &Result) + : WarningGadget(Kind::UnsafeLibcFunctionCall), + Call(Result.Nodes.getNodeAs<CallExpr>(Tag)) { + if (Result.Nodes.getNodeAs<CallExpr>(UnsafeSprintfTag)) + WarnedFunKind = SPRINTF; + else if (Result.Nodes.getNodeAs<CallExpr>(UnsafeStringTag)) + WarnedFunKind = STRING; + else if (Result.Nodes.getNodeAs<CallExpr>(UnsafeSizedByTag)) + WarnedFunKind = SIZED_BY; + else if (Result.Nodes.getNodeAs<CallExpr>(UnsafeVaListTag)) + WarnedFunKind = VA_LIST; + } + + static Matcher matcher() { + return stmt( + stmt( + anyOf( + // Match a call to a predefined unsafe libc function (unless the + // call has a sole string literal argument): + callExpr(callee(functionDecl( + libc_func_matchers::isPredefinedUnsafeLibcFunc())), + unless(allOf(hasArgument(0, expr(stringLiteral())), + hasNumArgs(1)))), + // Match a call to one of the `v*printf` functions taking + // va-list, which cannot be checked at compile-time: + callExpr(callee(functionDecl( + libc_func_matchers::isUnsafeVaListPrintfFunc()))) + .bind(UnsafeVaListTag), ---------------- haoNoQ wrote:
It doesn't look like you care which node carries the tag, only that the tag exists in the match result, right? So if you attach the `.bind()` to `functionDecl()` instead, would it help you simplify the code like this?: ``` callExpr(callee(anyOf( functionDecl(...), functionDecl(...).bind(UnsafeVaListTag), ... ))) ``` https://github.com/llvm/llvm-project/pull/101583 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits