OpenCL apps can quote arguments they pass to the OpenCL compiler, most
commonly include paths containing spaces. If the OpenCL compiler was
called via a shell, the shell would remove (single or double) quotes
before passing the argument to the compiler. Since we call Clang as a
library, we have to remove quotes before passing the argument.
---
 .../state_trackers/clover/llvm/invocation.cpp      | 41 +++++++++++++++++++---
 1 file changed, 36 insertions(+), 5 deletions(-)

diff --git a/src/gallium/state_trackers/clover/llvm/invocation.cpp 
b/src/gallium/state_trackers/clover/llvm/invocation.cpp
index e2cadda..d389a76 100644
--- a/src/gallium/state_trackers/clover/llvm/invocation.cpp
+++ b/src/gallium/state_trackers/clover/llvm/invocation.cpp
@@ -147,12 +147,43 @@ namespace {
 
       // Parse the compiler options:
       std::vector<std::string> opts_array;
-      std::istringstream ss(opts);
+      std::ostringstream builder;
+
+      // OpenCL programs can pass a single or double quoted argument, most
+      // frequently include path. This is useful so that the path containing
+      // spaces is treated as a single argument, but we should anyhow unquote
+      // quoted arguments before passing them to the compiler.
+      // We do not want to avoid using std::string::replace here, as include
+      // path can contain quotes in file names.
+      bool escape_next = false;
+      bool skip_space = false;
+      bool in_quote_double = false;
+      bool in_quote_single = false;
+      for (auto pos = std::begin(opts); pos != std::end(opts); ++pos) {
+         if (escape_next) {
+            builder.put(*pos);
+            escape_next = false;
+         } else if (*pos == '\\') {
+            escape_next = true;
+         } else if (*pos == '"' && !in_quote_single) {
+            in_quote_double = !in_quote_double;
+            skip_space = !skip_space;
+         } else if (*pos == '\'' && !in_quote_double) {
+            in_quote_single = !in_quote_single;
+            skip_space = !skip_space;
+         } else if (*pos == ' ' && !skip_space && builder.tellp() > 0) {
+            opts_array.emplace_back(builder.str());
+            builder.str("");
+         } else if (*pos != ' ' || skip_space) {
+            builder.put(*pos);
+         }
+      }
+      if (builder.tellp() > 0) {
+         opts_array.emplace_back(builder.str());
+      }
 
-      while (!ss.eof()) {
-         std::string opt;
-         getline(ss, opt, ' ');
-         opts_array.push_back(opt);
+      if (in_quote_double || in_quote_single) {
+         throw error(CL_INVALID_COMPILER_OPTIONS);
       }
 
       opts_array.push_back(name);
-- 
2.7.4

_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to