[commit: ghc] master: Fix uninformative hp2ps error when the cmdline contains double quotes (390df8b)

git at git.haskell.org git at git.haskell.org
Thu Nov 22 18:46:24 UTC 2018


Repository : ssh://git@git.haskell.org/ghc

On branch  : master
Link       : http://ghc.haskell.org/trac/ghc/changeset/390df8b51b917fb6409cbde8e73fe838d61d8832/ghc

>---------------------------------------------------------------

commit 390df8b51b917fb6409cbde8e73fe838d61d8832
Author: Zejun Wu <watashi at fb.com>
Date:   Thu Nov 22 11:51:15 2018 -0500

    Fix uninformative hp2ps error when the cmdline contains double quotes
    
    The format of hp file didn't allow double quotes inside strings, and
    under prof build, we include args in JOB, which may have double quotes.
    When this happens, the error message is confusing to the user. This can
    also happen under normal build if the executable name contains double
    quite, which is unlikely though.
    
    We fix this issue by introducing escaping for double quotes inside a
    string by repeating it twice.
    
    We also fix a buffer overflow bug when the length of the string happen
    to be multiple of 5000.
    
    Test Plan:
    new tests, which used to fail with error message:
    
    ```
    hp2ps: "T15904".hp, line 2: integer must follow identifier
    ```
    
    use new ghc and hp2ps to profile a simple program.
    
    Reviewers: simonmar, bgamari, erikd
    
    Reviewed By: simonmar
    
    Subscribers: rwbarton, carter
    
    GHC Trac Issues: #15904
    
    Differential Revision: https://phabricator.haskell.org/D5346


>---------------------------------------------------------------

390df8b51b917fb6409cbde8e73fe838d61d8832
 rts/ProfHeap.c                      | 30 ++++++++++++++++++++--------
 testsuite/tests/hp2ps/Makefile      |  9 +++++++++
 testsuite/tests/hp2ps/T15904.hs     |  8 ++++++++
 testsuite/tests/hp2ps/T15904.stdout |  7 +++++++
 testsuite/tests/hp2ps/all.T         |  1 +
 utils/hp2ps/HpFile.c                | 39 +++++++++++++++++--------------------
 6 files changed, 65 insertions(+), 29 deletions(-)

diff --git a/rts/ProfHeap.c b/rts/ProfHeap.c
index de3d2b6..517702f 100644
--- a/rts/ProfHeap.c
+++ b/rts/ProfHeap.c
@@ -361,6 +361,18 @@ void endProfiling( void )
 #endif /* !PROFILING */
 
 static void
+printEscapedString(const char* string)
+{
+    for (const char* p = string; *p != '\0'; ++p) {
+        if (*p == '\"') {
+            // Escape every " as ""
+            fputc('"', hp_file);
+        }
+        fputc(*p, hp_file);
+    }
+}
+
+static void
 printSample(bool beginSample, StgDouble sampleValue)
 {
     fprintf(hp_file, "%s %f\n",
@@ -428,16 +440,18 @@ initHeapProfiling(void)
     initEra( &censuses[era] );
 
     /* initProfilingLogFile(); */
-    fprintf(hp_file, "JOB \"%s", prog_name);
+    fprintf(hp_file, "JOB \"");
+    printEscapedString(prog_name);
 
 #if defined(PROFILING)
-    {
-        int count;
-        for(count = 1; count < prog_argc; count++)
-            fprintf(hp_file, " %s", prog_argv[count]);
-        fprintf(hp_file, " +RTS");
-        for(count = 0; count < rts_argc; count++)
-            fprintf(hp_file, " %s", rts_argv[count]);
+    for (int i = 1; i < prog_argc; ++i) {
+        fputc(' ', hp_file);
+        printEscapedString(prog_argv[i]);
+    }
+    fprintf(hp_file, " +RTS");
+    for (int i = 0; i < rts_argc; ++i) {
+        fputc(' ', hp_file);
+        printEscapedString(rts_argv[i]);
     }
 #endif /* PROFILING */
 
diff --git a/testsuite/tests/hp2ps/Makefile b/testsuite/tests/hp2ps/Makefile
new file mode 100644
index 0000000..4618db7
--- /dev/null
+++ b/testsuite/tests/hp2ps/Makefile
@@ -0,0 +1,9 @@
+TOP=../..
+include $(TOP)/mk/boilerplate.mk
+include $(TOP)/mk/test.mk
+
+.PHONY: T15904
+T15904:
+	"$(TEST_HC)" $(TEST_HC_OPTS) -rtsopts -main-is "$@" "$@.hs" -o "\"$@\""
+	"./\"$@\"" '{"e": 2.72, "pi": 3.14}' $$'\n' "\\" "" +RTS -h
+	"$(HP2PS_ABS)" "\"$@\".hp"
diff --git a/testsuite/tests/hp2ps/T15904.hs b/testsuite/tests/hp2ps/T15904.hs
new file mode 100644
index 0000000..7c009ff
--- /dev/null
+++ b/testsuite/tests/hp2ps/T15904.hs
@@ -0,0 +1,8 @@
+module T15904 (main) where
+
+import System.Environment
+
+main :: IO ()
+main = do
+  args <- getArgs
+  mapM_ putStrLn args
diff --git a/testsuite/tests/hp2ps/T15904.stdout b/testsuite/tests/hp2ps/T15904.stdout
new file mode 100644
index 0000000..6b08737
--- /dev/null
+++ b/testsuite/tests/hp2ps/T15904.stdout
@@ -0,0 +1,7 @@
+[1 of 1] Compiling T15904           ( T15904.hs, T15904.o )
+Linking "T15904" ...
+{"e": 2.72, "pi": 3.14}
+
+
+\
+
diff --git a/testsuite/tests/hp2ps/all.T b/testsuite/tests/hp2ps/all.T
new file mode 100644
index 0000000..bebeb56
--- /dev/null
+++ b/testsuite/tests/hp2ps/all.T
@@ -0,0 +1 @@
+test('T15904', [], run_command, ['$MAKE -s --no-print-directory T15904'])
diff --git a/utils/hp2ps/HpFile.c b/utils/hp2ps/HpFile.c
index e21acf3..bcdf7aa 100644
--- a/utils/hp2ps/HpFile.c
+++ b/utils/hp2ps/HpFile.c
@@ -398,45 +398,42 @@ GetIdent(FILE *infp)
 
 
 /*
- *	Read a sequence of characters that make up a string and 
- *	assign the result to "thestring".
+ * Read a sequence of characters that make up a string and assign the result to
+ * "thestring". A string is surrounded by double quotes, with a double quote
+ * itself escaped as two contiguous double quotes.
  */
 
 void
 GetString(FILE *infp)
 {
-    unsigned int i;
-    char *stringbuffer;
-    size_t stringbuffersize;
+    size_t stringbuffersize = 5000;
+    char *stringbuffer = xmalloc(stringbuffersize);
 
     ASSERT(ch == '\"');
 
-    stringbuffersize = 5000;
-    stringbuffer = xmalloc(stringbuffersize);
-
-    ch = getc(infp);	/* skip the '\"' that begins the string */
+    ch = getc(infp);  /* skip the '\"' that begins the string */
 
-    i = 0;
-    while (ch != '\"') {
+    for (size_t i = 0; ; ++i) {
         if (ch == EOF) {
-	        Error("%s, line %d: EOF when expecting \"", hpfile, linenum, ch);
+            Error("%s, line %d: EOF when expecting \"", hpfile, linenum, ch);
         }
-        else if (i == stringbuffersize - 1) {
-            stringbuffersize = 2 * stringbuffersize;
+        if (i == stringbuffersize) {
+            stringbuffersize *= 2;
             stringbuffer = xrealloc(stringbuffer, stringbuffersize);
         }
-        stringbuffer[ i++ ] = ch;
+        if (ch == '\"') {
+            ch = getc(infp);
+            if (ch != '\"') {
+                stringbuffer[i] = '\0';
+                break;
+            }
+        }
+        stringbuffer[i] = ch;
         ch = getc(infp);
     }
 
-    stringbuffer[i] = '\0'; 
     thestring = copystring(stringbuffer);
-
     free(stringbuffer);
-
-    ASSERT(ch == '\"');
-
-    ch = getc(infp);      /* skip the '\"' that terminates the string */
 }
 
 boolish



More information about the ghc-commits mailing list