feat(build): add COMPILER_STATIC_ANALYZER option

This commit is contained in:
Alexey Lapshin 2024-06-06 15:23:02 +07:00 committed by BOT
parent e1b9985bd0
commit ed6e497c6f
46 changed files with 265 additions and 41 deletions

View File

@ -112,6 +112,22 @@ fast_template_app:
BUILD_COMMAND_ARGS: "-p"
#------------------------------------------------------------------------------
#######################
# gnu_static_analyzer #
#######################
gcc_static_analyzer:
extends:
- .build_template_app_template
- .rules:build:target_test
stage: pre_check
tags: [build, shiny]
variables:
CI_CCACHE_DISABLE: 1
ANALYZING_APP: "examples/get-started/hello_world"
script:
- echo "CONFIG_COMPILER_STATIC_ANALYZER=y" >> ${ANALYZING_APP}/sdkconfig.defaults
- python -m idf_build_apps build -vv -p ${ANALYZING_APP} -t all
########################################
# Clang Build Apps Without Tests Cases #
########################################

View File

@ -96,7 +96,7 @@ if(CMAKE_C_COMPILER_ID MATCHES "Clang")
list(APPEND compile_options "-Wno-pointer-bool-conversion")
# mbedTLS md5.c triggers this warning in md5_test_buf (false positive)
list(APPEND compile_options "-Wno-string-concatenation")
# multiple cases of implict convertions between unrelated enum types
# multiple cases of implicit conversions between unrelated enum types
list(APPEND compile_options "-Wno-enum-conversion")
# When IRAM_ATTR is specified both in function declaration and definition,
# it produces different section names, since section names include __COUNTER__.
@ -203,8 +203,10 @@ endif()
# GCC-specific options
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
list(APPEND compile_options "-fstrict-volatile-bitfields"
)
list(APPEND compile_options "-fstrict-volatile-bitfields")
if(CONFIG_COMPILER_STATIC_ANALYZER)
list(APPEND compile_options "-fanalyzer")
endif()
endif()
if(CONFIG_ESP_SYSTEM_USE_EH_FRAME)

11
Kconfig
View File

@ -48,6 +48,10 @@ mainmenu "Espressif IoT Development Framework Configuration"
bool
default "y" if IDF_TOOLCHAIN="clang"
config IDF_TOOLCHAIN_GCC
bool
default "y" if IDF_TOOLCHAIN="gcc"
config IDF_TARGET_ARCH_RISCV
bool
default "n"
@ -606,6 +610,13 @@ mainmenu "Espressif IoT Development Framework Configuration"
Places orphan sections without a warning/error message.
endchoice
config COMPILER_STATIC_ANALYZER
bool "Enable compiler static analyzer"
default "n"
depends on IDF_TOOLCHAIN_GCC
help
Enable compiler static analyzer. This may produce false-positive results and increases compile time.
endmenu # Compiler Options
menu "Component config"

View File

@ -37,3 +37,7 @@ idf_component_register(SRCS ${srcs}
PRIV_REQUIRES esp_driver_uart
esp_driver_usb_serial_jtag
)
if(CONFIG_COMPILER_STATIC_ANALYZER AND CMAKE_C_COMPILER_ID STREQUAL "GNU") # TODO IDF-10085
target_compile_options(${COMPONENT_LIB} PRIVATE "-fno-analyzer")
endif()

View File

@ -111,4 +111,9 @@ else()
esp_driver_uart esp_driver_ledc esp_driver_parlio esp_driver_usb_serial_jtag
LDFRAGMENTS ${ldfragments}
)
if(CONFIG_SOC_ADC_SUPPORTED AND
CONFIG_COMPILER_STATIC_ANALYZER AND CMAKE_C_COMPILER_ID STREQUAL "GNU") # TODO GCC-366
set_source_files_properties(deprecated/adc_legacy.c
PROPERTIES COMPILE_FLAGS "-Wno-analyzer-use-of-uninitialized-value")
endif()
endif()

View File

@ -27,6 +27,7 @@
#include "hal/rmt_ll.h"
#include "hal/gpio_hal.h"
#include "esp_rom_gpio.h"
#include "esp_compiler.h"
#define RMT_CHANNEL_ERROR_STR "RMT CHANNEL ERR"
#define RMT_ADDR_ERROR_STR "RMT ADDRESS ERR"
@ -1061,6 +1062,7 @@ esp_err_t rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int intr
#if SOC_RMT_SUPPORT_RX_PINGPONG
if (p_rmt_obj[channel]->rx_item_buf == NULL && rx_buf_size > 0) {
ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE("-Wanalyzer-malloc-leak") // False-positive detection. TODO GCC-366
#if !CONFIG_SPIRAM_USE_MALLOC
p_rmt_obj[channel]->rx_item_buf = calloc(1, rx_buf_size);
#else
@ -1074,6 +1076,7 @@ esp_err_t rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int intr
ESP_LOGE(TAG, "RMT malloc fail");
return ESP_FAIL;
}
ESP_COMPILER_DIAGNOSTIC_POP("-Wanalyzer-malloc-leak")
p_rmt_obj[channel]->rx_item_buf_size = rx_buf_size;
}
#endif
@ -1237,7 +1240,7 @@ esp_err_t rmt_translator_get_context(const size_t *item_num, void **context)
{
ESP_RETURN_ON_FALSE(item_num && context, ESP_ERR_INVALID_ARG, TAG, "invalid arguments");
// the address of tx_len_rem is directlly passed to the callback,
// the address of tx_len_rem is directly passed to the callback,
// so it's possible to get the object address from that
rmt_obj_t *obj = __containerof(item_num, rmt_obj_t, tx_len_rem);
*context = obj->tx_context;

View File

@ -11,6 +11,7 @@
#include "esp_types.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_compiler.h"
#include "freertos/FreeRTOS.h"
#include "esp_private/regi2c_ctrl.h"
#include "soc/regi2c_saradc.h"
@ -110,7 +111,9 @@ esp_err_t temp_sensor_stop(void)
esp_err_t temp_sensor_read_raw(uint32_t *tsens_out)
{
ESP_RETURN_ON_FALSE(tsens_out != NULL, ESP_ERR_INVALID_ARG, TAG, "no tsens_out specified");
ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE("-Wanalyzer-use-of-uninitialized-value") // False-positive detection. TODO GCC-366
*tsens_out = temperature_sensor_ll_get_raw_value();
ESP_COMPILER_DIAGNOSTIC_POP("-Wanalyzer-use-of-uninitialized-value")
return ESP_OK;
}

View File

@ -94,3 +94,10 @@ set(EFUSE_TEST_TABLE_CSV_PATH "${COMPONENT_DIR}/test/esp_efuse_test_table.csv")
add_custom_target(efuse_test_table COMMAND "${python}"
"${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py"
${EFUSE_TEST_TABLE_CSV_PATH} ${GEN_EFUSE_TABLE_ARG})
###################
# GNU analyzer excludes
if(CONFIG_COMPILER_STATIC_ANALYZER AND CMAKE_C_COMPILER_ID STREQUAL "GNU") # TODO IDF-10086
set_source_files_properties(src/esp_efuse_utility.c
PROPERTIES COMPILE_FLAGS "-fno-analyzer")
endif()

View File

@ -7,6 +7,7 @@
#include <sys/cdefs.h>
#include "esp_tls.h"
#include "esp_tls_error_capture_internal.h"
#include "esp_compiler.h"
typedef struct esp_tls_error_storage {
struct esp_tls_last_error parent; /*!< standard esp-tls last error container */
@ -34,11 +35,13 @@ void esp_tls_internal_event_tracker_capture(esp_tls_error_handle_t h, uint32_t t
esp_tls_error_handle_t esp_tls_internal_event_tracker_create(void)
{
ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE("-Wanalyzer-malloc-leak")
// Allocating internal error storage which extends the parent type
// `esp_tls_last_error` defined at interface level
struct esp_tls_error_storage* storage =
calloc(1, sizeof(struct esp_tls_error_storage));
return &storage->parent;
ESP_COMPILER_DIAGNOSTIC_POP("-Wanalyzer-malloc-leak")
}
void esp_tls_internal_event_tracker_destroy(esp_tls_error_handle_t h)

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2016-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -11,7 +11,7 @@
/*
* The likely and unlikely macro pairs:
* These macros are useful to place when application
* knows the majority ocurrence of a decision paths,
* knows the majority occurrence of a decision paths,
* placing one of these macros can hint the compiler
* to reorder instructions producing more optimized
* code.
@ -52,3 +52,31 @@
#define ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_STR(member, value) .member = value,
#define ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_EMPTY(member)
#endif
#define __COMPILER_PRAGMA__(string) _Pragma(#string)
#define _COMPILER_PRAGMA_(string) __COMPILER_PRAGMA__(string)
#if __clang__
#define ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE(warning) \
__COMPILER_PRAGMA__(clang diagnostic push) \
__COMPILER_PRAGMA__(clang diagnostic ignored "-Wunknown-warning-option") \
__COMPILER_PRAGMA__(clang diagnostic ignored warning)
#define ESP_COMPILER_DIAGNOSTIC_POP(warning) \
__COMPILER_PRAGMA__(clang diagnostic pop)
#elif __GNUC__
#define ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE(warning) \
__COMPILER_PRAGMA__(GCC diagnostic push) \
__COMPILER_PRAGMA__(GCC diagnostic ignored "-Wpragmas") \
__COMPILER_PRAGMA__(GCC diagnostic ignored warning)
#define ESP_COMPILER_DIAGNOSTIC_POP(warning) \
__COMPILER_PRAGMA__(GCC diagnostic pop)
#else
#define ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE(warning)
#define ESP_COMPILER_DIAGNOSTIC_POP(warning)
#endif
#if __clang_analyzer__ || CONFIG_COMPILER_STATIC_ANALYZER
#define ESP_STATIC_ANALYZER_CHECK(_expr_, _ret_) do { if ((_expr_)) { return (_ret_); } } while(0)
#else
#define ESP_STATIC_ANALYZER_CHECK(_expr_, _ret_)
#endif

View File

@ -1106,6 +1106,7 @@ static void IRAM_ATTR rmt_tx_default_isr(void *args)
}
#if SOC_RMT_SUPPORT_DMA
ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE("-Wanalyzer-null-dereference") // TODO IDF-10235
static bool IRAM_ATTR rmt_dma_tx_eof_cb(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data)
{
rmt_tx_channel_t *tx_chan = (rmt_tx_channel_t *)user_data;
@ -1132,4 +1133,5 @@ static bool IRAM_ATTR rmt_dma_tx_eof_cb(gdma_channel_handle_t dma_chan, gdma_eve
}
return false;
}
ESP_COMPILER_DIAGNOSTIC_POP("-Wanalyzer-null-dereference")
#endif // SOC_RMT_SUPPORT_DMA

View File

@ -189,6 +189,10 @@ idf_build_get_property(target IDF_TARGET)
add_subdirectory(port/${target})
add_subdirectory(lowpower)
if(CONFIG_COMPILER_STATIC_ANALYZER AND CMAKE_C_COMPILER_ID STREQUAL "GNU") # TODO IDF-10229
target_compile_options(${COMPONENT_LIB} PRIVATE "-fno-analyzer")
endif()
if(NOT BOOTLOADER_BUILD)
if(CONFIG_SPIRAM)
idf_component_optional_requires(PRIVATE esp_psram)

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -19,6 +19,7 @@
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_compiler.h"
static const char *TAG = "lcd_panel.io.i2c";
@ -47,6 +48,8 @@ typedef struct {
esp_err_t esp_lcd_new_panel_io_i2c_v1(uint32_t bus, const esp_lcd_panel_io_i2c_config_t *io_config, esp_lcd_panel_io_handle_t *ret_io)
{
// leak detection of i2c_panel_io because saving i2c_panel_io->base address
ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE("-Wanalyzer-malloc-leak")
#if CONFIG_LCD_ENABLE_DEBUG_LOG
esp_log_level_set(TAG, ESP_LOG_DEBUG);
#endif
@ -78,6 +81,7 @@ esp_err_t esp_lcd_new_panel_io_i2c_v1(uint32_t bus, const esp_lcd_panel_io_i2c_c
return ESP_OK;
err:
return ret;
ESP_COMPILER_DIAGNOSTIC_POP("-Wanalyzer-malloc-leak")
}
static esp_err_t panel_io_i2c_del(esp_lcd_panel_io_t *io)

View File

@ -21,6 +21,8 @@
#include "esp_check.h"
#include "freertos/FreeRTOS.h"
#include "esp_heap_caps.h"
#include "esp_compiler.h"
static const char *TAG = "lcd_panel.io.i2c";
#define BYTESHIFT(VAR, IDX) (((VAR) >> ((IDX) * 8)) & 0xFF)
@ -56,6 +58,8 @@ esp_err_t esp_lcd_new_panel_io_i2c_v2(i2c_master_bus_handle_t bus, const esp_lcd
i2c_master_dev_handle_t i2c_handle = NULL;
ESP_GOTO_ON_FALSE(io_config && ret_io, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
ESP_GOTO_ON_FALSE(io_config->control_phase_bytes * 8 > io_config->dc_bit_offset, ESP_ERR_INVALID_ARG, err, TAG, "D/C bit exceeds control bytes");
// leak detection of i2c_panel_io because saving i2c_panel_io->base address
ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE("-Wanalyzer-malloc-leak")
i2c_panel_io = calloc(1, sizeof(lcd_panel_io_i2c_t));
ESP_GOTO_ON_FALSE(i2c_panel_io, ESP_ERR_NO_MEM, err, TAG, "no mem for i2c panel io");
@ -88,6 +92,7 @@ err:
free(i2c_panel_io);
}
return ret;
ESP_COMPILER_DIAGNOSTIC_POP("-Wanalyzer-malloc-leak")
}
static esp_err_t panel_io_i2c_del(esp_lcd_panel_io_t *io)

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -24,6 +24,7 @@
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_compiler.h"
static const char *TAG = "lcd_panel.nt35510";
@ -61,6 +62,8 @@ esp_lcd_new_panel_nt35510(const esp_lcd_panel_io_handle_t io, const esp_lcd_pane
esp_err_t ret = ESP_OK;
nt35510_panel_t *nt35510 = NULL;
ESP_GOTO_ON_FALSE(io && panel_dev_config && ret_panel, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
// leak detection of nt35510 because saving nt35510->base address
ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE("-Wanalyzer-malloc-leak")
nt35510 = calloc(1, sizeof(nt35510_panel_t));
ESP_GOTO_ON_FALSE(nt35510, ESP_ERR_NO_MEM, err, TAG, "no mem for nt35510 panel");
@ -131,6 +134,7 @@ err:
free(nt35510);
}
return ret;
ESP_COMPILER_DIAGNOSTIC_POP("-Wanalyzer-malloc-leak")
}
static esp_err_t panel_nt35510_del(esp_lcd_panel_t *panel)

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -22,6 +22,7 @@
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_compiler.h"
static const char *TAG = "lcd_panel.ssd1306";
@ -73,6 +74,8 @@ esp_err_t esp_lcd_new_panel_ssd1306(const esp_lcd_panel_io_handle_t io, const es
ESP_GOTO_ON_FALSE(io && panel_dev_config && ret_panel, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
ESP_GOTO_ON_FALSE(panel_dev_config->bits_per_pixel == 1, ESP_ERR_INVALID_ARG, err, TAG, "bpp must be 1");
esp_lcd_panel_ssd1306_config_t *ssd1306_spec_config = (esp_lcd_panel_ssd1306_config_t *)panel_dev_config->vendor_config;
// leak detection of ssd1306 because saving ssd1306->base address
ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE("-Wanalyzer-malloc-leak")
ssd1306 = calloc(1, sizeof(ssd1306_panel_t));
ESP_GOTO_ON_FALSE(ssd1306, ESP_ERR_NO_MEM, err, TAG, "no mem for ssd1306 panel");
@ -111,6 +114,7 @@ err:
free(ssd1306);
}
return ret;
ESP_COMPILER_DIAGNOSTIC_POP("-Wanalyzer-malloc-leak")
}
static esp_err_t panel_ssd1306_del(esp_lcd_panel_t *panel)

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -24,6 +24,7 @@
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_compiler.h"
#define ST7789_CMD_RAMCTRL 0xb0
#define ST7789_DATA_LITTLE_ENDIAN_BIT (1 << 3)
@ -66,6 +67,8 @@ esp_lcd_new_panel_st7789(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel
esp_err_t ret = ESP_OK;
st7789_panel_t *st7789 = NULL;
ESP_GOTO_ON_FALSE(io && panel_dev_config && ret_panel, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
// leak detection of st7789 because saving st7789->base address
ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE("-Wanalyzer-malloc-leak")
st7789 = calloc(1, sizeof(st7789_panel_t));
ESP_GOTO_ON_FALSE(st7789, ESP_ERR_NO_MEM, err, TAG, "no mem for st7789 panel");
@ -139,6 +142,7 @@ err:
free(st7789);
}
return ret;
ESP_COMPILER_DIAGNOSTIC_POP("-Wanalyzer-malloc-leak")
}
static esp_err_t panel_st7789_del(esp_lcd_panel_t *panel)

View File

@ -1,22 +1,15 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include <esp_err.h>
#include <esp_log.h>
#include "esp_compiler.h"
#include "esp_local_ctrl.h"
#include "esp_local_ctrl_priv.h"
#include "esp_local_ctrl.pb-c.h"
@ -127,11 +120,13 @@ static esp_err_t cmd_get_prop_vals_handler(LocalCtrlMessage *req,
if (ret == ESP_OK) {
resp_payload->n_props = 0;
for (size_t i = 0; i < req->cmd_get_prop_vals->n_indices; i++) {
ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE("-Wanalyzer-malloc-leak") // False-positive detection. TODO GCC-366
resp_payload->props[i] = malloc(sizeof(PropertyInfo));
if (!resp_payload->props[i]) {
resp_payload->status = STATUS__InternalError;
break;
}
ESP_COMPILER_DIAGNOSTIC_POP("-Wanalyzer-malloc-leak")
resp_payload->n_props++;
property_info__init(resp_payload->props[i]);
resp_payload->props[i]->name = descs[i].name;

View File

@ -17,6 +17,7 @@
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#include "esp_cache.h"
#include "esp_compiler.h"
#include "esp_private/esp_cache_private.h"
#include "esp_private/critical_section.h"
@ -199,8 +200,10 @@ esp_err_t esp_cache_aligned_calloc_prefer(size_t n, size_t size, void **out_ptr,
arg = va_arg(argp, int);
ret = esp_cache_aligned_malloc_internal(size_bytes, arg, &ptr, actual_size);
if (ret == ESP_OK) {
ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE("-Wanalyzer-null-argument")
memset(ptr, 0, size_bytes);
*out_ptr = ptr;
ESP_COMPILER_DIAGNOSTIC_POP("-Wanalyzer-null-argument")
break;
}

View File

@ -14,6 +14,7 @@
#include "esp_log.h"
#include "esp_check.h"
#include "esp_heap_caps.h"
#include "esp_compiler.h"
#include "soc/soc_caps.h"
#include "hal/cache_types.h"
@ -630,9 +631,11 @@ esp_err_t esp_mmu_unmap(void *ptr)
size_t slot_len = 0;
for (int i = 0; i < s_mmu_ctx.num_regions; i++) {
ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE("-Wanalyzer-out-of-bounds")
if (ptr_laddr >= s_mmu_ctx.mem_regions[i].free_head && ptr_laddr < s_mmu_ctx.mem_regions[i].end) {
region = &s_mmu_ctx.mem_regions[i];
}
ESP_COMPILER_DIAGNOSTIC_POP("-Wanalyzer-out-of-bounds")
}
ESP_RETURN_ON_FALSE(region, ESP_ERR_NOT_FOUND, TAG, "munmap target pointer is outside external memory regions");

View File

@ -9,6 +9,7 @@
#include <lwip/ip_addr.h>
#include <lwip/sockets.h>
#include "esp_compiler.h"
#include "esp_check.h"
#include "esp_netif_lwip_internal.h"
#include "lwip/esp_netif_net_stack.h"
@ -859,12 +860,15 @@ static void esp_netif_lwip_remove(esp_netif_t *esp_netif)
static esp_err_t esp_netif_lwip_add(esp_netif_t *esp_netif)
{
ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE("-Wanalyzer-malloc-leak"); // False-positive detection. TODO GCC-366
if (esp_netif->lwip_netif == NULL) {
esp_netif->lwip_netif = calloc(1, sizeof(struct netif));
if (esp_netif->lwip_netif == NULL) {
return ESP_ERR_NO_MEM;
}
}
ESP_COMPILER_DIAGNOSTIC_POP("-Wanalyzer-malloc-leak");
if (esp_netif->flags & ESP_NETIF_FLAG_IS_PPP) {
#if CONFIG_PPP_SUPPORT
err_t err = esp_netif->lwip_init_fn(NULL);

View File

@ -822,12 +822,7 @@ static BaseType_t prvReceiveGeneric(Ringbuffer_t *pxRingbuffer,
BaseType_t xEntryTimeSet = pdFALSE;
TimeOut_t xTimeOut;
#ifdef __clang_analyzer__
// Teach clang-tidy that if NULL pointers are provided, this function will never dereference them
if (!pvItem1 || !pvItem2 || !xItemSize1 || !xItemSize2) {
return pdFALSE;
}
#endif /*__clang_analyzer__ */
ESP_STATIC_ANALYZER_CHECK(!pvItem1 || !pvItem2 || !xItemSize1 || !xItemSize2, pdFALSE);
while (xExitLoop == pdFALSE) {
portENTER_CRITICAL(&pxRingbuffer->mux);
@ -888,12 +883,7 @@ static BaseType_t prvReceiveGenericFromISR(Ringbuffer_t *pxRingbuffer,
{
BaseType_t xReturn = pdFALSE;
#ifdef __clang_analyzer__
// Teach clang-tidy that if NULL pointers are provided, this function will never dereference them
if (!pvItem1 || !pvItem2 || !xItemSize1 || !xItemSize2) {
return pdFALSE;
}
#endif /*__clang_analyzer__ */
ESP_STATIC_ANALYZER_CHECK(!pvItem1 || !pvItem2 || !xItemSize1 || !xItemSize2, pdFALSE);
portENTER_CRITICAL_ISR(&pxRingbuffer->mux);
if (prvCheckItemAvail(pxRingbuffer) == pdTRUE) {

View File

@ -8,6 +8,7 @@
#include "esp_err.h"
#include "esp_attr.h"
#include "esp_compiler.h"
#include "esp_private/system_internal.h"
#include "esp_private/usb_console.h"
@ -221,7 +222,7 @@ static inline void disable_all_wdts(void)
wdt_hal_write_protect_enable(&wdt0_context);
#if SOC_TIMER_GROUPS >= 2
//Interupt WDT is the Main Watchdog Timer of Timer Group 1
//Interrupt WDT is the Main Watchdog Timer of Timer Group 1
wdt_hal_write_protect_disable(&wdt1_context);
wdt_hal_disable(&wdt1_context);
wdt_hal_write_protect_enable(&wdt1_context);
@ -460,7 +461,9 @@ void IRAM_ATTR __attribute__((noreturn, no_sanitize_undefined)) panic_abort(cons
#endif
#endif
ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE("-Wanalyzer-null-dereference")
*((volatile int *) 0) = 0; // NOLINT(clang-analyzer-core.NullDereference) should be an invalid operation on targets
ESP_COMPILER_DIAGNOSTIC_POP("-Wanalyzer-null-dereference")
while (1);
}

View File

@ -9,6 +9,7 @@
#include "esp_attr.h"
#include "esp_err.h"
#include "esp_compiler.h"
#include "esp_system.h"
#include "esp_log.h"
@ -96,10 +97,13 @@ static void do_global_ctors(void)
}
#endif
ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE("-Wanalyzer-out-of-bounds")
for (p = &__init_array_end - 1; p >= &__init_array_start; --p) {
ESP_LOGD(TAG, "calling init function: %p", *p);
(*p)();
}
ESP_COMPILER_DIAGNOSTIC_POP("-Wanalyzer-out-of-bounds")
}
/**

View File

@ -18,6 +18,7 @@
#include "esp_ipc.h"
#include "esp_timer.h"
#include "esp_timer_impl.h"
#include "esp_compiler.h"
#include "esp_private/startup_internal.h"
#include "esp_private/esp_timer_private.h"
@ -215,7 +216,7 @@ esp_err_t IRAM_ATTR esp_timer_start_once(esp_timer_handle_t timer, uint64_t time
timer_list_lock(dispatch_method);
/* Check if the timer is armed once the list is locked.
* Otherwise another task may arm the timer inbetween the check
* Otherwise another task may arm the timer between the checks
* and us locking the list, resulting in us inserting the
* timer to s_timers a second time. This will create a loop
* in s_timers. */
@ -418,9 +419,11 @@ static bool timer_process_alarm(esp_timer_dispatch_t dispatch_method)
while (1) {
it = LIST_FIRST(&s_timers[dispatch_method]);
int64_t now = esp_timer_impl_get_time();
ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE("-Wanalyzer-use-after-free") // False-positive detection. TODO GCC-366
if (it == NULL || it->alarm > now) {
break;
}
ESP_COMPILER_DIAGNOSTIC_POP("-Wanalyzer-use-after-free")
processed = true;
LIST_REMOVE(it, list_entry);
if (it->event_id == EVENT_ID_DELETE_TIMER) {

View File

@ -248,4 +248,12 @@ else()
idf_component_optional_requires(PRIVATE esp_pm)
endif()
if(CONFIG_IDF_TARGET_ESP32P4 AND NOT CONFIG_FREERTOS_SMP AND
CONFIG_COMPILER_STATIC_ANALYZER AND CMAKE_C_COMPILER_ID STREQUAL "GNU") # suppress false-positive warning
set_source_files_properties(
"${kernel_impl}/queue.c"
PROPERTIES COMPILE_OPTIONS
"-Wno-analyzer-null-argument"
)
endif()
endif()

View File

@ -7,6 +7,7 @@
#include "sdkconfig.h"
#include "esp_assert.h"
#include "esp_heap_caps.h"
#include "esp_compiler.h"
#include "freertos/idf_additions.h"
#if CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT
#include "esp_private/freertos_debug.h"
@ -1041,6 +1042,8 @@ int xTaskGetNext( TaskIterator_t * xIterator )
BaseType_t vTaskGetSnapshot( TaskHandle_t pxTask,
TaskSnapshot_t * pxTaskSnapshot )
{
ESP_STATIC_ANALYZER_CHECK(!pxTask, pdFALSE);
if( ( portVALID_TCB_MEM( pxTask ) == false ) || ( pxTaskSnapshot == NULL ) )
{
return pdFALSE;

View File

@ -326,3 +326,8 @@ if(CONFIG_HAL_DEFAULT_ASSERTION_LEVEL EQUAL 1)
elseif(CONFIG_HAL_DEFAULT_ASSERTION_LEVEL EQUAL 2)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u __assert_func")
endif()
if((CONFIG_IDF_TARGET_ESP32H2 OR CONFIG_IDF_TARGET_ESP32S2 OR CONFIG_IDF_TARGET_ESP32S3) AND
CONFIG_COMPILER_STATIC_ANALYZER AND CMAKE_C_COMPILER_ID STREQUAL "GNU") # TODO IDF-10234
target_compile_options(${COMPONENT_LIB} PRIVATE "-fno-analyzer")
endif()

View File

@ -19,6 +19,7 @@
#include "esp_types.h"
#include "esp_attr.h"
#include "esp_bit_defs.h"
#include "esp_compiler.h"
#include "soc/spi_periph.h"
#include "soc/spi_struct.h"
#include "soc/spi_reg.h"
@ -1336,6 +1337,7 @@ static inline void spi_dma_ll_rx_enable_burst_desc(spi_dma_dev_t *dma_in, uint32
__attribute__((always_inline))
static inline uint32_t spi_dma_ll_get_in_suc_eof_desc_addr(spi_dma_dev_t *dma_in, uint32_t channel)
{
ESP_STATIC_ANALYZER_CHECK(!dma_in, -1);
return dma_in->dma_in_suc_eof_des_addr;
}
@ -1437,6 +1439,7 @@ static inline void spi_dma_ll_enable_out_auto_wrback(spi_dma_dev_t *dma_out, uin
__attribute__((always_inline))
static inline uint32_t spi_dma_ll_get_out_eof_desc_addr(spi_dma_dev_t *dma_out, uint32_t channel)
{
ESP_STATIC_ANALYZER_CHECK(!dma_out, -1);
return dma_out->dma_out_eof_des_addr;
}

View File

@ -293,6 +293,9 @@ endif()
foreach(target ${mbedtls_targets})
target_compile_definitions(${target} PUBLIC -DMBEDTLS_CONFIG_FILE="mbedtls/esp_config.h")
if(CONFIG_COMPILER_STATIC_ANALYZER AND CMAKE_C_COMPILER_ID STREQUAL "GNU") # TODO IDF-10087
target_compile_options(${target} PRIVATE "-fno-analyzer")
endif()
endforeach()
if(CONFIG_MBEDTLS_DYNAMIC_BUFFER)

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -71,8 +71,11 @@ out:
}
free(entries);
}
ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE("-Wanalyzer-malloc-leak") // Ignore intended return of allocated *out_dirlist
if (dir_ptr) {
closedir(dir_ptr);
}
return ret;
ESP_COMPILER_DIAGNOSTIC_POP("-Wanalyzer-malloc-leak")
}

View File

@ -41,3 +41,7 @@ else()
target_sources(${COMPONENT_LIB} PRIVATE "src/nvs_encrypted_partition.cpp")
target_link_libraries(${COMPONENT_LIB} PRIVATE idf::mbedtls)
endif()
if(CONFIG_COMPILER_STATIC_ANALYZER AND CMAKE_C_COMPILER_ID STREQUAL "GNU") # TODO IDF-10088
target_compile_options(${COMPONENT_LIB} PUBLIC "-fno-analyzer")
endif()

View File

@ -25,6 +25,7 @@
#include "pthread_internal.h"
#include "esp_pthread.h"
#include "esp_compiler.h"
#include "esp_log.h"
const static char *TAG = "pthread";
@ -165,7 +166,10 @@ esp_err_t esp_pthread_set_cfg(const esp_pthread_cfg_t *cfg)
*p = *cfg;
p->stack_alloc_caps = heap_caps;
pthread_setspecific(s_pthread_cfg_key, p);
ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE("-Wanalyzer-malloc-leak") // ignore leak of 'p'
return 0;
ESP_COMPILER_DIAGNOSTIC_POP("-Wanalyzer-malloc-leak")
}
esp_err_t esp_pthread_get_cfg(esp_pthread_cfg_t *p)

View File

@ -271,6 +271,9 @@ int esp_transport_get_errno(esp_transport_handle_t t)
void capture_tcp_transport_error(esp_transport_handle_t t, enum esp_tcp_transport_err_t error)
{
esp_tls_last_error_t *err_handle = esp_transport_get_error_handle(t);
if (err_handle == NULL) {
return;
}
switch (error) {
case ERR_TCP_TRANSPORT_CONNECTION_CLOSED_BY_FIN:
err_handle->last_error = ESP_ERR_ESP_TLS_TCP_CLOSED_FIN;

View File

@ -61,6 +61,8 @@ static inline transport_esp_tls_t *ssl_get_context_data(esp_transport_handle_t t
static int esp_tls_connect_async(esp_transport_handle_t t, const char *host, int port, int timeout_ms, bool is_plain_tcp)
{
transport_esp_tls_t *ssl = ssl_get_context_data(t);
ESP_STATIC_ANALYZER_CHECK(ssl == NULL, -1);
if (ssl->conn_state == TRANS_SSL_INIT) {
ssl->cfg.timeout_ms = timeout_ms;
ssl->cfg.is_plain_tcp = is_plain_tcp;
@ -101,6 +103,7 @@ static inline int tcp_connect_async(esp_transport_handle_t t, const char *host,
static int ssl_connect(esp_transport_handle_t t, const char *host, int port, int timeout_ms)
{
transport_esp_tls_t *ssl = ssl_get_context_data(t);
ESP_STATIC_ANALYZER_CHECK(ssl == NULL, -1);
ssl->cfg.timeout_ms = timeout_ms;
@ -139,6 +142,7 @@ static int tcp_connect(esp_transport_handle_t t, const char *host, int port, int
{
transport_esp_tls_t *ssl = ssl_get_context_data(t);
esp_tls_last_error_t *err_handle = esp_transport_get_error_handle(t);
ESP_STATIC_ANALYZER_CHECK(ssl == NULL, -1);
ssl->cfg.timeout_ms = timeout_ms;
esp_err_t err = esp_tls_plain_tcp_connect(host, strlen(host), port, &ssl->cfg, err_handle, &ssl->sockfd);
@ -154,6 +158,7 @@ static int tcp_connect(esp_transport_handle_t t, const char *host, int port, int
static int base_poll_read(esp_transport_handle_t t, int timeout_ms)
{
transport_esp_tls_t *ssl = ssl_get_context_data(t);
ESP_STATIC_ANALYZER_CHECK(ssl == NULL, -1);
int ret = -1;
int remain = 0;
struct timeval timeout;
@ -185,6 +190,7 @@ static int base_poll_read(esp_transport_handle_t t, int timeout_ms)
static int base_poll_write(esp_transport_handle_t t, int timeout_ms)
{
transport_esp_tls_t *ssl = ssl_get_context_data(t);
ESP_STATIC_ANALYZER_CHECK(ssl == NULL, -1);
int ret = -1;
struct timeval timeout;
fd_set writeset;
@ -211,6 +217,7 @@ static int ssl_write(esp_transport_handle_t t, const char *buffer, int len, int
{
int poll;
transport_esp_tls_t *ssl = ssl_get_context_data(t);
ESP_STATIC_ANALYZER_CHECK(ssl == NULL, -1);
if ((poll = esp_transport_poll_write(t, timeout_ms)) <= 0) {
ESP_LOGW(TAG, "Poll timeout or error, errno=%s, fd=%d, timeout_ms=%d", strerror(errno), ssl->sockfd, timeout_ms);
@ -233,6 +240,7 @@ static int tcp_write(esp_transport_handle_t t, const char *buffer, int len, int
{
int poll;
transport_esp_tls_t *ssl = ssl_get_context_data(t);
ESP_STATIC_ANALYZER_CHECK(ssl == NULL, -1);
if ((poll = esp_transport_poll_write(t, timeout_ms)) <= 0) {
ESP_LOGW(TAG, "Poll timeout or error, errno=%s, fd=%d, timeout_ms=%d", strerror(errno), ssl->sockfd, timeout_ms);
@ -249,6 +257,7 @@ static int tcp_write(esp_transport_handle_t t, const char *buffer, int len, int
static int ssl_read(esp_transport_handle_t t, char *buffer, int len, int timeout_ms)
{
transport_esp_tls_t *ssl = ssl_get_context_data(t);
ESP_STATIC_ANALYZER_CHECK(ssl == NULL, -1);
int poll = esp_transport_poll_read(t, timeout_ms);
if (poll == -1) {
@ -284,6 +293,7 @@ static int ssl_read(esp_transport_handle_t t, char *buffer, int len, int timeout
static int tcp_read(esp_transport_handle_t t, char *buffer, int len, int timeout_ms)
{
transport_esp_tls_t *ssl = ssl_get_context_data(t);
ESP_STATIC_ANALYZER_CHECK(ssl == NULL, -1);
int poll = esp_transport_poll_read(t, timeout_ms);
if (poll == -1) {
@ -316,6 +326,8 @@ static int base_close(esp_transport_handle_t t)
{
int ret = -1;
transport_esp_tls_t *ssl = ssl_get_context_data(t);
ESP_STATIC_ANALYZER_CHECK(ssl == NULL, -1);
if (ssl && ssl->ssl_initialized) {
ret = esp_tls_conn_destroy(ssl->tls);
ssl->tls = NULL;

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -104,6 +104,8 @@ static esp_transport_handle_t ws_get_payload_transport_handle(esp_transport_hand
static int esp_transport_read_internal(transport_ws_t *ws, char *buffer, int len, int timeout_ms)
{
ESP_STATIC_ANALYZER_CHECK(buffer == NULL, 0);
// No buffered data to read from, directly attempt to read from the transport.
if (ws->buffer_len == 0) {
return esp_transport_read(ws->parent, buffer, len, timeout_ms);

View File

@ -34,3 +34,7 @@ idf_component_register(SRCS ${srcs}
PRIV_INCLUDE_DIRS ${priv_includes}
PRIV_REQUIRES ${priv_requires}
)
if(CONFIG_COMPILER_STATIC_ANALYZER AND CMAKE_C_COMPILER_ID STREQUAL "GNU") # TODO GCC-366 (segfault)
set_property(SOURCE usb_host.c PROPERTY COMPILE_FLAGS -fno-analyzer)
endif()

View File

@ -9,3 +9,7 @@ idf_component_register(SRCS "Partition.cpp"
PRIV_INCLUDE_DIRS private_include
REQUIRES esp_partition
PRIV_REQUIRES spi_flash)
if(CONFIG_COMPILER_STATIC_ANALYZER AND CMAKE_C_COMPILER_ID STREQUAL "GNU") # TODO IDF-10089
target_compile_options(${COMPONENT_LIB} PUBLIC -fno-analyzer)
endif()

View File

@ -231,6 +231,10 @@ idf_component_register(SRCS "${srcs}" "${esp_srcs}" "${tls_src}" "${roaming_src}
PRIV_REQUIRES mbedtls esp_timer esp_wifi)
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-strict-aliasing -Wno-write-strings -Werror)
if(CONFIG_COMPILER_STATIC_ANALYZER AND CMAKE_C_COMPILER_ID STREQUAL "GNU") # TODO IDF-10090
target_compile_options(${COMPONENT_LIB} PRIVATE "-fno-analyzer")
endif()
target_compile_definitions(${COMPONENT_LIB} PRIVATE
__ets__
ESP_SUPPLICANT

View File

@ -0,0 +1,14 @@
Code Quality
============
:link_to_translation:`zh_CN:[中文]`
Code quality refers to how well-written and maintainable a piece of software code is. It encompasses aspects like readability, efficiency, reliability, and adherence to coding standards. High-quality code is easier to understand, modify, and extend, leading to reduced development time and fewer bugs.
Guides
------
.. toctree::
:maxdepth: 2
static-analyzer

View File

@ -0,0 +1,31 @@
Static Analyzer
===============
:link_to_translation:`zh_CN:[中文]`
A static analyzer is a tool that checks source code for errors and vulnerabilities without running it. It helps developers find issues early, improving code quality.
GNU Static Analyzer
-------------------
The GNU Static Analyzer is distributed with GCC (refer to `GCC documentation <https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html>`_). It can be enabled with :ref:`CONFIG_COMPILER_STATIC_ANALYZER` to perform code checks during application builds.
Suppressing Warnings
^^^^^^^^^^^^^^^^^^^^
GNU Static Analyzer is still under development and may give some false-positive warnings. Here is an example of how to suppress unwanted warnings using IDF:
.. code-block:: c
#include "esp_compiler.h"
/* .... */
ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE("-Wanalyzer-null-dereference")
*((volatile int *) 0) = 0;
ESP_COMPILER_DIAGNOSTIC_POP("-Wanalyzer-null-dereference")
/* .... */
Clang Static Analyzer
---------------------
See :doc:`IDF Clang-Tidy <../../api-guides/tools/idf-clang-tidy>`

View File

@ -14,6 +14,7 @@ API Guides
:SOC_SUPPORT_COEXISTENCE: coexist
c
cplusplus
code-quality/index
core_dump
current-consumption-measurement-modules
:SOC_RTC_MEM_SUPPORTED: deep-sleep-stub

View File

@ -0,0 +1 @@
.. include:: ../../../en/api-guides/code-quality/index.rst

View File

@ -0,0 +1 @@
.. include:: ../../../en/api-guides/code-quality/static-analyzer.rst

View File

@ -14,6 +14,7 @@ API 指南
:SOC_SUPPORT_COEXISTENCE: coexist
c
cplusplus
code-quality/index
core_dump
current-consumption-measurement-modules
:SOC_RTC_MEM_SUPPORTED: deep-sleep-stub

View File

@ -407,7 +407,6 @@ components/esp_hid/include/esp_hidh_bluedroid.h
components/esp_hid/include/esp_hidh_gattc.h
components/esp_hid/private/bt_hidd.h
components/esp_hid/private/bt_hidh.h
components/esp_local_ctrl/src/esp_local_ctrl_handler.c
components/esp_local_ctrl/src/esp_local_ctrl_priv.h
components/esp_local_ctrl/src/esp_local_ctrl_transport_ble.c
components/esp_phy/test/test_phy_rtc.c