[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