logging: Prevent multiple arguments evaluation

Logging v2 is utilizing complex preprocessing operations to
prepare message at compile time. Multiple operations are peformed
on log message arguments. However, it is expected that argument
will be evaluated only once (e.g. it can be a call to a function
with side effects). Adding additional layer which creates copies
of user arguments on stack and passes them to further processing.

Updated test for log_msg2 which is using internal macro which
got renamed.

Signed-off-by: Krzysztof Chruscinski <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
Krzysztof Chruscinski
2022-01-26 11:05:45 +01:00
committed by Carles Cufí
parent 154ca8526c
commit a662e69cad
2 changed files with 38 additions and 17 deletions

View File

@@ -324,7 +324,7 @@ do { \
* @param ... Optional string with arguments (fmt, ...). It may be empty.
*/
#ifdef CONFIG_LOG2_ALWAYS_RUNTIME
#define Z_LOG_MSG2_CREATE3(_try_0cpy, _mode, _cstr_cnt, _domain_id, _source,\
#define Z_LOG_MSG2_CREATE2(_try_0cpy, _mode, _cstr_cnt, _domain_id, _source,\
_level, _data, _dlen, ...) \
do {\
Z_LOG_MSG2_STR_VAR(_fmt, ##__VA_ARGS__) \
@@ -357,42 +357,45 @@ do { \
} \
(void)_mode; \
} while (0)
#endif /* CONFIG_LOG2_ALWAYS_RUNTIME */
#define Z_LOG_MSG2_CREATE2(_try_0cpy, _mode, _domain_id, _source,\
_level, _data, _dlen, ...) \
Z_LOG_MSG2_CREATE3(_try_0cpy, _mode, UTIL_CAT(Z_LOG_FUNC_PREFIX_, _level), \
_domain_id, _source, _level, _data, _dlen, \
Z_LOG_STR(_level, __VA_ARGS__))
#if defined(__cplusplus)
#define Z_AUTO_TYPE auto
#else
#define Z_AUTO_TYPE __auto_type
#endif
/* Macro for getting name of a local variable with the exception of the first argument
* which is a formatted string in log message.
*/
#define Z_LOG_LOCAL_ARG_NAME(idx, arg) COND_CODE_0(idx, (arg), (_v##idx))
/* Create local variable from input variable (expect first (fmt) argument). */
#ifdef __cplusplus
/* Create local variable from input variable (expect for the first (fmt) argument). */
#define Z_LOG_LOCAL_ARG_CREATE(idx, arg) \
COND_CODE_0(idx, (), (auto Z_LOG_LOCAL_ARG_NAME(idx, arg) = (arg) + 0))
#else
#define Z_LOG_LOCAL_ARG_CREATE(idx, arg) \
COND_CODE_0(idx, (), (__auto_type Z_LOG_LOCAL_ARG_NAME(idx, arg) = (arg) + 0))
#endif
COND_CODE_0(idx, (), (Z_AUTO_TYPE Z_LOG_LOCAL_ARG_NAME(idx, arg) = (arg) + 0))
/* First level of processing creates stack variables to be passed for further processing.
* This is done to prevent multiple evaluations of input arguments (in case argument
* evaluation has consequences, e.g. it is a function call).
* evaluation has side effects, e.g. it is a non-pure function call).
*/
#define Z_LOG_MSG2_CREATE(_try_0cpy, _mode, _domain_id, _source, _level, _data, _dlen, ...) \
#define Z_LOG_MSG2_CREATE2(_try_0cpy, _mode, _cstr_cnt, _domain_id, _source, \
_level, _data, _dlen, ...) \
do { \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wpointer-arith\"") \
FOR_EACH_IDX(Z_LOG_LOCAL_ARG_CREATE, (;), __VA_ARGS__); \
_Pragma("GCC diagnostic pop") \
Z_LOG_MSG2_CREATE2(_try_0cpy, _mode, _domain_id, _source,\
Z_LOG_MSG2_CREATE3(_try_0cpy, _mode, _cstr_cnt, _domain_id, _source,\
_level, _data, _dlen, \
FOR_EACH_IDX(Z_LOG_LOCAL_ARG_NAME, (,), __VA_ARGS__)); \
} while (0)
#endif /* CONFIG_LOG2_ALWAYS_RUNTIME */
#define Z_LOG_MSG2_CREATE(_try_0cpy, _mode, _domain_id, _source,\
_level, _data, _dlen, ...) \
Z_LOG_MSG2_CREATE2(_try_0cpy, _mode, UTIL_CAT(Z_LOG_FUNC_PREFIX_, _level), \
_domain_id, _source, _level, _data, _dlen, \
Z_LOG_STR(_level, __VA_ARGS__))
/** @brief Allocate log message.
*

View File

@@ -15,6 +15,24 @@ if(NOT CONFIG_LOG_MODE_MINIMAL)
log_msg2.c
)
# Determine if __auto_type is supported. If not then runtime approach must always
# be used.
# Supported by:
# - C++ (auto)
# - GCC 4.9.0 https://gcc.gnu.org/gcc-4.9/changes.html
# - Clang 3.8
if (NOT CONFIG_LOG2_ALWAYS_RUNTIME)
if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
if(CMAKE_C_COMPILER_VERSION VERSION_LESS "3.8.0")
message(WARNING "Compiler version requires CONFIG_LOG2_ALWAYS_RUNTIME to be set")
endif()
endif()
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
if(CMAKE_C_COMPILER_VERSION VERSION_LESS "4.9.0")
message(WARNING "Compiler version requires CONFIG_LOG2_ALWAYS_RUNTIME to be set")
endif()
endif()
endif()
zephyr_sources_ifdef(
CONFIG_LOG_BACKEND_UART