[PATCH i-g-t v3 07/10] runner: Fix use of newline on arguments
Lucas De Marchi
lucas.demarchi at intel.com
Thu Jan 30 17:21:46 UTC 2025
Currently there's no support for newlines on arguments passed to runner.
However it's also a silent failure:
# igt_runner --test-list '/tmp/test
list2.txt' build/tests/ /tmp/results
# head /tmp/results/metadata.txt
disk_usage_limit : 0
test_list : /tmp/test
list2.txt
name : results
...
# ./build/runner/igt_resume /tmp/results
[9840425.334900] All tests already executed.
resume failed at generating results
Done.
Embedding a newline like this is very dubious for test-list, but it's
used for e.g. hooks. In future we will add the command line to the
metadata and possibly migrate the hooks, so add support for
escaping/unescaping the string on save/restore.
The method chosen is slightly different than the one used for hooks:
instead of adding a escape char and keeping the char escaped, this just
prefers using an hex representation of the char with a \x<HEX>h
sequence. This makes it easier when unescaping since the reader can
continue reading one line per iteration. In future this can also be
adopted by the hooks or even migrating the hooks to use metadata.txt.
For compatibility with previous parsing, it still prints "(null)" for
NULL pointers: ideally there would be nothing printed to avoid the
special case for this string.
Signed-off-by: Lucas De Marchi <lucas.demarchi at intel.com>
---
runner/settings.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 76 insertions(+), 1 deletion(-)
diff --git a/runner/settings.c b/runner/settings.c
index 693c5484e..b527c01d9 100644
--- a/runner/settings.c
+++ b/runner/settings.c
@@ -1052,10 +1052,79 @@ static bool serialize_hook_strs(struct settings *settings, int dirfd)
return true;
}
+/*
+ * Serialize @s to @f, escaping '\' and '\n'. See unescape_str()
+ */
+static void escape_str(const char *s, FILE *f)
+{
+ if (!s) {
+ fputs("(null)", f);
+ return;
+ }
+
+ while (*s) {
+ size_t len = strcspn(s, "\\\n");
+
+ if (len > 0) {
+ fwrite(s, len, 1, f);
+ s += len;
+ }
+
+ if (*s) {
+ fprintf(f, "\\x%xh", *s);
+ s++;
+ }
+ }
+}
+
+/*
+ * Unescape a '\' and '\n': undo escape_str
+ *
+ * Exacpe chars using the form '\x<hex>h' so they don't interfere with the line
+ * parser.
+ *
+ * Return the number of chars saved in buf and optionally
+ * the number of chars scanned in @n_src if that is non-nul.
+ */
+static size_t unescape_str(char *buf, size_t *n_src)
+{
+ size_t dst_len = 0;
+ char *s = buf;
+
+ while (*s) {
+ char next = *(s + 1);
+
+ if (*s != '\\') {
+ buf[dst_len++] = *s++;
+ } else if (*s == '\\' && next == 'x') {
+ s += 2;
+ buf[dst_len++] = strtoul(s, &s, 16);
+ if (*s != 'h') {
+ /* this shouldn't happen */
+ return 0;
+ }
+ s++;
+ } else {
+ return 0;
+ }
+ }
+
+ buf[dst_len] = '\0';
+
+ if (n_src)
+ *n_src = s - buf;
+
+ return dst_len;
+}
+
#define SERIALIZE_LINE(f, s, name, fmt) fprintf(f, "%s : " fmt "\n", #name, s->name)
#define SERIALIZE_INT(f, s, name) SERIALIZE_LINE(f, s, name, "%d")
#define SERIALIZE_UL(f, s, name) SERIALIZE_LINE(f, s, name, "%lu")
-#define SERIALIZE_STR(f, s, name) SERIALIZE_LINE(f, s, name, "%s")
+#define SERIALIZE_STR(f, s, name) do { \
+ fputs(#name " : ", f); \
+ escape_str(s->name, f); \
+ fputc('\n', f); \
+ } while (0)
bool serialize_settings(struct settings *settings)
{
FILE *f;
@@ -1171,6 +1240,12 @@ static char *parse_str(char **val)
{
char *ret = *val;
+ /*
+ * Unescaping a string is guaranteed to produce a string that is
+ * smaller or of the same size. Just modify it in place and leak the
+ * buffer
+ */
+ unescape_str(ret, NULL);
*val = NULL;
return ret;
--
2.48.0
More information about the igt-dev
mailing list