kopia lustrzana https://github.com/espressif/esp-idf
system: add option to enable undefined behavior sanitizer (UBSAN)
Closes https://github.com/espressif/esp-idf/issues/1574pull/6974/head
rodzic
469c137c83
commit
9069f70db3
|
@ -19,7 +19,8 @@ else()
|
|||
"startup.c"
|
||||
"system_time.c"
|
||||
"stack_check.c"
|
||||
"task_wdt.c")
|
||||
"task_wdt.c"
|
||||
"ubsan.c")
|
||||
|
||||
if(NOT (${target} STREQUAL "esp32c3") )
|
||||
list(APPEND srcs "dbg_stubs.c")
|
||||
|
@ -58,3 +59,7 @@ if(CONFIG_IDF_ENV_FPGA)
|
|||
# Forces the linker to include fpga stubs from this component
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u esp_common_include_fpga_overrides")
|
||||
endif()
|
||||
|
||||
# Force linking UBSAN hooks. If UBSAN is not enabled, the hooks will ultimately be removed
|
||||
# due to -ffunction-sections -Wl,--gc-sections options.
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u __ubsan_include")
|
||||
|
|
|
@ -19,6 +19,10 @@ ifndef CONFIG_IDF_ENV_FPGA
|
|||
COMPONENT_OBJEXCLUDE += fpga_overrides.o
|
||||
endif
|
||||
|
||||
# Force linking UBSAN hooks. If UBSAN is not enabled, the hooks will ultimately be removed
|
||||
# due to -ffunction-sections -Wl,--gc-sections options.
|
||||
COMPONENT_ADD_LDFLAGS += -u __ubsan_include
|
||||
|
||||
include $(COMPONENT_PATH)/port/soc/$(SOC_NAME)/component.mk
|
||||
|
||||
# disable stack protection in files which are involved in initialization of that feature
|
||||
|
|
|
@ -8,6 +8,7 @@ entries:
|
|||
|
||||
esp_err (noflash)
|
||||
esp_system:esp_system_abort (noflash)
|
||||
ubsan (noflash)
|
||||
|
||||
if ESP_CONSOLE_USB_CDC_SUPPORT_ETS_PRINTF:
|
||||
usb_console:esp_usb_console_write_char (noflash)
|
||||
|
|
|
@ -348,7 +348,7 @@ void esp_panic_handler(panic_info_t *info)
|
|||
}
|
||||
|
||||
|
||||
void __attribute__((noreturn)) panic_abort(const char *details)
|
||||
void __attribute__((noreturn,no_sanitize_undefined)) panic_abort(const char *details)
|
||||
{
|
||||
g_panic_abort = true;
|
||||
s_panic_abort_details = (char*) details;
|
||||
|
|
|
@ -0,0 +1,294 @@
|
|||
// Copyright (c) 2016, Linaro Limited
|
||||
// Modified for HelenOS use by Jiří Zárevúcky.
|
||||
// Adaptations for ESP-IDF Copyright (c) 2020 Espressif Systems (Shanghai) Co. Ltd.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "esp_system.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "hal/cpu_hal.h"
|
||||
|
||||
|
||||
struct source_location {
|
||||
const char *file_name;
|
||||
uint32_t line;
|
||||
uint32_t column;
|
||||
};
|
||||
|
||||
struct type_descriptor {
|
||||
uint16_t type_kind;
|
||||
uint16_t type_info;
|
||||
char type_name[];
|
||||
};
|
||||
|
||||
struct type_mismatch_data {
|
||||
struct source_location loc;
|
||||
struct type_descriptor *type;
|
||||
unsigned long alignment;
|
||||
unsigned char type_check_kind;
|
||||
};
|
||||
|
||||
struct type_mismatch_data_v1 {
|
||||
struct source_location loc;
|
||||
struct type_descriptor *type;
|
||||
unsigned char log_alignment;
|
||||
unsigned char type_check_kind;
|
||||
};
|
||||
|
||||
struct overflow_data {
|
||||
struct source_location loc;
|
||||
struct type_descriptor *type;
|
||||
};
|
||||
|
||||
struct shift_out_of_bounds_data {
|
||||
struct source_location loc;
|
||||
struct type_descriptor *lhs_type;
|
||||
struct type_descriptor *rhs_type;
|
||||
};
|
||||
|
||||
struct out_of_bounds_data {
|
||||
struct source_location loc;
|
||||
struct type_descriptor *array_type;
|
||||
struct type_descriptor *index_type;
|
||||
};
|
||||
|
||||
struct unreachable_data {
|
||||
struct source_location loc;
|
||||
};
|
||||
|
||||
struct vla_bound_data {
|
||||
struct source_location loc;
|
||||
struct type_descriptor *type;
|
||||
};
|
||||
|
||||
struct invalid_value_data {
|
||||
struct source_location loc;
|
||||
struct type_descriptor *type;
|
||||
};
|
||||
|
||||
struct nonnull_arg_data {
|
||||
struct source_location loc;
|
||||
};
|
||||
|
||||
struct nonnull_return_data {
|
||||
struct source_location loc;
|
||||
struct source_location attr_loc;
|
||||
};
|
||||
|
||||
struct pointer_overflow_data {
|
||||
struct source_location loc;
|
||||
};
|
||||
|
||||
struct invalid_builtin_data {
|
||||
struct source_location loc;
|
||||
unsigned char kind;
|
||||
};
|
||||
|
||||
|
||||
static void __ubsan_default_handler(struct source_location *loc, const char *func) __attribute__((noreturn));
|
||||
|
||||
/*
|
||||
* When compiling with -fsanitize=undefined the compiler expects functions
|
||||
* with the following signatures. The functions are never called directly,
|
||||
* only when undefined behavior is detected in instrumented code.
|
||||
*/
|
||||
void __ubsan_handle_type_mismatch(struct type_mismatch_data *data, unsigned long ptr);
|
||||
void __ubsan_handle_type_mismatch_v1(struct type_mismatch_data_v1 *data, unsigned long ptr);
|
||||
void __ubsan_handle_add_overflow(struct overflow_data *data, unsigned long lhs, unsigned long rhs);
|
||||
void __ubsan_handle_sub_overflow(struct overflow_data *data, unsigned long lhs, unsigned long rhs);
|
||||
void __ubsan_handle_mul_overflow(struct overflow_data *data, unsigned long lhs, unsigned long rhs);
|
||||
void __ubsan_handle_negate_overflow(struct overflow_data *data, unsigned long old_val);
|
||||
void __ubsan_handle_divrem_overflow(struct overflow_data *data, unsigned long lhs, unsigned long rhs);
|
||||
void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data, unsigned long lhs, unsigned long rhs);
|
||||
void __ubsan_handle_out_of_bounds(struct out_of_bounds_data *data, unsigned long idx);
|
||||
void __ubsan_handle_missing_return(struct unreachable_data *data);
|
||||
void __ubsan_handle_vla_bound_not_positive(struct vla_bound_data *data, unsigned long bound);
|
||||
void __ubsan_handle_load_invalid_value(struct invalid_value_data *data, unsigned long val);
|
||||
void __ubsan_handle_nonnull_arg(struct nonnull_arg_data *data);
|
||||
void __ubsan_handle_nonnull_return(struct nonnull_return_data *data);
|
||||
void __ubsan_handle_builtin_unreachable(struct unreachable_data *data);
|
||||
void __ubsan_handle_pointer_overflow(struct pointer_overflow_data *data,
|
||||
unsigned long base, unsigned long result);
|
||||
|
||||
static void __ubsan_maybe_debugbreak(void)
|
||||
{
|
||||
if (cpu_hal_is_debugger_attached()) {
|
||||
cpu_hal_break();
|
||||
}
|
||||
}
|
||||
|
||||
static void __ubsan_default_handler(struct source_location *loc, const char *func)
|
||||
{
|
||||
/* Although the source location is available here, it is not printed:
|
||||
*
|
||||
* - We could use "snprintf", but that uses a lot of stack, and may allocate memory,
|
||||
* so is not safe from UBSAN handler.
|
||||
* - Alternatively, "itoa" could be used. However itoa doesn't take the remaining
|
||||
* string length as as argument and is therefore unsafe (nor does it return
|
||||
* the number of characters written). itoa is also not present in ESP32-S2 ROM,
|
||||
* and would need to be placed into IRAM on that chip.
|
||||
* - Third option is to print the message using esp_rom_printf, and not pass anything
|
||||
* to esp_system_abort. However we'd like to capture this information, e.g. for the
|
||||
* purpose of including the abort reason into core dumps.
|
||||
*
|
||||
* Since the source file and line number are already printed while decoding
|
||||
* the panic backtrace, not printing the line number here seems to be an okay choice.
|
||||
*/
|
||||
char msg[60] = {};
|
||||
(void) strlcat(msg, "Undefined behavior of type ", sizeof(msg));
|
||||
(void) strlcat(msg, func + strlen("__ubsan_handle_"), sizeof(msg));
|
||||
esp_system_abort(msg);
|
||||
}
|
||||
|
||||
void __ubsan_handle_type_mismatch(struct type_mismatch_data *data,
|
||||
unsigned long ptr)
|
||||
{
|
||||
__ubsan_maybe_debugbreak();
|
||||
__ubsan_default_handler(&data->loc, __func__);
|
||||
}
|
||||
|
||||
void __ubsan_handle_type_mismatch_v1(struct type_mismatch_data_v1 *data,
|
||||
unsigned long ptr)
|
||||
{
|
||||
__ubsan_maybe_debugbreak();
|
||||
__ubsan_default_handler(&data->loc, __func__);
|
||||
}
|
||||
|
||||
void __ubsan_handle_add_overflow(struct overflow_data *data,
|
||||
unsigned long lhs,
|
||||
unsigned long rhs)
|
||||
{
|
||||
__ubsan_maybe_debugbreak();
|
||||
__ubsan_default_handler(&data->loc, __func__);
|
||||
}
|
||||
|
||||
void __ubsan_handle_sub_overflow(struct overflow_data *data,
|
||||
unsigned long lhs,
|
||||
unsigned long rhs)
|
||||
{
|
||||
__ubsan_maybe_debugbreak();
|
||||
__ubsan_default_handler(&data->loc, __func__);
|
||||
}
|
||||
|
||||
void __ubsan_handle_mul_overflow(struct overflow_data *data,
|
||||
unsigned long lhs,
|
||||
unsigned long rhs)
|
||||
{
|
||||
__ubsan_maybe_debugbreak();
|
||||
__ubsan_default_handler(&data->loc, __func__);
|
||||
}
|
||||
|
||||
void __ubsan_handle_negate_overflow(struct overflow_data *data,
|
||||
unsigned long old_val)
|
||||
{
|
||||
__ubsan_maybe_debugbreak();
|
||||
__ubsan_default_handler(&data->loc, __func__);
|
||||
}
|
||||
|
||||
void __ubsan_handle_divrem_overflow(struct overflow_data *data,
|
||||
unsigned long lhs,
|
||||
unsigned long rhs)
|
||||
{
|
||||
__ubsan_maybe_debugbreak();
|
||||
__ubsan_default_handler(&data->loc, __func__);
|
||||
}
|
||||
|
||||
void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data,
|
||||
unsigned long lhs,
|
||||
unsigned long rhs)
|
||||
{
|
||||
if (rhs == 32) {
|
||||
return;
|
||||
}
|
||||
__ubsan_maybe_debugbreak();
|
||||
__ubsan_default_handler(&data->loc, __func__);
|
||||
}
|
||||
|
||||
void __ubsan_handle_out_of_bounds(struct out_of_bounds_data *data,
|
||||
unsigned long idx)
|
||||
{
|
||||
__ubsan_maybe_debugbreak();
|
||||
__ubsan_default_handler(&data->loc, __func__);
|
||||
}
|
||||
|
||||
void __ubsan_handle_missing_return(struct unreachable_data *data)
|
||||
{
|
||||
__ubsan_maybe_debugbreak();
|
||||
__ubsan_default_handler(&data->loc, __func__);
|
||||
}
|
||||
|
||||
void __ubsan_handle_vla_bound_not_positive(struct vla_bound_data *data,
|
||||
unsigned long bound)
|
||||
{
|
||||
__ubsan_maybe_debugbreak();
|
||||
__ubsan_default_handler(&data->loc, __func__);
|
||||
}
|
||||
|
||||
void __ubsan_handle_load_invalid_value(struct invalid_value_data *data,
|
||||
unsigned long val)
|
||||
{
|
||||
__ubsan_maybe_debugbreak();
|
||||
__ubsan_default_handler(&data->loc, __func__);
|
||||
}
|
||||
|
||||
void __ubsan_handle_nonnull_arg(struct nonnull_arg_data *data)
|
||||
{
|
||||
__ubsan_maybe_debugbreak();
|
||||
__ubsan_default_handler(&data->loc, __func__);
|
||||
}
|
||||
|
||||
void __ubsan_handle_nonnull_return(struct nonnull_return_data *data)
|
||||
{
|
||||
__ubsan_maybe_debugbreak();
|
||||
__ubsan_default_handler(&data->loc, __func__);
|
||||
}
|
||||
|
||||
void __ubsan_handle_builtin_unreachable(struct unreachable_data *data)
|
||||
{
|
||||
__ubsan_maybe_debugbreak();
|
||||
__ubsan_default_handler(&data->loc, __func__);
|
||||
}
|
||||
|
||||
void __ubsan_handle_pointer_overflow(struct pointer_overflow_data *data,
|
||||
unsigned long base, unsigned long result)
|
||||
{
|
||||
__ubsan_maybe_debugbreak();
|
||||
__ubsan_default_handler(&data->loc, __func__);
|
||||
}
|
||||
|
||||
void __ubsan_handle_invalid_builtin(struct invalid_builtin_data *data)
|
||||
{
|
||||
__ubsan_maybe_debugbreak();
|
||||
__ubsan_default_handler(&data->loc, __func__);
|
||||
}
|
||||
|
||||
/* Hook for the linker to include this object file */
|
||||
void __ubsan_include(void)
|
||||
{
|
||||
}
|
|
@ -33,7 +33,7 @@ static inline uint32_t mpu_ll_id_to_addr(int id)
|
|||
// 0xa0000000 = 5
|
||||
// 0xc0000000 = 6
|
||||
// 0xe0000000 = 7
|
||||
return id * SOC_MPU_MIN_REGION_SIZE;
|
||||
return (unsigned)id * SOC_MPU_MIN_REGION_SIZE;
|
||||
}
|
||||
|
||||
static inline void mpu_ll_set_region_rw(uint32_t addr)
|
||||
|
|
|
@ -71,6 +71,8 @@ These third party libraries can be included into the application (firmware) prod
|
|||
|
||||
* :component:`openthread`, Copyright (c) The OpenThread Authors, is licensed under Apache License 2.0 as described in :component_file:`LICENSE file<openthread/openthread/LICENSE>`.
|
||||
|
||||
* :component_file:` UBSAN runtime <esp_system/ubsan.c>` — Copyright (c) 2016, Linaro Limited and Jiří Zárevúcky, licensed under the BSD 2-clause license.
|
||||
|
||||
Build Tools
|
||||
-----------
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ In certain situations, execution of the program can not be continued in a well d
|
|||
- Stack overflow
|
||||
- Stack smashing protection check
|
||||
- Heap integrity check
|
||||
- Undefined behavior sanitizer (UBSAN) checks
|
||||
|
||||
- Failed assertions, via ``assert``, ``configASSERT`` and similar macros.
|
||||
|
||||
|
@ -389,3 +390,98 @@ The backtrace should point to the function where stack smashing has occured. Che
|
|||
.. |CPU_EXCEPTIONS_LIST| replace:: Illegal Instruction, Load/Store Alignment Error, Load/Store Prohibited error.
|
||||
.. |ILLEGAL_INSTR_MSG| replace:: Illegal instruction
|
||||
.. |CACHE_ERR_MSG| replace:: Cache error
|
||||
|
||||
Undefined behavior sanitizer (UBSAN) checks
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Undefined behavior sanitizer (UBSAN) is a compiler feature which adds run-time checks for potentially incorrect operations, such as:
|
||||
|
||||
- overflows (multiplication overflow, signed integer overflow)
|
||||
- shift base or exponent errors (e.g. shift by more than 32 bits)
|
||||
- integer conversion errors
|
||||
|
||||
See `GCC documentation <https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html>`_ of ``-fsanitize=undefined`` option for the complete list of supported checks.
|
||||
|
||||
Enabling UBSAN
|
||||
""""""""""""""
|
||||
|
||||
UBSAN is disabled by default. It can be enabled at file, component, or project level by adding ``-fsanitize=undefined`` compiler option in the build system.
|
||||
|
||||
When enabling UBSAN for the code which uses hardware register header files (``soc/xxx_reg.h``), it is recommended to disable shift-base sanitizer using ``-fno-sanitize=shift-base`` option. This is due to the fact that ESP-IDF register header files currently contain patterns which cause false positives for this specific sanitizer option.
|
||||
|
||||
To enable UBSAN at project level, add the following at the end of the project CMakeLists.txt file::
|
||||
|
||||
idf_build_set_property(COMPILE_OPTIONS "-fsanitize=undefined" "-fno-sanitize=shift-base" APPEND)
|
||||
|
||||
Alternatively, pass these options through ``EXTRA_CFLAGS`` and ``EXTRA_CXXFLAGS`` environment variables.
|
||||
|
||||
Enabling UBSAN results in significant increase of code and data size. Most applications, except for the trivial ones, will not fit into the available RAM of the microcontroller when UBSAN is enabled for the whole application. Therefore it is recommended that UBSAN is instead enabled for specific components under test.
|
||||
|
||||
To enable UBSAN for the specific component (``component_name``) from the project CMakeLists.txt file, add the following at the end of the file::
|
||||
|
||||
idf_component_get_property(lib component_name COMPONENT_LIB)
|
||||
target_compile_options(${lib} PRIVATE "-fsanitize=undefined" "-fno-sanitize=shift-base")
|
||||
|
||||
.. note:: See the build system documentation for more information about :ref:`build properties<cmake-build-properties>` and :ref:`component properties<cmake-component-properties>`.
|
||||
|
||||
To enable UBSAN for the specific component (``component_name``) from CMakeLists.txt of the same component, add the following at the end of the file::
|
||||
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-fsanitize=undefined" "-fno-sanitize=shift-base")
|
||||
|
||||
UBSAN output
|
||||
""""""""""""
|
||||
|
||||
When UBSAN detects an error, a message and the backtrace are printed, for example::
|
||||
|
||||
Undefined behavior of type out_of_bounds
|
||||
|
||||
Backtrace:0x4008b383:0x3ffcd8b0 0x4008c791:0x3ffcd8d0 0x4008c587:0x3ffcd8f0 0x4008c6be:0x3ffcd950 0x400db74f:0x3ffcd970 0x400db99c:0x3ffcd9a0
|
||||
|
||||
When using :doc:`IDF Monitor <tools/idf-monitor>`, the backtrace will be decoded to function names and source code locations, pointing to the location where the issue has happened (here it is ``main.c:128``)::
|
||||
|
||||
0x4008b383: panic_abort at /path/to/esp-idf/components/esp_system/panic.c:367
|
||||
|
||||
0x4008c791: esp_system_abort at /path/to/esp-idf/components/esp_system/system_api.c:106
|
||||
|
||||
0x4008c587: __ubsan_default_handler at /path/to/esp-idf/components/esp_system/ubsan.c:152
|
||||
|
||||
0x4008c6be: __ubsan_handle_out_of_bounds at /path/to/esp-idf/components/esp_system/ubsan.c:223
|
||||
|
||||
0x400db74f: test_ub at main.c:128
|
||||
|
||||
0x400db99c: app_main at main.c:56 (discriminator 1)
|
||||
|
||||
The types of errors reported by UBSAN can be as follows:
|
||||
|
||||
.. list-table::
|
||||
:widths: 40 60
|
||||
:header-rows: 1
|
||||
|
||||
* - Name
|
||||
- Meaning
|
||||
* - ``type_mismatch``, ``type_mismatch_v1``
|
||||
- Incorrect pointer value: null, unaligned, not compatible with the given type.
|
||||
* - ``add_overflow``, ``sub_overflow``, ``mul_overflow``, ``negate_overflow``
|
||||
- Integer overflow during addition, subtraction, multiplication, negation.
|
||||
* - ``divrem_overflow``
|
||||
- Integer division by 0 or ``INT_MIN``.
|
||||
* - ``shift_out_of_bounds``
|
||||
- Overflow in left or right shift operators.
|
||||
* - ``out_of_bounds``
|
||||
- Access outside of bounds of an array.
|
||||
* - ``unreachable``
|
||||
- Unreachable code executed.
|
||||
* - ``missing_return``
|
||||
- Non-void function has reached its end without returning a value (C++ only).
|
||||
* - ``vla_bound_not_positive``
|
||||
- Size of variable length array is not positive.
|
||||
* - ``load_invalid_value``
|
||||
- Value of ``bool`` or ``enum`` (C++ only) variable is invalid (out of bounds).
|
||||
* - ``nonnull_arg``
|
||||
- Null argument passed to a function which is declared with a ``nonnull`` attribute.
|
||||
* - ``nonnull_return``
|
||||
- Null value returned from a function which is declared with ``returns_nonnull`` attribute.
|
||||
* - ``builtin_unreachable``
|
||||
- ``__builtin_unreachable`` function called.
|
||||
* - ``pointer_overflow``
|
||||
- Overflow in pointer arithmetic.
|
||||
|
|
|
@ -2,5 +2,27 @@
|
|||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(COMPONENTS esptool_py main)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
project(test_panic)
|
||||
|
||||
# Enable UBSAN checks
|
||||
#
|
||||
# shift-base sanitizer is disabled due to the following pattern found in register header files:
|
||||
# #define SOME_FIELD 0xFFFF
|
||||
# #define SOME_FIELD_M ((SOME_FIELD_V)<<(SOME_FIELD_S))
|
||||
# #define SOME_FIELD_V 0xFFFF
|
||||
# #define SOME_FIELD_S 16
|
||||
# here SOME_FIELD_V doesn't have an unsigned (U) prefix, so the compiler flags
|
||||
# SOME_FIELD_M expansion (0xFFFF << 16) as generating integer overflow.
|
||||
#
|
||||
set(ubsan_options "-fsanitize=undefined" "-fno-sanitize=shift-base")
|
||||
|
||||
# Only enable UBSAN for a few components related to the panic test,
|
||||
# due to RAM size limitations.
|
||||
foreach(component main espcoredump esp_system spi_flash
|
||||
esp_common esp_hw_support soc hal freertos)
|
||||
idf_component_get_property(lib ${component} COMPONENT_LIB)
|
||||
target_compile_options(${lib} PRIVATE ${ubsan_options})
|
||||
endforeach()
|
||||
|
|
|
@ -292,5 +292,37 @@ def test_gdbstub_abort(env, _extra_data):
|
|||
test.abort_inner(env, 'gdbstub')
|
||||
|
||||
|
||||
# test_ub
|
||||
|
||||
@panic_test()
|
||||
def test_panic_ub(env, _extra_data):
|
||||
test.ub_inner(env, "panic")
|
||||
|
||||
|
||||
@panic_test()
|
||||
def test_coredump_ub_uart_elf_crc(env, _extra_data):
|
||||
test.ub_inner(env, "coredump_uart_elf_crc")
|
||||
|
||||
|
||||
@panic_test()
|
||||
def test_coredump_ub_uart_bin_crc(env, _extra_data):
|
||||
test.ub_inner(env, "coredump_uart_bin_crc")
|
||||
|
||||
|
||||
@panic_test()
|
||||
def test_coredump_ub_flash_elf_sha(env, _extra_data):
|
||||
test.ub_inner(env, "coredump_flash_elf_sha")
|
||||
|
||||
|
||||
@panic_test()
|
||||
def test_coredump_ub_flash_bin_crc(env, _extra_data):
|
||||
test.ub_inner(env, "coredump_flash_bin_crc")
|
||||
|
||||
|
||||
@panic_test()
|
||||
def test_gdbstub_ub(env, _extra_data):
|
||||
test.ub_inner(env, "gdbstub")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_all(__file__, sys.argv[1:])
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
idf_component_register(SRCS "test_panic_main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES spi_flash esp_system)
|
||||
|
|
|
@ -22,6 +22,7 @@ static void test_int_wdt_cache_disabled(void);
|
|||
static void test_stack_overflow(void);
|
||||
static void test_illegal_instruction(void);
|
||||
static void test_instr_fetch_prohibited(void);
|
||||
static void test_ub(void);
|
||||
|
||||
|
||||
void app_main(void)
|
||||
|
@ -52,6 +53,7 @@ void app_main(void)
|
|||
HANDLE_TEST(test_stack_overflow);
|
||||
HANDLE_TEST(test_illegal_instruction);
|
||||
HANDLE_TEST(test_instr_fetch_prohibited);
|
||||
HANDLE_TEST(test_ub);
|
||||
|
||||
#undef HANDLE_TEST
|
||||
|
||||
|
@ -80,7 +82,7 @@ static void test_task_wdt(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void test_storeprohibited(void)
|
||||
static void __attribute__((no_sanitize_undefined)) test_storeprohibited(void)
|
||||
{
|
||||
*(int*) 0x1 = 0;
|
||||
}
|
||||
|
@ -142,6 +144,12 @@ static void test_instr_fetch_prohibited(void)
|
|||
fptr();
|
||||
}
|
||||
|
||||
static void test_ub(void)
|
||||
{
|
||||
uint8_t stuff[1] = {rand()};
|
||||
printf("%d\n", stuff[rand()]);
|
||||
}
|
||||
|
||||
/* implementations of the utility functions */
|
||||
|
||||
#define BOOT_CMD_MAX_LEN (128)
|
||||
|
@ -183,7 +191,7 @@ static void die(const char* msg)
|
|||
{
|
||||
printf("Test error: %s\n\n", msg);
|
||||
fflush(stdout);
|
||||
fsync(fileno(stdout));
|
||||
usleep(1000);
|
||||
/* Don't use abort here as it would enter the panic handler */
|
||||
esp_restart_noos();
|
||||
}
|
||||
|
|
|
@ -147,3 +147,15 @@ def instr_fetch_prohibited_inner(env, test_name):
|
|||
dut.expect_none('Guru Meditation')
|
||||
test_common(dut, test_name,
|
||||
expected_backtrace=['_init'] + get_default_backtrace(dut.test_name))
|
||||
|
||||
|
||||
def ub_inner(env, test_name):
|
||||
with get_dut(env, test_name, "test_ub") as dut:
|
||||
dut.expect(re.compile(r"Undefined behavior of type out_of_bounds"))
|
||||
dut.expect_backtrace()
|
||||
dut.expect_elf_sha256()
|
||||
dut.expect_none("Guru Meditation", "Re-entered core dump")
|
||||
test_common(dut, test_name, expected_backtrace=[
|
||||
# Backtrace interrupted when abort is called, IDF-842
|
||||
"panic_abort", "esp_system_abort"
|
||||
])
|
||||
|
|
|
@ -13,3 +13,6 @@ CONFIG_ESP_TASK_WDT_PANIC=y
|
|||
|
||||
# For vTaskGetInfo() used in test_stack_overflow()
|
||||
CONFIG_FREERTOS_USE_TRACE_FACILITY=y
|
||||
|
||||
# Reduce IRAM size
|
||||
CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y
|
||||
|
|
Ładowanie…
Reference in New Issue