analyzer: fix further overzealous state purging [PR108733]

PR analyzer/108733 reports various false positives in qemu from
-Wanalyzer-use-of-uninitialized-value with __attribute__((cleanup))
at -O1 and above.

Root cause is that the state-purging code was failing to treat:
   _25 = MEM[(void * *)&val];
as a usage of "val", leading to it erroneously purging the
initialization of "val" along an execution path that didn't otherwise
use "val", apart from the  __attribute__((cleanup)).

Fixed thusly.

Integration testing on the patch show this change in the number of
diagnostics:
  -Wanalyzer-use-of-uninitialized-value
       coreutils-9.1: 18 -> 16 (-2)
          qemu-7.2.0: 87 -> 80 (-7)
where all that I investigated appear to have been false positives, hence
an improvement.

gcc/analyzer/ChangeLog:
	PR analyzer/108733
	* state-purge.cc (get_candidate_for_purging): Add ADDR_EXPR
	and MEM_REF.

gcc/testsuite/ChangeLog:
	PR analyzer/108733
	* gcc.dg/analyzer/torture/uninit-pr108733.c: New test.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
This commit is contained in:
David Malcolm 2023-02-09 17:09:51 -05:00
parent 10827a92f1
commit 125b57aa67
2 changed files with 67 additions and 0 deletions

View file

@ -63,6 +63,8 @@ get_candidate_for_purging (tree node)
default:
return NULL_TREE;
case ADDR_EXPR:
case MEM_REF:
case COMPONENT_REF:
iter = TREE_OPERAND (iter, 0);
continue;

View file

@ -0,0 +1,65 @@
#define NULL ((void*)0)
typedef unsigned char __uint8_t;
typedef __uint8_t uint8_t;
typedef char gchar;
typedef void* gpointer;
extern void g_free(gpointer mem);
extern gchar* g_strdup(const gchar* str) __attribute__((__malloc__));
static inline void
g_autoptr_cleanup_generic_gfree(void* p)
{
void** pp = (void**)p;
g_free(*pp); /* { dg-bogus "use of uninitialized value" } */
}
typedef struct Object Object;
void
error_setg_internal(const char* fmt,
...) __attribute__((__format__(gnu_printf, 1, 2)));
void
visit_type_str(const char* name, char** obj);
typedef struct SpaprMachineState SpaprMachineState;
extern uint8_t
spapr_get_cap(SpaprMachineState* spapr, int cap);
typedef struct SpaprCapPossible
{
int num;
/* [...snip...] */
const char* vals[];
} SpaprCapPossible;
typedef struct SpaprCapabilityInfo
{
const char* name;
/* [...snip...] */
int index;
/* [...snip...] */
SpaprCapPossible* possible;
/* [...snip...] */
} SpaprCapabilityInfo;
void
spapr_cap_get_string(SpaprMachineState* spapr,
const char* name,
SpaprCapabilityInfo* cap)
{
__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char* val = NULL;
uint8_t value = spapr_get_cap(spapr, cap->index);
if (value >= cap->possible->num) {
error_setg_internal("Invalid value (%d) for cap-%s",
value,
cap->name);
return;
}
val = g_strdup(cap->possible->vals[value]);
visit_type_str(name, &val);
}