fix -fanalyzer warnings (from Arm GCC 14.2/15 at least) (#3013)
* fix -fanalyzer warnings (from Arm GCC 14.2/15 at least) - don't plan to fix false positives from earlier versions
* suppress false positive fanalyzer warning that only shows up in release mode
diff --git a/src/common/pico_base_headers/include/pico/assert.h b/src/common/pico_base_headers/include/pico/assert.h
index a9af542..8b84f44 100644
--- a/src/common/pico_base_headers/include/pico/assert.h
+++ b/src/common/pico_base_headers/include/pico/assert.h
@@ -37,7 +37,7 @@
#define invalid_params_if_and_return(x, test, rc) ({if (PARAM_ASSERTIONS_ENABLED(x)) assert(!(test)); if (test) return rc; })
#ifdef NDEBUG
-extern void hard_assertion_failure(void);
+extern void __attribute__((noreturn)) hard_assertion_failure(void);
/*! \brief Perform a runtime assertion always (i.e. not just when NDEBUG is undefined)
* \ingroup pico_base
diff --git a/src/rp2_common/hardware_psram/psram.c b/src/rp2_common/hardware_psram/psram.c
index 0010a67..cad27f5 100644
--- a/src/rp2_common/hardware_psram/psram.c
+++ b/src/rp2_common/hardware_psram/psram.c
@@ -389,7 +389,7 @@
static_assert(FLASH_DEVINFO_SIZE_MAX == FLASH_DEVINFO_SIZE_16M, "expected max region size of 16M");
extern uint32_t __psram_start__;
extern uint32_t __psram_end__;
- uint32_t psram_words = (uint32_t)(&__psram_end__ - &__psram_start__);
+ uint32_t psram_words = ((uintptr_t)&__psram_end__ - (uintptr_t)&__psram_start__) / sizeof(uint32_t);
if (psram_words > psram_word_size) {
// Setup to bus fault for variables that don't fit in available PSRAM
int clear_regions = 0; // Clear no regions by default
diff --git a/src/rp2_common/pico_rand/rand.c b/src/rp2_common/pico_rand/rand.c
index dd539c0..95aedec 100644
--- a/src/rp2_common/pico_rand/rand.c
+++ b/src/rp2_common/pico_rand/rand.c
@@ -224,7 +224,8 @@
bit_done = true;
if (i == n - 1) {
// samples has our random bits, so let's mix them in now
- samples = rosc_samples = (rosc_samples << n) | samples;
+ if (n < 64) samples |= rosc_samples << n;
+ rosc_samples = samples;
}
}
spin_unlock(lock, save);
diff --git a/src/rp2_common/pico_runtime_init/runtime_init.c b/src/rp2_common/pico_runtime_init/runtime_init.c
index 5e1ad04..ca55065 100644
--- a/src/rp2_common/pico_runtime_init/runtime_init.c
+++ b/src/rp2_common/pico_runtime_init/runtime_init.c
@@ -216,7 +216,7 @@
#if !(PICO_NO_RAM_VECTOR_TABLE || PICO_NO_FLASH)
extern uint32_t __vectors;
extern uint32_t __vectors_end;
- uint32_t stored_words = (uint32_t)(&__vectors_end - &__vectors);
+ uint32_t stored_words = ((uintptr_t)&__vectors_end - (uintptr_t)&__vectors) / sizeof(uint32_t);
__builtin_memcpy(ram_vector_table, &__vectors, 4 * MIN(stored_words, PICO_RAM_VECTOR_TABLE_SIZE));
for(uint i = stored_words; i<count_of(ram_vector_table); i++) {
ram_vector_table[i] = (uintptr_t)__unhandled_user_irq;
diff --git a/src/rp2_common/pico_sha256/sha256.c b/src/rp2_common/pico_sha256/sha256.c
index 91009c8..4a69d22 100644
--- a/src/rp2_common/pico_sha256/sha256.c
+++ b/src/rp2_common/pico_sha256/sha256.c
@@ -96,7 +96,11 @@
while (data_size_bytes >= 4) {
// write a whole word
sha256_wait_ready_blocking();
+ // false positive; data_size_bytes does indeed prevent us reading off the end
+GCC_Pragma("GCC diagnostic push")
+GCC_Pragma("GCC diagnostic ignored \"-Wanalyzer-out-of-bounds\"")
sha256_put_word(*data32++);
+GCC_Pragma("GCC diagnostic pop")
data_size_bytes -= 4;
}
data = (const uint8_t *)data32;
diff --git a/src/rp2_common/pico_thread_local/thread_local.c b/src/rp2_common/pico_thread_local/thread_local.c
index 7032730..4974786 100644
--- a/src/rp2_common/pico_thread_local/thread_local.c
+++ b/src/rp2_common/pico_thread_local/thread_local.c
@@ -85,6 +85,8 @@
static inline void _tls_init_from_emutls_or_tdata(void *tls) {
#if PICO_THREAD_LOCAL_SUPPORT_EMUTLS
uint8_t *tls_adjusted = ((uint8_t *)tls) - TLS_ADJUST;
+GCC_Pragma("GCC diagnostic push")
+GCC_Pragma("GCC diagnostic ignored \"-Wanalyzer-out-of-bounds\"")
for (tls_object_t* tls_obj = &__emutls_array_start; tls_obj < &__emutls_array_end; ++tls_obj) {
if (tls_obj->tplate) {
memcpy(tls_adjusted + tls_obj->offset, tls_obj->tplate, tls_obj->size);
@@ -92,6 +94,7 @@
memset(tls_adjusted + tls_obj->offset, 0, tls_obj->size);
}
}
+GCC_Pragma("GCC diagnostic pop")
#endif
#if PICO_THREAD_LOCAL_SUPPORT_THREAD_POINTER
// when using thread pointers we expect data to come from tdata/tbss
@@ -239,15 +242,18 @@
// aligned_alloc is not available in all libraries we support, and it isn't thread safe anyway,
// so we'll just do the padded malloc
// tls = aligned_alloc(size, _emutls_align);
- void *tls = malloc(size + _emutls_align - 1);
- // note we never free the memory, so bumping the pointer is fine
- tls = (void *)((((uintptr_t)tls) + (_emutls_align - 1)) & ~(_emutls_align - 1));
- if (tls) {
+ void *raw = malloc(size + _emutls_align - 1);
+ if (raw) {
+ // note we never free the memory, so bumping the pointer is fine
+ void *tls = (void *)((((uintptr_t)raw) + (_emutls_align - 1)) & ~(_emutls_align - 1));
_init_tls(tls);
_set_tls(tls);
}
}
+GCC_Pragma("GCC diagnostic push")
+GCC_Pragma("GCC diagnostic ignored \"-Wanalyzer-malloc-leak\"")
return _get_tls_adjusted_for_core(core_num);
+GCC_Pragma("GCC diagnostic pop")
}
void* __emutls_get_address(void* obj) {
diff --git a/test/kitchen_sink/kitchen_sink.c b/test/kitchen_sink/kitchen_sink.c
index 0d8e705..398c84a 100644
--- a/test/kitchen_sink/kitchen_sink.c
+++ b/test/kitchen_sink/kitchen_sink.c
@@ -194,13 +194,13 @@
extern uint32_t __load_start_overlay_second;
extern uint32_t __load_stop_overlay_second;
- stored_words = (uint32_t)(&__load_stop_overlay_second - &__load_start_overlay_second);
+ stored_words = ((uintptr_t)&__load_stop_overlay_second - (uintptr_t)&__load_start_overlay_second) / sizeof(uint32_t);
memcpy(&__overlays_start__, &__load_start_overlay_second, 4 * stored_words);
printf("overlay_second after load = %d, %d\n", overlay_second_one, overlay_second_two);
extern uint32_t __load_start_overlay_first;
extern uint32_t __load_stop_overlay_first;
- stored_words = (uint32_t)(&__load_stop_overlay_first - &__load_start_overlay_first);
+ stored_words = ((uintptr_t)&__load_stop_overlay_first - (uintptr_t)&__load_start_overlay_first) / sizeof(uint32_t);
memcpy(&__overlays_start__, &__load_start_overlay_first, 4 * stored_words);
printf("overlay_first after load = %d\n", overlay_first);
printf("overlay_second after overlay_first load = %d, %d\n", overlay_second_one, overlay_second_two);
@@ -211,7 +211,7 @@
extern uint32_t __extra_data_source__;
extern uint32_t __extra_data_start__;
extern uint32_t __extra_data_end__;
- uint32_t stored_words = (uint32_t)(&__extra_data_end__ - &__extra_data_start__);
+ uint32_t stored_words = ((uintptr_t)&__extra_data_end__ - (uintptr_t)&__extra_data_start__) / sizeof(uint32_t);
memcpy(&__extra_data_start__, &__extra_data_source__, 4 * stored_words);
printf("extra_data after load = %d\n", extra_data);
diff --git a/test/kitchen_sink/kitchen_sink_cpp.cpp b/test/kitchen_sink/kitchen_sink_cpp.cpp
index 650d36a..8ec96c4 100644
--- a/test/kitchen_sink/kitchen_sink_cpp.cpp
+++ b/test/kitchen_sink/kitchen_sink_cpp.cpp
@@ -16,8 +16,13 @@
for (const auto &x : sv) {
puts(x);
}
+ // false positive
+GCC_Pragma("GCC diagnostic push")
+GCC_Pragma("GCC diagnostic ignored \"-Wanalyzer-possible-null-dereference\"")
for (const auto &x : vec) {
printf("Number %d\n", x);
}
+GCC_Pragma("GCC diagnostic pop")
}
+
#endif
diff --git a/test/panic_function_test/panic_function_test.c b/test/panic_function_test/panic_function_test.c
index 7e44575..5b6a9e7 100644
--- a/test/panic_function_test/panic_function_test.c
+++ b/test/panic_function_test/panic_function_test.c
@@ -32,41 +32,42 @@
int magic2 = va_arg(args, int);
if (magic2 != MAGIC2) {
printf("magic2 (%08x) != 0x%08x\n", magic2, MAGIC2);
- return;
+ goto done;
}
double magic3 = va_arg(args, double);
if (magic3 != MAGIC3) {
printf("magic3 (%f) != 0x%f\n", magic3, MAGIC3);
- return;
+ goto done;
}
#if PICO_PANIC_FUNCTION_WITH_ALL_VAARGS
printf("checking remaining vaargs...\n");
int magic4 = va_arg(args, int);
if (magic4 != MAGIC4) {
printf("magic4 (%08x) != 0x%08x\n", magic4, MAGIC4);
- return;
+ goto done;
}
int magic5 = va_arg(args, int);
if (magic5 != MAGIC5) {
printf("magic5 (%08x) != 0x%08x\n", magic5, MAGIC5);
- return;
+ goto done;
}
int magic6 = va_arg(args, int);
if (magic6 != MAGIC6) {
printf("magic6 (%08x) != 0x%08x\n", magic6, MAGIC6);
- return;
+ goto done;
}
int magic7 = va_arg(args, int);
if (magic7 != MAGIC7) {
printf("magic7 (%08x) != 0x%08x\n", magic7, MAGIC7);
- return;
+ goto done;
}
#endif
- va_end(args);
puts("PASSED");
#if PICO_PANIC_FUNCTION_DOES_NOT_RETURN
__breakpoint();
#endif
+ done:
+ va_end(args);
}
int main() {
diff --git a/test/pico_divider_test/CMakeLists.txt b/test/pico_divider_test/CMakeLists.txt
index 095d498..f958e87 100644
--- a/test/pico_divider_test/CMakeLists.txt
+++ b/test/pico_divider_test/CMakeLists.txt
@@ -16,6 +16,8 @@
pico_set_divider_implementation(pico_divider_test hardware_explicit) # want to compare against compiler impl
endif()
+ target_compile_options(pico_divider_test PRIVATE -Wno-analyzer-use-of-uninitialized-value)
+
pico_add_extra_outputs(pico_divider_test)
target_compile_definitions(pico_divider_test PRIVATE
diff --git a/test/pico_divider_test/pico_divider_test.c b/test/pico_divider_test/pico_divider_test.c
index 77e1682..7c574fd 100644
--- a/test/pico_divider_test/pico_divider_test.c
+++ b/test/pico_divider_test/pico_divider_test.c
@@ -265,7 +265,6 @@
return div_u64u64(a, b);
}
-
void perf_test() {
*(volatile unsigned int *)0xe000e010=5; // enable SYSTICK at core clock
diff --git a/test/pico_float_test/CMakeLists.txt b/test/pico_float_test/CMakeLists.txt
index 660d0c3..ac7b5a5 100644
--- a/test/pico_float_test/CMakeLists.txt
+++ b/test/pico_float_test/CMakeLists.txt
@@ -63,6 +63,9 @@
target_link_libraries(custom_float_funcs_test_${FLOAT_TYPE} PRIVATE pico_stdlib)
pico_add_extra_outputs(custom_float_funcs_test_${FLOAT_TYPE})
pico_set_printf_implementation(custom_float_funcs_test_${FLOAT_TYPE} compiler)
+ if (PICO_C_COMPILER_IS_GNU)
+ target_compile_options(custom_float_funcs_test_${FLOAT_TYPE} PRIVATE -Wno-analyzer-use-of-uninitialized-value)
+ endif()
if (PICO_C_COMPILER_IS_CLANG)
# llvm by default will treat our out of range float->int conversions as undefined behavior
# and may just decide the function is too broken to bother even with the function epilogue, so we
diff --git a/test/pico_sha256_test/pico_sha256_test.c b/test/pico_sha256_test/pico_sha256_test.c
index 9cd819a..a1bb78d 100644
--- a/test/pico_sha256_test/pico_sha256_test.c
+++ b/test/pico_sha256_test/pico_sha256_test.c
@@ -87,6 +87,7 @@
// nist 3
uint8_t *buffer = malloc(10000);
+ hard_assert(buffer);
memset(buffer, 0x61, BUFFER_SIZE);
const uint8_t nist_3_expected[] = { \
0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 0x81, 0xa1, \
diff --git a/test/pico_time_test/pico_time_test.c b/test/pico_time_test/pico_time_test.c
index 9ed05e2..b42e16e 100644
--- a/test/pico_time_test/pico_time_test.c
+++ b/test/pico_time_test/pico_time_test.c
@@ -126,8 +126,8 @@
}
PICOTEST_CHECK(absolute_time_diff_us(time_base, get_absolute_time()) < init_ms * 1000, "This is a flaky test :-(");
- uint64_t last_fired_at[NUM_ALARMS];
- uint64_t last_target[NUM_ALARMS];
+ uint64_t last_fired_at[NUM_ALARMS] = {};
+ uint64_t last_target[NUM_ALARMS] = {};
memset(&last_fired_at, 0, sizeof(last_fired_at));
printf("Sleeping...\n");
sleep_us(TEST_LENGTH_US + 250000);