Author: shreya-jain
Date: 2026-10-09T11:12:09+02:00
New Revision: 1fcb5a0dff28c54dfc9f0904210da6a43e89222e

URL: 
https://github.com/llvm/llvm-project/commit/1fcb5a0dff28c54dfc9f0904210da6a43e89222e
DIFF: 
https://github.com/llvm/llvm-project/commit/1fcb5a0dff28c54dfc9f0904210da6a43e89222e.diff

LOG:  [clang][SafeBuffers] Add -Wunsafe-buffer-usage-main-argv to allow 
ignoring main() argument warnings (#229871)

Introduce a new sub-flag, `-Wunsafe-buffer-usage-main-argv` (grouped
under -Wunsafe-buffer-usage), which specifically controls warnings
related to buffer operations on parameters of the `main()` function.

Unsafe buffer operations on `argv `(such as `argv[1]` or pointer
arithmetic) occur commonly. Many codebases may want to adopt the strict
`-Wunsafe-buffer-usage` without addressing potential noise from main's
arguments. This new flag allows developers to pass
`-Wno-unsafe-buffer-usage-main-argv` to explicitly suppress warnings on
`argc`/`argv`.

Added: 
    clang/test/SemaCXX/warn-unsafe-buffer-usage-main-argv.cpp

Modified: 
    clang/docs/ReleaseNotes.md
    clang/docs/SafeBuffers.md
    clang/include/clang/Basic/DiagnosticGroups.td
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/Sema/AnalysisBasedWarnings.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 2ea67cbd78bcce..32116077622b58 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -608,6 +608,10 @@ features cannot lower the translation-unit ABI level;
  
 - Clang now diagnoses arrays whose size is deduced from an initializer list 
when they exceed the maximum object size
 
+- Added `-Wunsafe-buffer-usage-main-argv` as a diagnostic group under
+  `-Wunsafe-buffer-usage` to control warnings on `main`'s `argv` parameter,
+  allowing users to suppress them with `-Wno-unsafe-buffer-usage-main-argv`.
+
 ### Improvements to Clang's time-trace
 
 ### Improvements to Coverage Mapping

diff  --git a/clang/docs/SafeBuffers.md b/clang/docs/SafeBuffers.md
index 4cd98fcbda1333..8e41d1c6af591a 100644
--- a/clang/docs/SafeBuffers.md
+++ b/clang/docs/SafeBuffers.md
@@ -353,6 +353,11 @@ There are a few natural reasons to use this pragma:
   never be converted to C++) or with the code that simply haven't been 
converted
   yet.
 
+- In `main(int argc, char **argv)`, where the function signature is fixed by 
the
+  language standard and `argv` cannot be changed to a `std::span`. Warnings on
+  `main`'s `argv` parameter can also be selectively suppressed via the
+  `-Wno-unsafe-buffer-usage-main-argv` compiler flag.
+
 Interoperation with unsafe code may require a lot of suppressions.
 You are encouraged to introduce "unsafe wrapper functions" for various unsafe
 operations that you need to perform regularly.

diff  --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index 1da7698944b24b..7779a6989cb7a9 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1996,7 +1996,8 @@ def UnsafeBufferUsageInUniquePtrArrayAccess : 
DiagGroup<"unsafe-buffer-usage-in-
 def UnsafeBufferUsageInStaticSizedArray : 
DiagGroup<"unsafe-buffer-usage-in-static-sized-array">;
 def UnsafeBufferUsageInFormatAttrCall : 
DiagGroup<"unsafe-buffer-usage-in-format-attr-call">;
 def UnsafeBufferUsageInStringView : 
DiagGroup<"unsafe-buffer-usage-in-string-view">;
-def UnsafeBufferUsage : DiagGroup<"unsafe-buffer-usage", 
[UnsafeBufferUsageInContainer, UnsafeBufferUsageInLibcCall, 
UnsafeBufferUsageInUniquePtrArrayAccess, UnsafeBufferUsageInStaticSizedArray, 
UnsafeBufferUsageInFormatAttrCall, UnsafeBufferUsageInStringView]>;
+def UnsafeBufferUsageMainArgv : DiagGroup<"unsafe-buffer-usage-main-argv">;
+def UnsafeBufferUsage : DiagGroup<"unsafe-buffer-usage", 
[UnsafeBufferUsageInContainer, UnsafeBufferUsageInLibcCall, 
UnsafeBufferUsageInUniquePtrArrayAccess, UnsafeBufferUsageInStaticSizedArray, 
UnsafeBufferUsageInFormatAttrCall, UnsafeBufferUsageInStringView, 
UnsafeBufferUsageMainArgv]>;
 
 // Warnings and notes InstallAPI verification.
 def InstallAPIViolation : DiagGroup<"installapi-violation">;

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 79f10b8240aa47..f40b8976373410 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13953,15 +13953,21 @@ def err_cast_from_randomized_struct : Error<
   "casting from randomized structure pointer type %0 to %1">;
 
 // Unsafe buffer usage diagnostics.
-def warn_unsafe_buffer_variable : Warning<
+defvar UnsafeBufferVariableMsg =
   "%0 is an %select{unsafe pointer used for buffer access|unsafe buffer that "
-  "does not perform bounds checks}1">,
-  InGroup<UnsafeBufferUsage>, DefaultIgnore;
-def warn_unsafe_buffer_operation : Warning<
+  "does not perform bounds checks}1";
+defvar UnsafeBufferOperationMsg =
   "%select{unsafe pointer operation|unsafe pointer arithmetic|"
-  "unsafe buffer access|function introduces unsafe buffer manipulation|unsafe 
invocation of %1|"
-  "field %1 prone to unsafe buffer manipulation}0">,
+  "unsafe buffer access|function introduces unsafe buffer manipulation|"
+  "unsafe invocation of %1|field %1 prone to unsafe buffer manipulation}0";
+def warn_unsafe_buffer_variable : Warning<UnsafeBufferVariableMsg>,
+  InGroup<UnsafeBufferUsage>, DefaultIgnore;
+def warn_unsafe_buffer_variable_main_argv : Warning<UnsafeBufferVariableMsg>,
+  InGroup<UnsafeBufferUsageMainArgv>, DefaultIgnore;
+def warn_unsafe_buffer_operation : Warning<UnsafeBufferOperationMsg>,
   InGroup<UnsafeBufferUsage>, DefaultIgnore;
+def warn_unsafe_buffer_operation_main_argv : Warning<UnsafeBufferOperationMsg>,
+  InGroup<UnsafeBufferUsageMainArgv>, DefaultIgnore;
 def warn_unsafe_buffer_libc_call : Warning<
   "function %0 is unsafe">,
   InGroup<UnsafeBufferUsageInLibcCall>, DefaultIgnore;

diff  --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp 
b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 1ac79e3af44739..21af6ed5527ffc 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2421,6 +2421,22 @@ class ConsumedWarningsHandler : public 
ConsumedWarningsHandlerBase {
 
//===----------------------------------------------------------------------===//
 
 namespace {
+
+bool isMainParam(const Decl *D) {
+  if (const auto *PVD = dyn_cast_or_null<ParmVarDecl>(D))
+    if (const auto *FD = dyn_cast<FunctionDecl>(PVD->getDeclContext()))
+      return FD->isMain();
+  return false;
+}
+
+bool refersMainParam(const Expr *E) {
+  if (!E)
+    return false;
+  if (const auto *DRE = 
dyn_cast_or_null<DeclRefExpr>(E->IgnoreParenImpCasts()))
+    return isMainParam(DRE->getDecl());
+  return false;
+}
+
 class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
   Sema &S;
   bool SuggestSuggestions;  // Recommend -fsafe-buffer-usage-suggestions?
@@ -2470,20 +2486,24 @@ class UnsafeBufferUsageReporter : public 
UnsafeBufferUsageHandler {
     SourceRange Range;
     unsigned MsgParam = 0;
     NamedDecl *D = nullptr;
+    const Expr *BufferOperand = nullptr;
     if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Operation)) {
-      Loc = ASE->getBase()->getExprLoc();
-      Range = ASE->getBase()->getSourceRange();
+      BufferOperand = ASE->getBase();
+      Loc = BufferOperand->getExprLoc();
+      Range = BufferOperand->getSourceRange();
       MsgParam = 2;
     } else if (const auto *BO = dyn_cast<BinaryOperator>(Operation)) {
       BinaryOperator::Opcode Op = BO->getOpcode();
       if (Op == BO_Add || Op == BO_AddAssign || Op == BO_Sub ||
           Op == BO_SubAssign) {
         if (BO->getRHS()->getType()->isIntegerType()) {
-          Loc = BO->getLHS()->getExprLoc();
-          Range = BO->getLHS()->getSourceRange();
+          BufferOperand = BO->getLHS();
+          Loc = BufferOperand->getExprLoc();
+          Range = BufferOperand->getSourceRange();
         } else {
-          Loc = BO->getRHS()->getExprLoc();
-          Range = BO->getRHS()->getSourceRange();
+          BufferOperand = BO->getRHS();
+          Loc = BufferOperand->getExprLoc();
+          Range = BufferOperand->getSourceRange();
         }
         MsgParam = 1;
       }
@@ -2491,8 +2511,9 @@ class UnsafeBufferUsageReporter : public 
UnsafeBufferUsageHandler {
       UnaryOperator::Opcode Op = UO->getOpcode();
       if (Op == UO_PreInc || Op == UO_PreDec || Op == UO_PostInc ||
           Op == UO_PostDec) {
-        Loc = UO->getSubExpr()->getExprLoc();
-        Range = UO->getSubExpr()->getSourceRange();
+        BufferOperand = UO->getSubExpr();
+        Loc = BufferOperand->getExprLoc();
+        Range = BufferOperand->getSourceRange();
         MsgParam = 1;
       }
     } else {
@@ -2550,12 +2571,14 @@ class UnsafeBufferUsageReporter : public 
UnsafeBufferUsageHandler {
              "Variables blamed for unsafe buffer usage without suggestions!");
       S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam << Range;
     } else {
-      if (D) {
-        S.Diag(Loc, diag::warn_unsafe_buffer_operation)
-            << MsgParam << D << Range;
-      } else {
-        S.Diag(Loc, diag::warn_unsafe_buffer_operation) << MsgParam << Range;
-      }
+      unsigned DiagID = refersMainParam(BufferOperand)
+                            ? diag::warn_unsafe_buffer_operation_main_argv
+                            : diag::warn_unsafe_buffer_operation;
+
+      if (D)
+        S.Diag(Loc, DiagID) << MsgParam << D << Range;
+      else
+        S.Diag(Loc, DiagID) << MsgParam << Range;
       if (SuggestSuggestions) {
         S.Diag(Loc, diag::note_safe_buffer_usage_suggestions_disabled);
       }
@@ -2648,7 +2671,12 @@ class UnsafeBufferUsageReporter : public 
UnsafeBufferUsageHandler {
                                  const FixitStrategy &VarTargetTypes) override 
{
     assert(!SuggestSuggestions &&
            "Unsafe buffer usage fixits displayed without suggestions!");
-    S.Diag(Variable->getLocation(), diag::warn_unsafe_buffer_variable)
+
+    unsigned DiagID = isMainParam(Variable)
+                          ? diag::warn_unsafe_buffer_variable_main_argv
+                          : diag::warn_unsafe_buffer_variable;
+
+    S.Diag(Variable->getLocation(), DiagID)
         << Variable << (Variable->getType()->isPointerType() ? 0 : 1)
         << Variable->getSourceRange();
     if (!Fixes.empty()) {

diff  --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-main-argv.cpp 
b/clang/test/SemaCXX/warn-unsafe-buffer-usage-main-argv.cpp
new file mode 100644
index 00000000000000..fc4297b33033fe
--- /dev/null
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-main-argv.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -Wunsafe-buffer-usage -fsafe-buffer-usage-suggestions 
-verify=expected,both %s
+// RUN: %clang_cc1 -Wunsafe-buffer-usage -Wno-unsafe-buffer-usage-main-argv 
-fsafe-buffer-usage-suggestions -verify=both %s
+
+int main(int argc, char **argv) {
+  // expected-warning@+1{{unsafe buffer access}}
+  char c = argv[1][0];
+
+  // expected-warning@+1{{unsafe pointer arithmetic}}
+  char **ptr1 = argv + 1;
+  // expected-warning@+1{{unsafe pointer arithmetic}}
+  argv++;
+  // expected-warning@+1{{unsafe pointer arithmetic}}
+  argv += 1;
+
+  int *p = nullptr;
+  // both-warning@+1{{unsafe buffer access}}
+  return p[5];
+}
+
+int other_func(int argc, char **argv) {
+  // both-warning@+1{{unsafe buffer access}}
+  return argv[1][0];
+}


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to