[Git][ghc/ghc][wip/andreask/jsonProfEscaping] Escape backslashes in json profiling reports properly.

Andreas Klebinger gitlab at gitlab.haskell.org
Fri Jul 10 13:53:09 UTC 2020



Andreas Klebinger pushed to branch wip/andreask/jsonProfEscaping at Glasgow Haskell Compiler / GHC


Commits:
8ef59825 by Andreas Klebinger at 2020-07-10T15:52:59+02:00
Escape backslashes in json profiling reports properly.

I also took the liberty to do away the fixed buffer size for escaping.
Using a fixed size here can only lead to issues down the line.

Fixes #18438.

- - - - -


1 changed file:

- rts/ProfilerReportJson.c


Changes:

=====================================
rts/ProfilerReportJson.c
=====================================
@@ -6,6 +6,7 @@
  *
  * ---------------------------------------------------------------------------*/
 
+#define PROFILING
 #if defined(PROFILING)
 
 #include "PosixSource.h"
@@ -15,23 +16,33 @@
 #include "ProfilerReportJson.h"
 #include "Profiling.h"
 
-// This only handles characters that you might see in a Haskell cost-centre
-// name.
-static void escapeString(char const* str, char *out, int len)
+// I don't think this code is all that perf critical.
+// So we just allocate a new buffer each time around.
+static void escapeString(char const* str, char **buf)
 {
-    len--; // reserve character in output for terminating NUL
-    for (; *str != '\0' && len > 0; str++) {
+    char *out;
+    size_t req_size; //Max required size for decoding.
+    size_t in_size;  //Input size, including zero.
+
+    in_size = strlen(str) + 1;
+    // The strings are generally small and short
+    // lived so should be ok to just double the size.
+    req_size = in_size * 2;
+    out = stgMallocBytes(req_size, "writeCCSReportJson");
+    *buf = out;
+    // We provide an outputbuffer twice the size of the input,
+    // and at worse double the output size. So we can skip
+    // length checks.
+    for (; *str != '\0'; str++) {
         char c = *str;
         if (c == '\\') {
-            if (len < 2) break;
-            *out = '\\'; out++; len--;
-            *out = '\\'; out++; len--;
+            *out = '\\'; out++;
+            *out = '\\'; out++;
         } else if (c == '\n') {
-            if (len < 2) break;
-            *out = '\\'; out++; len--;
-            *out = 'n';  out++; len--;
+            *out = '\\'; out++;
+            *out = 'n';  out++;
         } else {
-            *out = c; out++; len--;
+            *out = c; out++;
         }
     }
     *out = '\0';
@@ -40,11 +51,13 @@ static void escapeString(char const* str, char *out, int len)
 static void
 logCostCentres(FILE *prof_file)
 {
-    char tmp[256];
+    char* lbl;
+    char* src_loc;
     bool needs_comma = false;
     fprintf(prof_file, "[\n");
     for (CostCentre *cc = CC_LIST; cc != NULL; cc = cc->link) {
-        escapeString(cc->label, tmp, sizeof(tmp));
+        escapeString(cc->label, &lbl);
+        escapeString(cc->srcloc, &src_loc);
         fprintf(prof_file,
                 "%s"
                 "{\"id\": %" FMT_Int ", "
@@ -53,11 +66,13 @@ logCostCentres(FILE *prof_file)
                 "\"src_loc\": \"%s\", "
                 "\"is_caf\": %s}",
                 needs_comma ? ", " : "",
-                cc->ccID, tmp, cc->module, cc->srcloc,
+                cc->ccID, lbl, cc->module, src_loc,
                 cc->is_caf ? "true" : "false");
         needs_comma = true;
     }
     fprintf(prof_file, "]\n");
+    stgFree(lbl);
+    stgFree(src_loc);
 }
 
 static void
@@ -92,15 +107,24 @@ writeCCSReportJson(FILE *prof_file,
                    CostCentreStack const *stack,
                    ProfilerTotals totals)
 {
+
     fprintf(prof_file, "{\n\"program\": \"%s\",\n", prog_name);
     fprintf(prof_file, "\"arguments\": [");
-    for (int count = 0; prog_argv[count]; count++)
+    for (int count = 0; prog_argv[count]; count++) {
+        char* arg;
+        escapeString(prog_argv[count], &arg);
         fprintf(prof_file, "%s\"%s\"",
-                count == 0 ? "" : ", ", prog_argv[count]);
+                count == 0 ? "" : ", ", arg);
+        stgFree(arg);
+    }
     fprintf(prof_file, "],\n\"rts_arguments\": [");
-    for (int count = 0; rts_argv[count]; count++)
+    for (int count = 0; rts_argv[count]; count++) {
+        char* arg;
+        escapeString(rts_argv[count], &arg);
         fprintf(prof_file, "%s\"%s\"",
-                count == 0 ? "" : ", ", rts_argv[count]);
+                count == 0 ? "" : ", ", arg);
+        stgFree(arg);
+    }
     fprintf(prof_file, "],\n");
 
     fprintf(prof_file, "\"end_time\": \"%s\",\n", time_str());
@@ -121,6 +145,7 @@ writeCCSReportJson(FILE *prof_file,
     fprintf(prof_file, ",\n\"profile\": ");
     logCostCentreStack(prof_file, stack);
     fprintf(prof_file, "}\n");
+
 }
 
 



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/8ef5982548113c789c238270809e541e706e30a6

-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/8ef5982548113c789c238270809e541e706e30a6
You're receiving this email because of your account on gitlab.haskell.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20200710/5f5b4471/attachment-0001.html>


More information about the ghc-commits mailing list