]> granicus.if.org Git - clang/commitdiff
-Wformat: better handling of qualifiers on pointer arguments
authorHans Wennborg <hans@hanshq.net>
Tue, 31 Jul 2012 16:37:47 +0000 (16:37 +0000)
committerHans Wennborg <hans@hanshq.net>
Tue, 31 Jul 2012 16:37:47 +0000 (16:37 +0000)
Warn about using pointers to const-qualified types as arguments to
scanf. Ignore the volatile qualifier when checking if types match.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@161052 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/FormatString.cpp
lib/Analysis/ScanfFormatString.cpp
test/Sema/format-strings-scanf.c
test/Sema/format-strings.c

index a68b9bb3240f21889c37c8014af665edbf21bfa8..f03a84fb523e68aec0abb15eae07c8fa3186d1d3 100644 (file)
@@ -262,6 +262,13 @@ bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const {
         argTy = ETy->getDecl()->getIntegerType();
       argTy = C.getCanonicalType(argTy).getUnqualifiedType();
 
+      if (const PointerType *PTy = argTy->getAs<PointerType>()) {
+        // Strip volatile qualifier from pointee type.
+        QualType Pointee = PTy->getPointeeType();
+        Pointee.removeLocalVolatile();
+        argTy = C.getPointerType(Pointee);
+      }
+
       if (T == argTy)
         return true;
       // Check for "compatible types".
index 3c848f1f093d53de893ec12ae6d1c895ef6a1c13..1bbd5f2d296ea4f5c93e08fad8b1d464557c4d1f 100644 (file)
@@ -453,6 +453,15 @@ bool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H,
 }
 
 bool ScanfArgTypeResult::matchesType(ASTContext& C, QualType argTy) const {
+  // It has to be a pointer type.
+  const PointerType *PT = argTy->getAs<PointerType>();
+  if (!PT)
+    return false;
+
+  // We cannot write through a const qualified pointer.
+  if (PT->getPointeeType().isConstQualified())
+    return false;
+
   switch (K) {
     case InvalidTy:
       llvm_unreachable("ArgTypeResult must be valid");
@@ -463,9 +472,6 @@ bool ScanfArgTypeResult::matchesType(ASTContext& C, QualType argTy) const {
     case WCStrTy:
       return ArgTypeResult(ArgTypeResult::WCStrTy).matchesType(C, argTy);
     case PtrToArgTypeResultTy: {
-      const PointerType *PT = argTy->getAs<PointerType>();
-      if (!PT)
-        return false;
       return A.matchesType(C, PT->getPointeeType());
     }
   }
index 2ce94840a6f12dc491490a27ce49599971e7b642..6f6cb10eb384e39e6269f9f90d57edc93e2050df 100644 (file)
@@ -126,3 +126,21 @@ void test_writeback(int *x) {
   scanf("%n", (void*)0); // expected-warning{{format specifies type 'int *' but the argument has type 'void *'}}
   scanf("%n %c", x, x); // expected-warning{{format specifies type 'char *' but the argument has type 'int *'}}
 }
+
+void test_qualifiers(const int *cip, volatile int* vip,
+                     const char *ccp, volatile char* vcp,
+                     const volatile int *cvip) {
+  scanf("%d", cip); // expected-warning{{format specifies type 'int *' but the argument has type 'const int *'}}
+  scanf("%n", cip); // expected-warning{{format specifies type 'int *' but the argument has type 'const int *'}}
+  scanf("%s", ccp); // expected-warning{{format specifies type 'char *' but the argument has type 'const char *'}}
+  scanf("%d", cvip); // expected-warning{{format specifies type 'int *' but the argument has type 'const volatile int *'}}
+
+  scanf("%d", vip); // No warning.
+  scanf("%n", vip); // No warning.
+  scanf("%c", vcp); // No warning.
+
+  typedef int* ip_t;
+  typedef const int* cip_t;
+  scanf("%d", (ip_t)0); // No warning.
+  scanf("%d", (cip_t)0); // expected-warning{{format specifies type 'int *' but the argument has type 'cip_t' (aka 'const int *')}}
+}
index d35125833c2b93de054dc8751adc86220bdb3b90..aff996fed3ee41438d218b821937a610bad98ae7 100644 (file)
@@ -555,3 +555,19 @@ void test14_zed(int *p) {
   test14_foo("%", "%d", p); // expected-warning{{incomplete format specifier}}
   test14_bar("%", "%d", p); // expected-warning{{incomplete format specifier}}
 }
+
+void test_qualifiers(volatile int *vip, const int *cip,
+                     const volatile int *cvip) {
+  printf("%n", cip); // expected-warning{{format specifies type 'int *' but the argument has type 'const int *'}}
+  printf("%n", cvip); // expected-warning{{format specifies type 'int *' but the argument has type 'const volatile int *'}}
+
+  printf("%n", vip); // No warning.
+  printf("%p", cip); // No warning.
+  printf("%p", cvip); // No warning.
+
+
+  typedef int* ip_t;
+  typedef const int* cip_t;
+  printf("%n", (ip_t)0); // No warning.
+  printf("%n", (cip_t)0); // expected-warning{{format specifies type 'int *' but the argument has type 'cip_t' (aka 'const int *')}}
+}