ASDenysPetrov created this revision.
ASDenysPetrov added reviewers: Charusso, NoQ.
ASDenysPetrov added a project: clang.
Herald added subscribers: cfe-commits, dkrupp, donat.nagy, Szelethus, 
mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, xazax.hun.

Windows forbidden file path characters are used in a field `file`, while 
creating a dump `dot` file using an argument -analyzer-dump-egraph. It 
specifically relates to angle brackets when using `<scratch space>`, 
`<built-in>`, `<command line>` values in filenames. It causes that script 
exploded-graph-rewriter.py incorrectly parses the dump.

Fix: Remove forbidden characters from filename for Windows platform, when 
creating graph dump file.

This patch shall follow after D82092 <https://reviews.llvm.org/D82092>, since 
it has a fix for `assert`. `assert` is used in the test here.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D82103

Files:
  clang/include/clang/Basic/JsonSupport.h
  
clang/test/Analysis/exploded-graph-rewriter/l_directory_from_l/win_file_macros.cpp
  clang/test/Analysis/exploded-graph-rewriter/win_filepath.cpp
  clang/utils/analyzer/exploded-graph-rewriter.py

Index: clang/utils/analyzer/exploded-graph-rewriter.py
===================================================================
--- clang/utils/analyzer/exploded-graph-rewriter.py
+++ clang/utils/analyzer/exploded-graph-rewriter.py
@@ -368,8 +368,7 @@
                 self.root_id = node_id
             # Note: when writing tests you don't need to escape everything,
             # even though in a valid dot file everything is escaped.
-            node_label = result.group(2).replace('\\l', '') \
-                                        .replace('&nbsp;', '') \
+            node_label = result.group(2).replace('&nbsp;', '') \
                                         .replace('\\"', '"') \
                                         .replace('\\{', '{') \
                                         .replace('\\}', '}') \
@@ -378,6 +377,15 @@
                                         .replace('\\<', '\\\\<') \
                                         .replace('\\>', '\\\\>') \
                                         .rstrip(',')
+            # Handle `\l` separately for Windows, because macros __FILE__ produces
+            # Windows specific delimiters `\` and sometimes it happens
+            # when directory name starts with the letter `l`.
+            if sys.platform == 'win32':
+                # Find all `\l` (like `,\l`, `}\l`, `[\l`) except `\\l`,
+                # because __FILE__ containes multiple `\` before `\l`.
+                node_label = re.sub(r'(?<!\\)\\l', '', node_label)
+            else:
+                node_label = node_label.replace('\\l', '')
             logging.debug(node_label)
             json_node = json.loads(node_label)
             self.nodes[node_id].construct(node_id, json_node)
Index: clang/test/Analysis/exploded-graph-rewriter/win_filepath.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/exploded-graph-rewriter/win_filepath.cpp
@@ -0,0 +1,28 @@
+// FIXME: Figure out how to use %clang_analyze_cc1 with our lit.local.cfg.
+// RUN: %clang_cc1 -analyze -triple x86_64-unknown-linux-gnu \
+// RUN:                     -analyzer-checker=core \
+// RUN:                     -analyzer-dump-egraph=%t.dot %s
+// RUN: %exploded_graph_rewriter %t.dot | FileCheck %s
+// REQUIRES: asserts
+// UNSUPPORTED: !windows
+
+// Angle brackets shall not be presented in the field `file`,
+// because exploded_graph_rewriter handles it as a file path
+// and such symbols are forbidden on Windows platform.
+
+extern void __assert_fail (__const char *__assertion, __const char *__file,
+    unsigned int __line, __const char *__function)
+     __attribute__ ((__noreturn__));
+#define assert(expr) \
+  ((expr)  ? (void)(0)  : __assert_fail (#expr, __FILE__, __LINE__, __func__))
+  
+int test(int *array, int size)
+{
+  //Here `assert` helps to produce angle brackets.
+  assert(size);
+  return array[size];
+}
+
+//This test is passed if exploded_graph_rewriter handles dot file without errors.
+// CHECK: digraph "ExplodedGraph"
+
Index: clang/test/Analysis/exploded-graph-rewriter/l_directory_from_l/win_file_macros.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/exploded-graph-rewriter/l_directory_from_l/win_file_macros.cpp
@@ -0,0 +1,28 @@
+// FIXME: Figure out how to use %clang_analyze_cc1 with our lit.local.cfg.
+// RUN: %clang_cc1 -analyze -triple x86_64-unknown-linux-gnu \
+// RUN:                     -analyzer-checker=core \
+// RUN:                     -analyzer-dump-egraph=%t.dot %s
+// RUN: %exploded_graph_rewriter %t.dot | FileCheck %s
+// REQUIRES: asserts
+// UNSUPPORTED: !windows
+
+// This test checks a special case when `\l` can be not only as a new-line symbol,
+// but as a start of the directory name on Windows platform.
+// This occures when using __FILE__ macros.
+
+extern void __assert_fail (__const char *__assertion, __const char *__file,
+    unsigned int __line, __const char *__function)
+     __attribute__ ((__noreturn__));
+#define assert(expr) \
+  ((expr)  ? (void)(0)  : __assert_fail (#expr, __FILE__, __LINE__, __func__))
+  
+int test1(int i)
+{
+  //Here `assert` produces angle brackets and uses __FILE__ macros.
+  assert(i);
+  return i;
+}
+
+// This test is passed if exploded_graph_rewriter handles dot file without errors.
+// CHECK: digraph "ExplodedGraph"
+
Index: clang/include/clang/Basic/JsonSupport.h
===================================================================
--- clang/include/clang/Basic/JsonSupport.h
+++ clang/include/clang/Basic/JsonSupport.h
@@ -13,6 +13,7 @@
 #include "clang/Basic/SourceManager.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/raw_ostream.h"
+#include <iterator>
 
 
 namespace clang {
@@ -98,7 +99,16 @@
     if (AddBraces)
       Out << "{ ";
     std::string filename(PLoc.getFilename());
-#ifdef _WIN32 // Handle windows-specific path delimiters.
+#ifdef _WIN32 
+    // Remove forbidden Windows path characters
+    auto RemoveIt =
+        std::remove_if(filename.begin(), filename.end(), [](auto Char) {
+          static const char ForbiddenChars[] = "<>*?\"|";
+          return std::find(std::begin(ForbiddenChars), std::end(ForbiddenChars),
+                           Char) != std::end(ForbiddenChars);
+        });
+    filename.erase(RemoveIt, filename.end());
+    // Handle windows-specific path delimiters.
     std::replace(filename.begin(), filename.end(), '\\', '/');
 #endif
     Out << "\"line\": " << PLoc.getLine()
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to