r336629 - Fix parsing of privacy annotations in os_log format strings.

Akira Hatanaka via cfe-commits cfe-commits at lists.llvm.org
Mon Jul 9 17:50:25 PDT 2018


Author: ahatanak
Date: Mon Jul  9 17:50:25 2018
New Revision: 336629

URL: http://llvm.org/viewvc/llvm-project?rev=336629&view=rev
Log:
Fix parsing of privacy annotations in os_log format strings.

Privacy annotations shouldn't have to appear in the first
comma-delimited string in order to be recognized. Also, they should be
ignored if they are preceded or followed by non-whitespace characters.

rdar://problem/40706280

Modified:
    cfe/trunk/lib/Analysis/PrintfFormatString.cpp
    cfe/trunk/test/CodeGen/builtins.c

Modified: cfe/trunk/lib/Analysis/PrintfFormatString.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/PrintfFormatString.cpp?rev=336629&r1=336628&r2=336629&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/PrintfFormatString.cpp (original)
+++ cfe/trunk/lib/Analysis/PrintfFormatString.cpp Mon Jul  9 17:50:25 2018
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Analysis/Analyses/FormatString.h"
+#include "clang/Analysis/Analyses/OSLog.h"
 #include "FormatStringParsing.h"
 #include "clang/Basic/TargetInfo.h"
 
@@ -119,36 +120,55 @@ static PrintfSpecifierResult ParsePrintf
     return true;
   }
 
-  const char *OSLogVisibilityFlagsStart = nullptr,
-             *OSLogVisibilityFlagsEnd = nullptr;
   if (*I == '{') {
-    OSLogVisibilityFlagsStart = I++;
-    // Find the end of the modifier.
-    while (I != E && *I != '}') {
-      I++;
-    }
-    if (I == E) {
-      if (Warn)
-        H.HandleIncompleteSpecifier(Start, E - Start);
-      return true;
-    }
-    assert(*I == '}');
-    OSLogVisibilityFlagsEnd = I++;
-
-    // Just see if 'private' or 'public' is the first word. os_log itself will
-    // do any further parsing.
-    const char *P = OSLogVisibilityFlagsStart + 1;
-    while (P < OSLogVisibilityFlagsEnd && isspace(*P))
-      P++;
-    const char *WordStart = P;
-    while (P < OSLogVisibilityFlagsEnd && (isalnum(*P) || *P == '_'))
-      P++;
-    const char *WordEnd = P;
-    StringRef Word(WordStart, WordEnd - WordStart);
-    if (Word == "private") {
-      FS.setIsPrivate(WordStart);
-    } else if (Word == "public") {
-      FS.setIsPublic(WordStart);
+    ++I;
+    unsigned char PrivacyFlags = 0;
+    StringRef MatchedStr;
+
+    do {
+      StringRef Str(I, E - I);
+      std::string Match = "^[\t\n\v\f\r ]*(private|public)[\t\n\v\f\r ]*(,|})";
+      llvm::Regex R(Match);
+      SmallVector<StringRef, 2> Matches;
+
+      if (R.match(Str, &Matches)) {
+        MatchedStr = Matches[1];
+        I += Matches[0].size();
+
+        // Set the privacy flag if there is a privacy annotation in the
+        // comma-delimited segment. This overrides any privacy annotations that
+        // appeared in previous comma-delimited segments.
+        if (MatchedStr.equals("private"))
+          PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPrivate;
+        else if (MatchedStr.equals("public"))
+          PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPublic;
+      } else {
+        size_t CommaOrBracePos =
+            Str.find_if([](char c) { return c == ',' || c == '}'; });
+        I += CommaOrBracePos + 1;
+
+        if (CommaOrBracePos == StringRef::npos) {
+          // Neither a comma nor the closing brace was found.
+          if (Warn)
+            H.HandleIncompleteSpecifier(Start, E - Start);
+          return true;
+        }
+      }
+      // Continue until the closing brace is found.
+    } while (*(I - 1) == ',');
+
+    // Set the privacy flag.
+    switch (PrivacyFlags) {
+    case 0:
+      break;
+    case clang::analyze_os_log::OSLogBufferItem::IsPrivate:
+      FS.setIsPrivate(MatchedStr.data());
+      break;
+    case clang::analyze_os_log::OSLogBufferItem::IsPublic:
+      FS.setIsPublic(MatchedStr.data());
+      break;
+    default:
+      llvm_unreachable("Unexpected privacy flag value");
     }
   }
 

Modified: cfe/trunk/test/CodeGen/builtins.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/builtins.c?rev=336629&r1=336628&r2=336629&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/builtins.c (original)
+++ cfe/trunk/test/CodeGen/builtins.c Mon Jul  9 17:50:25 2018
@@ -421,7 +421,29 @@ void test_builtin_os_log(void *buf, int
   // CHECK: %[[V5:.*]] = load i8*, i8** %[[DATA_ADDR]]
   // CHECK: %[[V6:.*]] = ptrtoint i8* %[[V5]] to i64
   // CHECK: call void @__os_log_helper_1_3_4_4_0_8_34_4_17_8_49(i8* %[[V1]], i32 %[[V2]], i64 %[[V4]], i32 16, i64 %[[V6]])
-  __builtin_os_log_format(buf, "%d %{public}s %{private}.16P", i, data, data);
+  __builtin_os_log_format(buf, "%d %{private,public}s %{public,private}.16P", i, data, data);
+
+  // privacy annotations aren't recognized when they are preceded or followed
+  // by non-whitespace characters.
+
+  // CHECK: call void @__os_log_helper_1_2_1_8_32(
+  __builtin_os_log_format(buf, "%{xyz public}s", data);
+
+  // CHECK: call void @__os_log_helper_1_2_1_8_32(
+  __builtin_os_log_format(buf, "%{ public xyz}s", data);
+
+  // CHECK: call void @__os_log_helper_1_2_1_8_32(
+  __builtin_os_log_format(buf, "%{ public1}s", data);
+
+  // Privacy annotations do not have to be in the first comma-delimited string.
+
+  // CHECK: call void @__os_log_helper_1_2_1_8_34(
+  __builtin_os_log_format(buf, "%{ xyz, public }s", "abc");
+
+  // The last privacy annotation in the string wins.
+
+  // CHECK: call void @__os_log_helper_1_3_1_8_33(
+  __builtin_os_log_format(buf, "%{ public, private, public, private}s", "abc");
 }
 
 // CHECK-LABEL: define linkonce_odr hidden void @__os_log_helper_1_3_4_4_0_8_34_4_17_8_49




More information about the cfe-commits mailing list