From 85c682f7e60d2c281db66c05b309da10141a2d0c Mon Sep 17 00:00:00 2001 From: Christian Buttner Date: Thu, 15 Aug 2024 15:01:53 +0200 Subject: [PATCH] Escape arguments to platform linker/compiler. (#1358) * Escape arguments to platform linker/compiler. --- .../testproject/lib/clib.c3l/manifest.json | 2 +- .../lib/clib.c3l/whitespace test.c | 1 + src/compiler/linker.c | 39 +++---- src/utils/lib.h | 6 +- src/utils/stringutils.c | 110 ++++++++++++++---- 5 files changed, 109 insertions(+), 49 deletions(-) create mode 100644 resources/testproject/lib/clib.c3l/whitespace test.c diff --git a/resources/testproject/lib/clib.c3l/manifest.json b/resources/testproject/lib/clib.c3l/manifest.json index 44de08bff..3d5cca505 100644 --- a/resources/testproject/lib/clib.c3l/manifest.json +++ b/resources/testproject/lib/clib.c3l/manifest.json @@ -1,6 +1,6 @@ { "provides" : "clib", - "c-sources" : ["hello2.c"], + "c-sources" : ["hello2.c", "whitespace test.c"], "targets" : { "macos-x64" : { }, diff --git a/resources/testproject/lib/clib.c3l/whitespace test.c b/resources/testproject/lib/clib.c3l/whitespace test.c new file mode 100644 index 000000000..53c5fdf17 --- /dev/null +++ b/resources/testproject/lib/clib.c3l/whitespace test.c @@ -0,0 +1 @@ +#include diff --git a/src/compiler/linker.c b/src/compiler/linker.c index c8c26558a..eca35e140 100644 --- a/src/compiler/linker.c +++ b/src/compiler/linker.c @@ -36,17 +36,6 @@ static const char *ld_target(ArchType arch_type) } } -static const char *string_esc(const char *str) -{ - scratch_buffer_clear(); - size_t len = strlen(str); - for (size_t i = 0; i < len; i++) - { - if (i > 3 && !char_is_alphanum_(str[i])) scratch_buffer_append_char('\\'); - scratch_buffer_append_char(str[i]); - } - return strdup(scratch_buffer_to_string()); -} static void linker_setup_windows(const char ***args_ref, Linker linker_type) { @@ -673,22 +662,20 @@ bool obj_format_linking_supported(ObjectFormatType format_type) const char *concat_string_parts(const char **args) { - unsigned size_needed = 0; + scratch_buffer_clear(); FOREACH(const char *, arg, args) { - size_needed += strlen(arg) + 1; + assert(arg != scratch_buffer.str && "Incorrectly passed a scratch buffer string as an argument."); + if (PLATFORM_WINDOWS && arg == *args) + { + scratch_buffer_append(arg); + } + else + { + scratch_buffer_append_argument(arg); + } } - char *output = malloc_string(size_needed); - char *ptr = output; - FOREACH(const char *, arg, args) - { - unsigned len = (unsigned)strlen(arg); - memcpy(ptr, arg, len); - ptr += len; - *(ptr++) = ' '; - } - ptr[-1] = '\0'; - return output; + return scratch_buffer_copy(); } @@ -780,7 +767,7 @@ const char *cc_compiler(const char *cc, const char *file, const char *flags, con FOREACH(const char *, include_dir, include_dirs) { - vec_add(parts, str_printf(is_cl_exe ? "/I\"%s\"" : "-I\"%s\"", include_dir)); + vec_add(parts, str_printf(is_cl_exe ? "/I%s" : "-I%s", include_dir)); } const bool pie_set = @@ -799,7 +786,7 @@ const char *cc_compiler(const char *cc, const char *file, const char *flags, con vec_add(parts, file); if (is_cl_exe) { - vec_add(parts, str_printf("/Fo:\"%s\"", out_name)); + vec_add(parts, str_printf("/Fo:%s", out_name)); } else { diff --git a/src/utils/lib.h b/src/utils/lib.h index bd24d2c4c..fe4458004 100644 --- a/src/utils/lib.h +++ b/src/utils/lib.h @@ -154,10 +154,12 @@ void slice_trim(StringSlice *slice); void scratch_buffer_clear(void); void scratch_buffer_append(const char *string); -UNUSED char *scratch_buffer_get_quoted(const char *string); -UNUSED void scratch_buffer_append_quoted(const char *string); +void scratch_buffer_append_argument(const char *string); +void scratch_buffer_append_double_quoted(const char *string); +void scratch_buffer_append_shell_escaped(const char *string); void scratch_buffer_append_len(const char *string, size_t len); void scratch_buffer_append_char(char c); +void scratch_buffer_append_char_repeat(char c, size_t count); void scratch_buffer_append_signed_int(int64_t i); void scratch_buffer_append_double(double d); UNUSED void scratch_buffer_append_unsigned_int(uint64_t i); diff --git a/src/utils/stringutils.c b/src/utils/stringutils.c index 6e46fa44f..83bc69c08 100644 --- a/src/utils/stringutils.c +++ b/src/utils/stringutils.c @@ -320,37 +320,99 @@ void scratch_buffer_append_len(const char *string, size_t len) scratch_buffer.len += (uint32_t)len; } -char *scratch_buffer_get_quoted(const char *string) -{ - scratch_buffer_clear(); - scratch_buffer_append_quoted(string); - return scratch_buffer_to_string(); -} - -void scratch_buffer_append_quoted(const char *string) +#if PLATFORM_WINDOWS +static bool contains_whitespace_or_quotes(const char *string) { char c; - while ((c = string++[0]) != '\0') + while ((c = *string++) != '\0') { + switch (c) + { + case ' ': + case '\t': + case '\n': + case '\r': + case '"': + return true; + } + } + return false; +} +#endif + +void scratch_buffer_append_argument(const char *string) +{ + if (scratch_buffer.len != 0) scratch_buffer_append_char(' '); +#if PLATFORM_WINDOWS + if (contains_whitespace_or_quotes(string)) + { + scratch_buffer_append_double_quoted(string); + } + else + { + scratch_buffer_append(string); + } +#else + scratch_buffer_append_shell_escaped(string); +#endif +} + +void scratch_buffer_append_double_quoted(const char *string) +{ + scratch_buffer_append_char('"'); + size_t len = strlen(string); + for (size_t i = 0; i < len; ) + { + char c = string[i++]; switch (c) { case '"': scratch_buffer_append("\\\""); continue; case '\\': - scratch_buffer_append("\\\\"); + { + int backslash_count = 1; + for (; i < len && string[i] == '\\'; i++, backslash_count++) {} + if (i == len || string[i] == '"') + { + scratch_buffer_append_char_repeat('\\', backslash_count * 2); + } + else + { + scratch_buffer_append_char_repeat('\\', backslash_count); + } continue; - case '\n': - scratch_buffer_append("\\n"); - continue; - case '\'': - scratch_buffer_append("\\'"); - continue; - default: - scratch_buffer_append_char(c); - continue; - + } } + scratch_buffer_append_char(c); + } + scratch_buffer_append_char('"'); +} + +void scratch_buffer_append_shell_escaped(const char *string) +{ + char c; + while ((c = string++[0]) != '\0') + { + if ((unsigned)c < 0x80) + { + switch (c) + { + case LOWER_CHAR_CASE: + case UPPER_CHAR_CASE: + case NUMBER_CHAR_CASE: + case '_': + case '/': + case '.': + case ',': + case '-': + break; + default: + scratch_buffer_append_char('\\'); + break; + } + } + scratch_buffer_append_char(c); } } void scratch_buffer_append(const char *string) @@ -407,6 +469,14 @@ void scratch_buffer_append_char(char c) scratch_buffer.str[scratch_buffer.len++] = c; } +void scratch_buffer_append_char_repeat(char c, size_t count) +{ + for (size_t i = 0; i < count; i++) + { + scratch_buffer_append_char(c); + } +} + char *scratch_buffer_to_string(void) { scratch_buffer.str[scratch_buffer.len] = '\0';