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
