From cdbe424ecae0ea6332bf06722d65bea7be5f76b6 Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Wed, 19 Feb 2025 12:07:34 +0100 Subject: [PATCH] cmake: escape json input string Escape the json input string given to `to_yaml()` function and the content given to `yaml_set()` function. This ensures that a string like `foo\bar` becomes `foo\\bar` during internal CMake json processing and when written to the file it becomes `foo\bar`. Signed-off-by: Torsten Rasmussen --- cmake/modules/extensions.cmake | 21 ++++++++++++++++++++- cmake/modules/yaml.cmake | 9 ++++++--- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index 51726a3b7ec..2299c29958d 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -3037,6 +3037,16 @@ endfunction() # This function extends the CMake string function by providing additional # manipulation arguments to CMake string. # +# ESCAPE: Ensure that any single '\' in the input string is escaped with the +# escape char '\'. For example the string 'foo\bar' will be escaped +# so that it becomes 'foo\\bar'. +# Backslashes which are already escaped will not be escaped further, +# for example 'foo\\bar' will not be modified. +# This is useful for handling of windows path separator in strings or +# when strings contains newline escapes such as '\n' and this can +# cause issues when writing to a file where a '\n' is desired in the +# string instead of a newline. +# # SANITIZE: Ensure that the output string does not contain any special # characters. Special characters, such as -, +, =, $, etc. are # converted to underscores '_'. @@ -3048,9 +3058,11 @@ endfunction() # # returns the updated string function(zephyr_string) - set(options SANITIZE TOUPPER) + set(options SANITIZE TOUPPER ESCAPE) cmake_parse_arguments(ZEPHYR_STRING "${options}" "" "" ${ARGN}) + zephyr_check_flags_exclusive(${CMAKE_CURRENT_FUNCTION} ZEPHYR_STRING SANITIZE ESCAPE) + if (NOT ZEPHYR_STRING_UNPARSED_ARGUMENTS) message(FATAL_ERROR "Function zephyr_string() called without a return variable") endif() @@ -3068,6 +3080,13 @@ function(zephyr_string) string(TOUPPER ${work_string} work_string) endif() + if(ZEPHYR_STRING_ESCAPE) + # If a single '\' is discovered, such as 'foo\bar', then it must be escaped like: 'foo\\bar' + # \\1 and \\2 are keeping the match patterns, the \\\\ --> \\ meaning an escaped '\', + # which then becomes a single '\' in the final string. + string(REGEX REPLACE "([^\\][\\])([^\\])" "\\1\\\\\\2" work_string "${ZEPHYR_STRING_UNPARSED_ARGUMENTS}") + endif() + set(${return_arg} ${work_string} PARENT_SCOPE) endfunction() diff --git a/cmake/modules/yaml.cmake b/cmake/modules/yaml.cmake index ec12a04bec5..a509567bc5d 100644 --- a/cmake/modules/yaml.cmake +++ b/cmake/modules/yaml.cmake @@ -422,9 +422,11 @@ function(yaml_set) internal_yaml_list_initializer(json_string ${genex}) string(JSON json_content SET "${json_content}" ${ARG_YAML_KEY} "${json_string}") endif() - internal_yaml_list_append(json_content ${genex} "${ARG_YAML_KEY}" ${ARG_YAML_LIST}) + zephyr_string(ESCAPE escape_list "${ARG_YAML_LIST}") + internal_yaml_list_append(json_content ${genex} "${ARG_YAML_KEY}" ${escape_list}) else() - string(JSON json_content SET "${json_content}" ${ARG_YAML_KEY} "\"${ARG_YAML_VALUE}\"") + zephyr_string(ESCAPE escape_value "${ARG_YAML_VALUE}") + string(JSON json_content SET "${json_content}" ${ARG_YAML_KEY} "\"${escape_value}\"") endif() zephyr_set(JSON "${json_content}" SCOPE ${ARG_YAML_NAME}) @@ -539,7 +541,8 @@ function(yaml_save) endif() endfunction() -function(to_yaml json level yaml genex) +function(to_yaml in_json level yaml genex) + zephyr_string(ESCAPE json "${in_json}") if(level GREATER 0) math(EXPR level_dec "${level} - 1") set(indent_${level} "${indent_${level_dec}} ")