Skip to content

[clang] Fix FP -Wformat in functions with 2+ attribute((format)) #129954

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 6, 2025

Conversation

apple-fcloutier
Copy link
Contributor

When defining functions with two or more format attributes, if the format strings don't have the same format family, there is a false positive warning that the incorrect kind of format string is being passed at forwarded format string call sites.

This happens because we check that the format string family of each format attribute is compatible before we check that we're using the associated format parameter. The fix is to move the check down one scope, after we've established that we are checking the right parameter.

Tests are updated to include a true negative and a true positive of this situation.

When defining functions with two or more format attributes, if the
format strings don't have the same format family, there is a false
positive warning that the incorrect kind of format string is being
passed at forwarded format string call sites.
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Mar 5, 2025
@apple-fcloutier apple-fcloutier requested a review from bgra8 March 5, 2025 23:05
@llvmbot
Copy link
Member

llvmbot commented Mar 5, 2025

@llvm/pr-subscribers-clang

Author: None (apple-fcloutier)

Changes

When defining functions with two or more format attributes, if the format strings don't have the same format family, there is a false positive warning that the incorrect kind of format string is being passed at forwarded format string call sites.

This happens because we check that the format string family of each format attribute is compatible before we check that we're using the associated format parameter. The fix is to move the check down one scope, after we've established that we are checking the right parameter.

Tests are updated to include a true negative and a true positive of this situation.


Full diff: https://github.com/llvm/llvm-project/pull/129954.diff

2 Files Affected:

  • (modified) clang/lib/Sema/SemaChecking.cpp (+12-11)
  • (modified) clang/test/Sema/format-strings.c (+20)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index f9926c6b4adab..9cac9cf5c4df7 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -6149,18 +6149,19 @@ static StringLiteralCheckType checkFormatStringExpr(
             if (!Sema::getFormatStringInfo(D, PVFormat->getFormatIdx(),
                                            PVFormat->getFirstArg(), &CallerFSI))
               continue;
-            // We also check if the formats are compatible.
-            // We can't pass a 'scanf' string to a 'printf' function.
-            if (Type != S.GetFormatStringType(PVFormat)) {
-              S.Diag(Args[format_idx]->getBeginLoc(),
-                     diag::warn_format_string_type_incompatible)
-                  << PVFormat->getType()->getName()
-                  << S.GetFormatStringTypeName(Type);
-              if (!InFunctionCall) {
-                S.Diag(E->getBeginLoc(), diag::note_format_string_defined);
+            if (PV->getFunctionScopeIndex() == CallerFSI.FormatIdx) {
+              // We also check if the formats are compatible.
+              // We can't pass a 'scanf' string to a 'printf' function.
+              if (Type != S.GetFormatStringType(PVFormat)) {
+                S.Diag(Args[format_idx]->getBeginLoc(),
+                       diag::warn_format_string_type_incompatible)
+                    << PVFormat->getType()->getName()
+                    << S.GetFormatStringTypeName(Type);
+                if (!InFunctionCall) {
+                  S.Diag(E->getBeginLoc(), diag::note_format_string_defined);
+                }
+                return SLCT_UncheckedLiteral;
               }
-              return SLCT_UncheckedLiteral;
-            } else if (PV->getFunctionScopeIndex() == CallerFSI.FormatIdx) {
               // Lastly, check that argument passing kinds transition in a
               // way that makes sense:
               // from a caller with FAPK_VAList, allow FAPK_VAList
diff --git a/clang/test/Sema/format-strings.c b/clang/test/Sema/format-strings.c
index efd88d5c18e66..af30ad5d15fe2 100644
--- a/clang/test/Sema/format-strings.c
+++ b/clang/test/Sema/format-strings.c
@@ -496,6 +496,26 @@ void rdar8332221(va_list ap, int *x, long *y) {
   rdar8332221_vprintf_scanf("%", ap, "%d", x); // expected-warning{{incomplete format specifier}}
 }
 
+void rdar8332221_vprintf_scanf(const char *p, va_list ap, const char *s, ...) {
+  vprintf(p, ap);
+
+  va_list vs;
+  va_start(vs, s);
+  vscanf(s, vs);
+  va_end(vs);
+}
+
+__attribute__((__format__(__printf__, 1, 0)))
+__attribute__((__format__(__scanf__, 3, 4)))
+void vprintf_scanf_bad(const char *p, va_list ap, const char *s, ...) {
+  vscanf(p, ap); // expected-warning{{passing 'printf' format string where 'scanf' format string is expected}}
+
+  va_list vs;
+  va_start(vs, s);
+  vprintf(s, vs); // expected-warning{{passing 'scanf' format string where 'printf' format string is expected}}
+  va_end(vs);
+}
+
 // PR8641
 void pr8641(void) {
   printf("%#x\n", 10);

Copy link
Contributor

@bgra8 bgra8 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully tested this locally! Thanks for the fix!

@hnrklssn hnrklssn merged commit c628e8e into llvm:main Mar 6, 2025
14 checks passed
@hnrklssn hnrklssn deleted the apple-fcloutier/146330169 branch March 6, 2025 17:12
@apple-fcloutier apple-fcloutier restored the apple-fcloutier/146330169 branch March 10, 2025 20:37
jph-13 pushed a commit to jph-13/llvm-project that referenced this pull request Mar 21, 2025
…m#129954)

When defining functions with two or more format attributes, if the
format strings don't have the same format family, there is a false
positive warning that the incorrect kind of format string is being
passed at forwarded format string call sites.

This happens because we check that the format string family of each
format attribute is compatible before we check that we're using the
associated format parameter. The fix is to move the check down one
scope, after we've established that we are checking the right parameter.

Tests are updated to include a true negative and a true positive of this
situation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants