analyzer: fix defaults in compound assignments from non-zero offsets [PR112969]

Confusion in binding_cluster::maybe_get_compound_binding about whether
offsets are relative to the start of the region or to the start of the
cluster was leading to incorrect handling of default values, leading
to false positives from -Wanalyzer-use-of-uninitialized-value, from
-Wanalyzer-exposure-through-uninit-copy, and other logic errors.

Fixed thusly.

gcc/analyzer/ChangeLog:
	PR analyzer/112969
	* store.cc (binding_cluster::maybe_get_compound_binding): When
	populating default_map, express the bit-range of the default key
	for REG relative to REG, rather than to the base region.

gcc/testsuite/ChangeLog:
	PR analyzer/112969
	* c-c++-common/analyzer/compound-assignment-5.c (test_3): Remove
	xfails, reorder tests.
	* c-c++-common/analyzer/compound-assignment-pr112969.c: New test.
	* gcc.dg/plugin/infoleak-pr112969.c: New test.
	* gcc.dg/plugin/plugin.exp: Add infoleak-pr112969.c to
	analyzer_kernel_plugin.c tests.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
This commit is contained in:
David Malcolm 2024-01-25 10:06:12 -05:00
parent 4ffcceef81
commit 6426d46677
5 changed files with 99 additions and 3 deletions

View file

@ -1759,7 +1759,16 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr,
else
default_sval = sval_mgr->get_or_create_initial_value (reg);
const binding_key *default_key = binding_key::make (mgr, reg);
default_map.put (default_key, default_sval);
/* Express the bit-range of the default key for REG relative to REG,
rather than to the base region. */
const concrete_binding *concrete_default_key
= default_key->dyn_cast_concrete_binding ();
if (!concrete_default_key)
return nullptr;
const concrete_binding *default_key_relative_to_reg
= mgr->get_concrete_binding (0, concrete_default_key->get_size_in_bits ());
default_map.put (default_key_relative_to_reg, default_sval);
for (map_t::iterator iter = m_map.begin (); iter != m_map.end (); ++iter)
{

View file

@ -48,9 +48,8 @@ void test_3 (void)
glob_arr3[7] = arr[3]; // or should the uninit warning be here?
__analyzer_eval (glob_arr3[7].x); /* { dg-warning "uninitialized" "uninit" { xfail *-*-* } } */
/* { dg-bogus "UNKNOWN" "unknown" { xfail *-*-* } .-1 } */
__analyzer_eval (glob_arr3[7].y == 6); /* { dg-warning "TRUE" } */
__analyzer_eval (glob_arr3[7].x); /* { dg-warning "uninitialized" "uninit" } */
}
/* Symbolic bindings: copying from one array to another. */

View file

@ -0,0 +1,35 @@
/* Reduced from -Wanalyzer-exposure-through-uninit-copy false positives
seen in Linux kernel in drivers/net/ethernet/intel/ice/ice_ptp.c */
#include "analyzer-decls.h"
/* { dg-do compile } */
struct hwtstamp_config
{
int flags;
int tx_type;
int rx_filter;
};
struct ice_ptp
{
long placeholder;
struct hwtstamp_config tstamp_config;
};
struct ice_pf
{
struct ice_ptp ptp;
};
void
ice_ptp_set_ts_config(struct ice_pf* pf)
{
struct hwtstamp_config config;
pf->ptp.tstamp_config.tx_type = 1;
pf->ptp.tstamp_config.rx_filter = 2;
config = pf->ptp.tstamp_config;
__analyzer_eval (config.flags == pf->ptp.tstamp_config.flags); /* { dg-warning "TRUE" } */
/* { dg-bogus "use of uninitialized value 'config.flags'" "PR analyzer/112969" { target *-*-* } .-1 } */
}

View file

@ -0,0 +1,52 @@
/* Reduced from -Wanalyzer-exposure-through-uninit-copy false positives
seen in Linux kernel in drivers/net/ethernet/intel/ice/ice_ptp.c */
/* { dg-do compile } */
/* { dg-options "-fanalyzer" } */
/* { dg-require-effective-target analyzer } */
extern unsigned long
copy_from_user(void* to, const void* from, unsigned long n);
extern unsigned long
copy_to_user(void* to, const void* from, unsigned long n);
struct ifreq
{
union
{
void* ifru_data;
} ifr_ifru;
};
struct hwtstamp_config
{
int flags;
int tx_type;
int rx_filter;
};
struct ice_ptp
{
long placeholder;
struct hwtstamp_config tstamp_config;
};
struct ice_pf
{
struct ice_ptp ptp;
};
int
ice_ptp_set_ts_config(struct ice_pf* pf, struct ifreq* ifr)
{
struct hwtstamp_config config;
int err;
if (copy_from_user(&config, ifr->ifr_ifru.ifru_data, sizeof(config)))
return -14;
pf->ptp.tstamp_config.tx_type = 0;
pf->ptp.tstamp_config.rx_filter = 0;
config = pf->ptp.tstamp_config;
if (copy_to_user(ifr->ifr_ifru.ifru_data, &config, sizeof(config))) /* { dg-bogus "-Wanalyzer-exposure-through-uninit-copy" "PR analyzer/112969" } */
return -14;
return 0;
}

View file

@ -150,6 +150,7 @@ set plugin_test_list [list \
infoleak-CVE-2017-18550-1.c \
infoleak-antipatterns-1.c \
infoleak-fixit-1.c \
infoleak-pr112969.c \
infoleak-uninit-size-1.c \
infoleak-uninit-size-2.c \
infoleak-net-ethtool-ioctl.c \