[PATCH] D112569: -Wformat-nonliteral should not trigger for format strings passed to blocks with __attribute__((format))

FĂ©lix Cloutier via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Tue Oct 26 12:14:18 PDT 2021


fcloutier created this revision.
fcloutier added reviewers: doug.gregor, dcoughlin, rsmith.
fcloutier added a project: clang.
fcloutier requested review of this revision.
Herald added a subscriber: cfe-commits.

The checker that implements `-Wformat-nonliteral` does not understand `__attribute__((format))` on blocks in the same way that it understands it on functions. This works just fine (assuming `#define __printflike(A, B) __attribute__((format(printf, A, B)))`):

  void printfblock(const char *fmt, ...) __printflike(1, 2) {
  	va_list ap;
  	va_start(ap, fmt);
  	vprintf(fmt, ap);
  	va_end(ap);
  }
  
  void foo(void) {
  	printfblock("%s %i\n", "hello", 1);
  }

However, this incorrectly triggers `-Wformat-nonliteral`:

  void foo(void) {
  	void (^printfblock)(const char *fmt, ...) __printflike(1, 2) = ^(const char *fmt, ...) __printflike(1, 2) {
  		va_list ap;
  		va_start(ap, fmt);
  		vprintf(fmt, ap); // warning: format string is not a string literal [-Wformat-nonliteral]
  		va_end(ap);
  	};
  	
  	printfblock("%s %i\n", "hello", 1);
  }

This patch updates `checkFormatStringExpr` so that it can look through `BlockDecl`s and find out which parameter is identified as a format string.

rdar://84603673


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D112569

Files:
  clang/lib/Sema/SemaChecking.cpp
  clang/test/Sema/format-strings.c


Index: clang/test/Sema/format-strings.c
===================================================================
--- clang/test/Sema/format-strings.c
+++ clang/test/Sema/format-strings.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -isystem %S/Inputs %s
-// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -isystem %S/Inputs -fno-signed-char %s
+// RUN: %clang_cc1 -fblocks -fsyntax-only -verify -Wformat-nonliteral -isystem %S/Inputs %s
+// RUN: %clang_cc1 -fblocks -fsyntax-only -verify -Wformat-nonliteral -isystem %S/Inputs -fno-signed-char %s
 
 #include <stdarg.h>
 #include <stddef.h>
@@ -714,3 +714,16 @@
 void test_printf_opaque_ptr(void *op) {
   printf("%s", op); // expected-warning{{format specifies type 'char *' but the argument has type 'void *'}}
 }
+
+void test_block() {
+  void __attribute__((__format__(__printf__, 1, 2))) (^printf_block)(const char *, ...) =
+      ^(const char *fmt, ...) __attribute__((__format__(__printf__, 1, 2))) {
+    va_list ap;
+    va_start(ap, fmt);
+    vprintf(fmt, ap);
+    va_end(ap);
+  };
+
+  printf_block("%s string %i\n", "aaa", 123);
+  printf_block("%s string\n", 123); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}
+}
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -7780,13 +7780,16 @@
       // }
       if (HasVAListArg) {
         if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(VD)) {
-          if (const NamedDecl *ND = dyn_cast<NamedDecl>(PV->getDeclContext())) {
-            int PVIndex = PV->getFunctionScopeIndex() + 1;
-            for (const auto *PVFormat : ND->specific_attrs<FormatAttr>()) {
+          if (const Decl *D = dyn_cast<Decl>(PV->getDeclContext())) {
+            int PVIndex = 1;
+            if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
+              PVIndex += PV->getFunctionScopeIndex();
               // adjust for implicit parameter
               if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND))
                 if (MD->isInstance())
                   ++PVIndex;
+            }
+            for (const auto *PVFormat : D->specific_attrs<FormatAttr>()) {
               // We also check if the formats are compatible.
               // We can't pass a 'scanf' string to a 'printf' function.
               if (PVIndex == PVFormat->getFormatIdx() &&


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D112569.382419.patch
Type: text/x-patch
Size: 2484 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20211026/0d8eab7e/attachment.bin>


More information about the cfe-commits mailing list