diff --git a/dev/cppcheck/cppcheck_test.c b/dev/cppcheck/cppcheck_test.c new file mode 100644 index 0000000000000..bee611ce9ef3d --- /dev/null +++ b/dev/cppcheck/cppcheck_test.c @@ -0,0 +1,65 @@ +/* + * Minimal reproducer for a cppcheck false positive. + * + * cppcheck incorrectly reports a memory leak for the pattern below. + * The pointer is a local copy of ptr>. When realloc() + * fails and returns NULL, becomes NULL, but the original + * allocation is still referenced by ptr>. The failure branch then + * uses ptr> to properly free the original memory, so there is no + * real leak. + * + * Reference: https://www.mail-archive.com/haproxy@formilux.org/msg46968.html + * Origin: src/quic_rx.c, function qc_try_store_new_token() + */ + +#include +#include + +struct buf { + char *ptr; + size_t len; +}; + +static inline char *buf_ptr(struct buf b) { return b.ptr; } +static inline size_t buf_len(struct buf b) { return b.len; } +static inline void buf_free(struct buf *b) { free(b->ptr); b->ptr = NULL; b->len = 0; } + +/* Update the raw-byte buffer with of length , reallocating + * when needed. The buffer stores raw bytes; no null terminator is appended. + * + * False positive: cppcheck may report a memleak at the realloc() line because + * it sees (a local variable) overwritten with the NULL return value + * of realloc() and concludes the original allocation is lost. In reality the + * original pointer is preserved in ptr> and properly freed in the else + * branch, so no leak can occur. + */ +static void update_buf(struct buf *b, const char *data, size_t len) +{ + char *local_ptr; + + local_ptr = buf_ptr(*b); + if (len > buf_len(*b)) { + local_ptr = realloc(local_ptr, len); + if (local_ptr) + b->ptr = local_ptr; + else { + memset(buf_ptr(*b), 0, buf_len(*b)); + buf_free(b); + } + } + + if (local_ptr) { + memcpy(local_ptr, data, len); + b->len = len; + } +} + +int main(void) +{ + struct buf b = { NULL, 0 }; + + update_buf(&b, "hello", 5); + update_buf(&b, "world!", 6); + buf_free(&b); + return 0; +} diff --git a/src/cpuset.c b/src/cpuset.c index f85c31b9c967d..d21c849c32d7e 100644 --- a/src/cpuset.c +++ b/src/cpuset.c @@ -28,6 +28,8 @@ int ha_cpuset_set(struct hap_cpuset *set, int cpu) set->cpuset |= (0x1 << cpu); return 0; #endif + + return 1; } int ha_cpuset_clr(struct hap_cpuset *set, int cpu) @@ -43,6 +45,8 @@ int ha_cpuset_clr(struct hap_cpuset *set, int cpu) set->cpuset &= ~(0x1 << cpu); return 0; #endif + + return 1; } void ha_cpuset_and(struct hap_cpuset *dst, struct hap_cpuset *src) @@ -97,6 +101,8 @@ int ha_cpuset_count(const struct hap_cpuset *set) #elif defined(CPUSET_USE_ULONG) return my_popcountl(set->cpuset); #endif + + return 0; } int ha_cpuset_ffs(const struct hap_cpuset *set) @@ -121,6 +127,8 @@ int ha_cpuset_ffs(const struct hap_cpuset *set) return my_ffsl(set->cpuset); #endif + + return 0; } void ha_cpuset_assign(struct hap_cpuset *dst, struct hap_cpuset *src) @@ -149,6 +157,8 @@ int ha_cpuset_isequal(const struct hap_cpuset *dst, const struct hap_cpuset *src #elif defined(CPUSET_USE_ULONG) return dst->cpuset == src->cpuset; #endif + + return 0; } int ha_cpuset_size() @@ -160,6 +170,8 @@ int ha_cpuset_size() return LONGBITS; #endif + + return 0; } /* Parse cpu sets. Each CPU set is either a unique number between 0 and