From 248229e475bb6620510f6262ebea78c372032ba5 Mon Sep 17 00:00:00 2001
From: Mehdi Amini <mehdi.amini@apple.com>
Date: Thu, 15 Dec 2016 18:54:00 +0000
Subject: [PATCH] Fix printf specifier handling: invalid specifier should not
 be marked as "consuming data arguments"

Reviewers: rsmith, bruno, dexonsmith

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D27796

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@289850 91177308-0d34-0410-b5e6-96231b3b80d8
---
 .../clang/Analysis/Analyses/FormatString.h    |  2 ++
 test/CodeGen/builtins.c                       | 28 +++++++++++++++++++
 test/Sema/format-strings.c                    |  8 +++---
 test/SemaObjC/format-strings-objc.m           |  2 +-
 4 files changed, 35 insertions(+), 5 deletions(-)

diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h
index 6813da98c63..8c531d638cc 100644
--- a/include/clang/Analysis/Analyses/FormatString.h
+++ b/include/clang/Analysis/Analyses/FormatString.h
@@ -211,6 +211,8 @@ public:
         return false;
       case PercentArg:
         return false;
+      case InvalidSpecifier:
+        return false;
       default:
         return true;
     }
diff --git a/test/CodeGen/builtins.c b/test/CodeGen/builtins.c
index a0f846b14f1..390c2e35bf9 100644
--- a/test/CodeGen/builtins.c
+++ b/test/CodeGen/builtins.c
@@ -538,6 +538,34 @@ void test_builtin_os_log_precision_width(void *buf, const char *data,
   __builtin_os_log_format(buf, "Hello %*.*s World", precision, width, data);
 }
 
+// CHECK-LABEL: define void @test_builtin_os_log_invalid
+// CHECK: (i8* [[BUF:%.*]], i32 [[DATA:%.*]])
+void test_builtin_os_log_invalid(void *buf, int data) {
+  volatile int len;
+  // CHECK: store i8* [[BUF]], i8** [[BUF_ADDR:%.*]], align 8
+  // CHECK: store i32 [[DATA]], i32* [[DATA_ADDR:%.*]]
+
+  // CHECK: store volatile i32 8,
+  len = __builtin_os_log_format_buffer_size("invalid specifier %: %d even a trailing one%", data);
+
+  // CHECK: [[BUF2:%.*]] = load i8*, i8** [[BUF_ADDR]]
+  // CHECK: [[SUMMARY:%.*]] = getelementptr i8, i8* [[BUF2]], i64 0
+  // CHECK: store i8 0, i8* [[SUMMARY]]
+  // CHECK: [[NUM_ARGS:%.*]] = getelementptr i8, i8* [[BUF2]], i64 1
+  // CHECK: store i8 1, i8* [[NUM_ARGS]]
+
+  // CHECK: [[ARG1_DESC:%.*]] = getelementptr i8, i8* [[BUF2]], i64 2
+  // CHECK: store i8 0, i8* [[ARG1_DESC]]
+  // CHECK: [[ARG1_SIZE:%.*]] = getelementptr i8, i8* [[BUF2]], i64 3
+  // CHECK: store i8 4, i8* [[ARG1_SIZE]]
+  // CHECK: [[ARG1:%.*]] = getelementptr i8, i8* [[BUF2]], i64 4
+  // CHECK: [[ARG1_INT:%.*]] = bitcast i8* [[ARG1]] to i32*
+  // CHECK: [[ARG1_VAL:%.*]] = load i32, i32* [[DATA_ADDR]]
+  // CHECK: store i32 [[ARG1_VAL]], i32* [[ARG1_INT]]
+
+  __builtin_os_log_format(buf, "invalid specifier %: %d even a trailing one%", data);
+}
+
 // CHECK-LABEL: define void @test_builtin_os_log_percent
 // CHECK: (i8* [[BUF:%.*]], i8* [[DATA1:%.*]], i8* [[DATA2:%.*]])
 // Check that the %% which does not consume any argument is correctly handled
diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c
index 5c332bd37a0..54651226adc 100644
--- a/test/Sema/format-strings.c
+++ b/test/Sema/format-strings.c
@@ -156,10 +156,10 @@ void check_writeback_specifier()
 
 void check_invalid_specifier(FILE* fp, char *buf)
 {
-  printf("%s%lb%d","unix",10,20); // expected-warning {{invalid conversion specifier 'b'}}
+  printf("%s%lb%d","unix",10,20); // expected-warning {{invalid conversion specifier 'b'}} expected-warning {{data argument not used by format string}}
   fprintf(fp,"%%%l"); // expected-warning {{incomplete format specifier}}
   sprintf(buf,"%%%%%ld%d%d", 1, 2, 3); // expected-warning{{format specifies type 'long' but the argument has type 'int'}}
-  snprintf(buf, 2, "%%%%%ld%;%d", 1, 2, 3); // expected-warning{{format specifies type 'long' but the argument has type 'int'}} expected-warning {{invalid conversion specifier ';'}}
+  snprintf(buf, 2, "%%%%%ld%;%d", 1, 2, 3); // expected-warning{{format specifies type 'long' but the argument has type 'int'}} expected-warning {{invalid conversion specifier ';'}} expected-warning {{data argument not used by format string}}
 }
 
 void check_null_char_string(char* b)
@@ -251,7 +251,7 @@ void test10(int x, float f, int i, long long lli) {
   printf("%**\n"); // expected-warning{{invalid conversion specifier '*'}}
   printf("%d%d\n", x); // expected-warning{{more '%' conversions than data arguments}}
   printf("%d\n", x, x); // expected-warning{{data argument not used by format string}}
-  printf("%W%d\n", x, x); // expected-warning{{invalid conversion specifier 'W'}}
+  printf("%W%d\n", x, x); // expected-warning{{invalid conversion specifier 'W'}}  expected-warning {{data argument not used by format string}}
   printf("%"); // expected-warning{{incomplete format specifier}}
   printf("%.d", x); // no-warning
   printf("%.", x);  // expected-warning{{incomplete format specifier}}
@@ -270,7 +270,7 @@ void test10(int x, float f, int i, long long lli) {
   printf("%.0Lf", (long double) 1.0); // no-warning
   printf("%c\n", "x"); // expected-warning{{format specifies type 'int' but the argument has type 'char *'}}
   printf("%c\n", 1.23); // expected-warning{{format specifies type 'int' but the argument has type 'double'}}
-  printf("Format %d, is %! %f", 1, 2, 4.4); // expected-warning{{invalid conversion specifier '!'}}
+  printf("Format %d, is %! %f", 1, 4.4); // expected-warning{{invalid conversion specifier '!'}}
 }
 
 typedef unsigned char uint8_t;
diff --git a/test/SemaObjC/format-strings-objc.m b/test/SemaObjC/format-strings-objc.m
index 9377a6c05c2..767d5ac6cd6 100644
--- a/test/SemaObjC/format-strings-objc.m
+++ b/test/SemaObjC/format-strings-objc.m
@@ -47,7 +47,7 @@ int printf(const char * restrict, ...) ;
 
 void check_nslog(unsigned k) {
   NSLog(@"%d%%", k); // no-warning
-  NSLog(@"%s%lb%d", "unix", 10,20); // expected-warning {{invalid conversion specifier 'b'}}
+  NSLog(@"%s%lb%d", "unix", 10, 20); // expected-warning {{invalid conversion specifier 'b'}} expected-warning {{data argument not used by format string}}
 }
 
 // Check type validation
-- 
GitLab