From 3a1d168e9e0e3e38adedf5df393e9f8c075fc755 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Mon, 26 Jul 2021 15:25:00 -0400 Subject: [PATCH] analyzer: fix uninit false +ve when returning structs This patch fixes some false positives from -Wanalyzer-use-of-uninitialized-value when returning structs from functions (seen on the Linux kernel). gcc/analyzer/ChangeLog: * region-model.cc (region_model::on_call_pre): Always set conjured LHS, not just for SSA names. gcc/testsuite/ChangeLog: * gcc.dg/analyzer/sock-1.c: New test. * gcc.dg/analyzer/sock-2.c: New test. Signed-off-by: David Malcolm --- gcc/analyzer/region-model.cc | 13 ++-- gcc/testsuite/gcc.dg/analyzer/sock-1.c | 112 +++++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/analyzer/sock-2.c | 20 ++++++ 3 files changed, 137 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/analyzer/sock-1.c create mode 100644 gcc/testsuite/gcc.dg/analyzer/sock-2.c diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index c029759..9d84b8c 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -1066,14 +1066,11 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt, if (tree lhs = gimple_call_lhs (call)) { const region *lhs_region = get_lvalue (lhs, ctxt); - if (TREE_CODE (lhs) == SSA_NAME) - { - const svalue *sval - = m_mgr->get_or_create_conjured_svalue (TREE_TYPE (lhs), call, - lhs_region); - purge_state_involving (sval, ctxt); - set_value (lhs_region, sval, ctxt); - } + const svalue *sval + = m_mgr->get_or_create_conjured_svalue (TREE_TYPE (lhs), call, + lhs_region); + purge_state_involving (sval, ctxt); + set_value (lhs_region, sval, ctxt); } if (gimple_call_internal_p (call)) diff --git a/gcc/testsuite/gcc.dg/analyzer/sock-1.c b/gcc/testsuite/gcc.dg/analyzer/sock-1.c new file mode 100644 index 0000000..0f3e822 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/sock-1.c @@ -0,0 +1,112 @@ +typedef unsigned int __u32; +__extension__ typedef __signed__ long long __s64; +__extension__ typedef unsigned long long __u64; +typedef __u32 u32; +typedef __s64 s64; +typedef __u64 u64; +typedef long long __kernel_time64_t; +typedef _Bool bool; +typedef __s64 time64_t; +struct __kernel_timespec { + __kernel_time64_t tv_sec; + long long tv_nsec; +}; +struct timespec64 { + time64_t tv_sec; + long tv_nsec; +}; + +extern struct timespec64 ns_to_timespec64(const s64 nsec); +int put_timespec64(const struct timespec64 *ts, + struct __kernel_timespec *uts); + +/* [...snip...] */ + +extern int put_old_timespec32(const struct timespec64 *, void *); + +/* [...snip...] */ + +/* [...snip...] */ + +typedef s64 ktime_t; + +/* [...snip...] */ + +extern void ktime_get_real_ts64(struct timespec64 *tv); + +/* [...snip...] */ + +enum tk_offsets { + TK_OFFS_REAL, + TK_OFFS_BOOT, + TK_OFFS_TAI, + TK_OFFS_MAX, +}; + +extern ktime_t ktime_get(void); +extern ktime_t ktime_get_with_offset(enum tk_offsets offs); +extern ktime_t ktime_get_coarse_with_offset(enum tk_offsets offs); +extern ktime_t ktime_mono_to_any(ktime_t tmono, enum tk_offsets offs); +extern ktime_t ktime_get_raw(void); +extern u32 ktime_get_resolution_ns(void); + + +static ktime_t ktime_get_real(void) +{ + return ktime_get_with_offset(TK_OFFS_REAL); +} + +/* [...snip...] */ + +struct socket { + /* [...snip...] */ + struct sock *sk; + /* [...snip...] */ +}; + +/* [...snip...] */ + +struct sock { + /* [...snip...] */ + ktime_t sk_stamp; + /* [...snip...] */ +}; + +/* [...snip...] */ + +static ktime_t sock_read_timestamp(struct sock *sk) +{ + return *(const volatile typeof(sk->sk_stamp) *)&(sk->sk_stamp); +} + +static void sock_write_timestamp(struct sock *sk, ktime_t kt) +{ + *(volatile typeof(sk->sk_stamp) *)&(sk->sk_stamp) = kt; +} + +/* [...snip...] */ + +int sock_gettstamp(struct socket *sock, void *userstamp, + bool timeval, bool time32) +{ + struct sock *sk = sock->sk; + struct timespec64 ts; + + /* [...snip...] */ + ts = ns_to_timespec64((sock_read_timestamp(sk))); + if (ts.tv_sec == -1) + return -2; + if (ts.tv_sec == 0) { + ktime_t kt = ktime_get_real(); + sock_write_timestamp(sk, kt); + ts = ns_to_timespec64((kt)); + } + + if (timeval) + ts.tv_nsec /= 1000; + + + if (time32) + return put_old_timespec32(&ts, userstamp); + return put_timespec64(&ts, userstamp); +} diff --git a/gcc/testsuite/gcc.dg/analyzer/sock-2.c b/gcc/testsuite/gcc.dg/analyzer/sock-2.c new file mode 100644 index 0000000..237e0cb --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/sock-2.c @@ -0,0 +1,20 @@ +__extension__ typedef __signed__ long long __s64; +typedef __s64 time64_t; +struct timespec64 { + time64_t tv_sec; + long tv_nsec; +}; + +extern struct timespec64 ns_to_timespec64(void); + +int sock_gettstamp() +{ + struct timespec64 ts; + + /* [...snip...] */ + ts = ns_to_timespec64(); + if (ts.tv_sec == -1) + return -2; + /* [...snip...] */ + return 0; +} -- 2.7.4