[clang] [-Wunsafe-buffer-usage] Warning Libc functions (PR #101583)

Ziqing Luo via cfe-commits cfe-commits at lists.llvm.org
Wed Aug 28 13:34:10 PDT 2024


================
@@ -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),
----------------
ziqingluo-90 wrote:

right, that's a good point!

https://github.com/llvm/llvm-project/pull/101583


More information about the cfe-commits mailing list