From ad144fa1bdd80577e95b69ffe2f2880a6ad386eb Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Tue, 24 Sep 2024 11:16:40 +0200 Subject: [PATCH] btstack_util: add safe versions of snprintf --- src/btstack_util.c | 44 +++++++++++++++++++++++++++++++++++++++----- src/btstack_util.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 5 deletions(-) diff --git a/src/btstack_util.c b/src/btstack_util.c index 707ef9779..c7118ab9b 100644 --- a/src/btstack_util.c +++ b/src/btstack_util.c @@ -45,16 +45,14 @@ #include "btstack_debug.h" #include "btstack_util.h" +#include // vsnprintf +#include // memcpy + #ifdef _MSC_VER #include #include #endif -#ifdef ENABLE_PRINTF_HEXDUMP -#include -#endif - -#include /** * @brief Compare two Bluetooth addresses @@ -641,6 +639,42 @@ void btstack_strcat(char * dst, uint16_t dst_size, const char * src){ dst[dst_len + bytes_to_copy] = 0; } +int btstack_printf_strlen(const char * format, ...){ + va_list argptr; + va_start(argptr, format); + char dummy_buffer[1]; + int len = vsnprintf(dummy_buffer, sizeof(dummy_buffer), format, argptr); + va_end(argptr); + return len; +} + +uint16_t btstack_snprintf_assert_complete(char * buffer, size_t size, const char * format, ...){ + va_list argptr; + va_start(argptr, format); + int len = vsnprintf(buffer, size, format, argptr); + va_end(argptr); + + // check for no error and no truncation + btstack_assert(len >= 0); + btstack_assert(len < size); + return (uint16_t) len; +} + +uint16_t btstack_snprintf_best_effort(char * buffer, size_t size, const char * format, ...){ + btstack_assert(size > 0); + va_list argptr; + va_start(argptr, format); + int len = vsnprintf(buffer, size, format, argptr); + va_end(argptr); + if (len < 0) { + // error -> len = 0 + return 0; + } else { + // min of total string len and buffer size + return (uint16_t) btstack_min((uint32_t) len, (uint32_t) size - 1); + } +} + uint16_t btstack_virtual_memcpy( const uint8_t * field_data, uint16_t field_len, uint16_t field_offset, // position of field in complete data block uint8_t * buffer, uint16_t buffer_size, uint16_t buffer_offset){ diff --git a/src/btstack_util.h b/src/btstack_util.h index dfb1b42e9..1db289b14 100644 --- a/src/btstack_util.h +++ b/src/btstack_util.h @@ -377,6 +377,50 @@ uint16_t btstack_strcpy(char * dst, uint16_t dst_size, const char * src); */ void btstack_strcat(char * dst, uint16_t dst_size, const char * src); +/** + * @brief Calculated the number of characters that would get printed + * @note same as calling snprintf without a buffer + * @param format + * @param argsq + * @return number of characters, or negative value on error + */ +int btstack_printf_strlen(const char * format, ...) +#ifdef __GNUC__ +__attribute__ ((format (__printf__, 1, 2))) +#endif +; + + +/** + * @brief Format string into buffer with '\0' and assert it is large enough + * @note same as calling snprintf and assert that the string was not truncated + * @param buffer + * @param size of buffer + * @param format + * @param argsq + * @return number of characters + */ +uint16_t btstack_snprintf_assert_complete(char * buffer, size_t size, const char * format, ...) +#ifdef __GNUC__ +__attribute__ ((format (__printf__, 3, 4))) +#endif +; + +/** + * @brief Format string into buffer, truncated if necessary. Output string is '\0' terminated + * @note similar to calling snprintf but returns the length of the output string + * @param buffer + * @param size of buffer + * @param format + * @param argsq + * @return number of characters + */ +uint16_t btstack_snprintf_best_effort(char * buffer, size_t size, const char * format, ...) +#ifdef __GNUC__ +__attribute__ ((format (__printf__, 3, 4))) +#endif +; + /** * Returns the number of leading 0-bits in x, starting at the most significant bit position. * If x is 0, the result is undefined.