From patchwork Fri Mar 18 23:23:56 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 1607295 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=cSHuAYzB; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4KL0TQ47kZz9sCD for ; Sat, 19 Mar 2022 10:24:24 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 6B5DD3888C6B for ; Fri, 18 Mar 2022 23:24:22 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6B5DD3888C6B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1647645862; bh=AhdBhS74eM3Q8PEH3A+7by137mkvfI5wBYBuftsP20M=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=cSHuAYzBSWJELwP9spjJBlGDlweCQgL04X04zML4QfakoH8TA3kRBwOZqmAsROTvp X/BXAy6JZtjbwnePJWYsIpXFvyfsufh6q1UUgAR9uCSf4wbk3v3yVZ9cwwnNBooL2J THKRZC9UnbPr3HeYLuFe3Oy0RSwXhlnxEOEfmxMA= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 8B4D63888C57 for ; Fri, 18 Mar 2022 23:24:00 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 8B4D63888C57 Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-658-84nBtRI-Mn64G3BvRZli3A-1; Fri, 18 Mar 2022 19:23:58 -0400 X-MC-Unique: 84nBtRI-Mn64G3BvRZli3A-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 91813802803 for ; Fri, 18 Mar 2022 23:23:58 +0000 (UTC) Received: from t14s.localdomain.com (unknown [10.2.17.210]) by smtp.corp.redhat.com (Postfix) with ESMTP id 6270453CD; Fri, 18 Mar 2022 23:23:58 +0000 (UTC) To: gcc-patches@gcc.gnu.org Subject: [committed] analyzer: add tests of boxed values [PR104943] Date: Fri, 18 Mar 2022 19:23:56 -0400 Message-Id: <20220318232356.67826-1-dmalcolm@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: David Malcolm via Gcc-patches From: David Malcolm Reply-To: David Malcolm Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" This patch adds various regression tests as preparatory work for purging irrelevant local decls from state (PR analyzer/104943) Tested on x86_64-pc-linux-gnu. Pushed to trunk as r12-7717-g1c1daca1cdf7bc0156d57bb2b9083ee70c66b000. gcc/testsuite/ChangeLog: PR analyzer/104943 * gcc.dg/analyzer/boxed-malloc-1-29.c: New test. * gcc.dg/analyzer/boxed-malloc-1.c: New test. * gcc.dg/analyzer/taint-alloc-5.c: New test. * gcc.dg/analyzer/torture/boxed-int-1.c: New test. * gcc.dg/analyzer/torture/boxed-ptr-1.c: New test. Signed-off-by: David Malcolm --- .../gcc.dg/analyzer/boxed-malloc-1-29.c | 36 ++ .../gcc.dg/analyzer/boxed-malloc-1.c | 476 ++++++++++++++++++ gcc/testsuite/gcc.dg/analyzer/taint-alloc-5.c | 21 + .../gcc.dg/analyzer/torture/boxed-int-1.c | 170 +++++++ .../gcc.dg/analyzer/torture/boxed-ptr-1.c | 82 +++ 5 files changed, 785 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/analyzer/boxed-malloc-1-29.c create mode 100644 gcc/testsuite/gcc.dg/analyzer/boxed-malloc-1.c create mode 100644 gcc/testsuite/gcc.dg/analyzer/taint-alloc-5.c create mode 100644 gcc/testsuite/gcc.dg/analyzer/torture/boxed-int-1.c create mode 100644 gcc/testsuite/gcc.dg/analyzer/torture/boxed-ptr-1.c diff --git a/gcc/testsuite/gcc.dg/analyzer/boxed-malloc-1-29.c b/gcc/testsuite/gcc.dg/analyzer/boxed-malloc-1-29.c new file mode 100644 index 00000000000..9e38f97fc8e --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/boxed-malloc-1-29.c @@ -0,0 +1,36 @@ +/* Isolating this false positive from boxed-malloc-1.c since it's + reported within boxed_malloc. */ + +#include + +typedef struct boxed_ptr { void *value; } boxed_ptr; + +boxed_ptr +boxed_malloc (size_t sz) +{ + boxed_ptr result; + result.value = malloc (sz); + return result; /* { dg-bogus "leak" "leak false +ve (PR analyzer/104979)" { xfail *-*-* } } */ +} + +boxed_ptr +boxed_free (boxed_ptr ptr) +{ + free (ptr.value); +} + +const boxed_ptr boxed_null = {NULL}; + +struct link +{ + boxed_ptr m_ptr; +}; + +boxed_ptr test_29 (void) +{ + boxed_ptr res = boxed_malloc (sizeof (struct link)); + if (!res.value) + return boxed_null; + ((struct link *)res.value)->m_ptr = boxed_malloc (sizeof (struct link)); + return res; +} diff --git a/gcc/testsuite/gcc.dg/analyzer/boxed-malloc-1.c b/gcc/testsuite/gcc.dg/analyzer/boxed-malloc-1.c new file mode 100644 index 00000000000..5428f2baf49 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/boxed-malloc-1.c @@ -0,0 +1,476 @@ +/* Adapted from malloc-1.c, but wrapping the pointers in a struct. */ + +/* { dg-require-effective-target alloca } */ + +#include + +extern int foo (void); +extern int bar (void); +extern void could_free (void *); +extern void cant_free (const void *); /* since it's a const void *. */ + +typedef struct boxed_ptr { void *value; } boxed_ptr; + +boxed_ptr +boxed_malloc (size_t sz) +{ + boxed_ptr result; + result.value = malloc (sz); + return result; +} + +boxed_ptr +boxed_free (boxed_ptr ptr) +{ + free (ptr.value); +} + +const boxed_ptr boxed_null = {NULL}; + +void test_1 (void) +{ + boxed_ptr ptr; + ptr.value = malloc (1024); + free (ptr.value); + free (ptr.value); /* { dg-warning "double-'free' of 'ptr.value'" } */ +} + +void test_2 (boxed_ptr ptr) +{ + free (ptr.value); + free (ptr.value); /* { dg-warning "double-'free' of 'ptr.value'" } */ +} + +boxed_ptr +test_3 (void) +{ + boxed_ptr ptr; + ptr.value = malloc (sizeof (int)); + *(int *)ptr.value = 42; /* { dg-warning "dereference of possibly-NULL 'ptr.value' \\\[CWE-690\\\]" } */ + return ptr; +} + +boxed_ptr +test_4 (void) +{ + boxed_ptr ptr; + ptr.value = malloc (sizeof (int)); + int *iptr = (int *)ptr.value; + if (iptr) + *iptr = 42; + else + *iptr = 43; /* { dg-warning "dereference of NULL 'iptr' \\\[CWE-476\\\]" } */ + return ptr; +} + +int test_5 (boxed_ptr ptr) +{ + free (ptr.value); + return *(int *)ptr.value; /* { dg-warning "use after 'free' of 'ptr.value'" } */ +} + +void test_6 (void *ptr) +{ + boxed_ptr q; + q.value = ptr; + free (ptr); + free (q.value); /* { dg-warning "double-'free' of 'ptr'" } */ +} + +void test_6a (boxed_ptr ptr) +{ + boxed_ptr q; + q = ptr; + boxed_free (ptr); + free (q.value); /* { dg-warning "double-'free' of 'ptr.value'" } */ +} + +void test_7 (void) +{ + boxed_ptr ptr = boxed_malloc(4096); + if (!ptr.value) + return; + __builtin_memset(ptr.value, 0, 4096); + boxed_free(ptr); +} + +boxed_ptr test_8 (void) +{ + boxed_ptr ptr = boxed_malloc(4096); + if (!ptr.value) + return boxed_null; + __builtin_memset(ptr.value, 0, 4096); + return ptr; +} + +void test_9 (void) +{ + boxed_ptr ptr = boxed_malloc (1024); + + int i; + for (i = 0; i < 1024; i++) + free (ptr.value); /* { dg-warning "double-'free' of 'ptr.value'" } */ +} + +void test_10 (void) +{ + boxed_ptr ptr = boxed_malloc (1024); + + int i; + for (i = 0; i < 1024; i++) + foo (); + + free (ptr.value); + free (ptr.value); /* { dg-warning "double-'free' of 'ptr.value'" } */ +} + +void test_11 (void) +{ + boxed_ptr ptr = boxed_malloc (1024); + + while (foo ()) + bar (); + + free (ptr.value); + free (ptr.value); /* { dg-warning "double-'free' of 'ptr.value'" } */ +} + +void test_12 (void) +{ + boxed_ptr ptr = boxed_malloc (1024); + + while (1) + { + free (ptr.value); + free (ptr.value); /* { dg-warning "double-'free' of 'ptr.value'" } */ + } +} + +void test_13 (void) +{ + boxed_ptr p = boxed_malloc (1024); + boxed_ptr q = boxed_malloc (1024); + + foo (); + if (!q.value) + { + boxed_free (q); + return; /* { dg-warning "leak of 'p.value'" } */ + } + bar (); + boxed_free (q); + boxed_free (p); +} + +void test_14 (void) +{ + boxed_ptr p, q; + p = boxed_malloc (1024); + if (!p.value) + return; + + q = boxed_malloc (1024); + if (!q.value) + { + boxed_free (p); + boxed_free (q); + /* oops: missing "return". */ + } + bar (); + boxed_free (q); /* Although this looks like a double-'free' of q, + it's known to be NULL for the case where free is + called twice on it. */ + free (p.value); /* { dg-warning "double-'free' of 'p.value'" } */ +} + +void test_15 (void) +{ + boxed_ptr p, q; + p.value = NULL; + q.value = NULL; + + p = boxed_malloc (1024); + if (!p.value) + goto fail; + + foo (); + + q = boxed_malloc (1024); + if (!q.value) + goto fail; + + bar (); + + fail: + boxed_free (q); + boxed_free (p); +} + +void test_16 (void) +{ + boxed_ptr p, q; /* { dg-message "region created on stack here" } */ + + p = boxed_malloc (1024); + if (!p.value) + goto fail; + + foo (); + + q = boxed_malloc (1024); + if (!q.value) + goto fail; + + bar (); + + fail: + boxed_free (q); /* { dg-warning "use of uninitialized value 'q'" } */ + boxed_free (p); +} + +void test_17 (void) +{ + boxed_ptr ptr = boxed_malloc (1024); +} /* { dg-warning "leak of 'ptr.value'" } */ + +void test_18 (void) +{ + boxed_ptr ptr = boxed_malloc (64); + ptr = boxed_null; /* { dg-warning "leak of 'ptr.value'" } */ +} + +void test_18a (void) +{ + boxed_ptr ptr = boxed_malloc (64); + ptr.value = NULL; /* { dg-warning "leak of 'ptr.value'" } */ +} + +void test_19 (void) +{ + boxed_ptr ptr = boxed_malloc (64); + free (ptr.value); + ptr.value = NULL; + free (ptr.value); +} + +boxed_ptr global_ptr_20; + +void test_20 (void) +{ + global_ptr_20 = boxed_malloc (1024); +} + +int *test_21 (int i) +{ + boxed_ptr ptr = boxed_malloc (sizeof (int)); + if (!ptr.value) + abort (); + *(int *)ptr.value = i; + return ptr.value; +} + +boxed_ptr test_21a (int i) +{ + boxed_ptr ptr = boxed_malloc (sizeof (int)); + if (!ptr.value) + abort (); + *(int *)ptr.value = i; + return ptr; +} + +void test_22 (void) +{ + boxed_ptr ptr = boxed_malloc (1024); + + int i; + for (i = 5; i < 10; i++) + foo (); + + free (ptr.value); + free (ptr.value); /* { dg-warning "double-'free' of 'ptr.value'" } */ +} + +int test_24 (void) +{ + boxed_ptr ptr; + ptr.value = __builtin_alloca (sizeof (int)); /* { dg-message "region created on stack here" } */ + free (ptr.value); /* { dg-warning "'free' of 'ptr.value' which points to memory on the stack \\\[CWE-590\\\]" } */ +} + +int test_25 (void) +{ + char tmp[100]; /* { dg-message "region created on stack here" } */ + boxed_ptr p; + p.value = tmp; + free (p.value); /* { dg-warning "'free' of '&tmp' which points to memory on the stack \\\[CWE-590\\\]" } */ +} + +char global_buffer[100]; /* { dg-message "region created here" } */ + +int test_26 (void) +{ + boxed_ptr p; + p.value = global_buffer; + free (p.value); /* { dg-warning "'free' of '&global_buffer' which points to memory not on the heap \\\[CWE-590\\\]" } */ +} + +struct coord { + float x; + float y; +}; + +boxed_ptr test_27 (void) +{ + boxed_ptr p = boxed_malloc (sizeof (struct coord)); + ((struct coord *)p.value)->x = 0.f; /* { dg-warning "dereference of possibly-NULL 'p.value' \\\[CWE-690\\\]" } */ + + /* Only the first such usage should be reported: */ + ((struct coord *)p.value)->y = 0.f; + + return p; +} + +struct link +{ + boxed_ptr m_ptr; +}; + +void test_31 (void) +{ + struct link tmp; + boxed_ptr ptr = boxed_malloc (sizeof (struct link)); + tmp.m_ptr = ptr; +} /* { dg-warning "leak" } */ + +void test_32 (void) +{ + boxed_ptr ptr = boxed_malloc (1024); + could_free (ptr.value); +} /* { dg-bogus "leak" } */ + +void test_33 (void) +{ + boxed_ptr ptr = boxed_malloc (1024); + cant_free (ptr.value); +} /* { dg-warning "leak of 'ptr.value'" } */ + +void test_34 (void) +{ + float *q; + boxed_ptr p = boxed_malloc (sizeof (struct coord)); + if (!p.value) + return; + ((struct coord *)p.value)->x = 0.0f; + q = &((struct coord *)p.value)->x; + boxed_free (p); + *q = 1.0f; /* { dg-warning "use after 'free' of 'q'" } */ +}; + +int test_35 (void) +{ + boxed_ptr ptr = boxed_malloc(4096); + if (!ptr.value) + return -1; + __builtin_memset(ptr.value, 0, 4096); + boxed_free(ptr); + return 0; +} + +void test_36 (void) +{ + boxed_ptr ptr = boxed_malloc(4096); + if (!ptr.value) + return; + __builtin_memset(ptr.value, 0, 4096); + boxed_free(ptr); +} + +boxed_ptr test_37a (void) +{ + boxed_ptr ptr = boxed_malloc(4096); + __builtin_memset(ptr.value, 0, 4096); /* { dg-warning "use of possibly-NULL 'ptr.value' where non-null expected \\\[CWE-690\\\]" } */ + return ptr; +} + +int test_37b (void) +{ + boxed_ptr p = boxed_malloc(4096); + boxed_ptr q = boxed_malloc(4096); + if (p.value) { + __builtin_memset(p.value, 0, 4096); /* Not a bug: checked */ + } else { + __builtin_memset(q.value, 0, 4096); /* { dg-warning "use of possibly-NULL 'q.value' where non-null expected \\\[CWE-690\\\]" } */ + } + boxed_free(p); + boxed_free(q); + return 0; +} + +extern void might_use_ptr (void *ptr); + +void test_38(int i) +{ + boxed_ptr p; + + p = boxed_malloc(1024); + if (p.value) { + boxed_free(p); + might_use_ptr(p.value); /* { dg-warning "use after 'free' of 'p.value'" "" { xfail *-*-* } } */ + // TODO: xfail + } +} + +boxed_ptr +test_39 (int i) +{ + boxed_ptr p = boxed_malloc(sizeof(int*)); + *(int *)p.value = i; /* { dg-warning "dereference of possibly-NULL 'p.value' \\\[CWE-690\\\]" } */ + return p; +} + +boxed_ptr +test_41 (int flag) +{ + boxed_ptr buffer; + + if (flag) { + buffer = boxed_malloc(4096); + } else { + buffer = boxed_null; + } + + ((char *)buffer.value)[0] = 'a'; /* { dg-warning "dereference of possibly-NULL 'buffer.value' \\\[CWE-690\\\]" "possibly-NULL" } */ + /* { dg-warning "dereference of NULL" "NULL" { target *-*-* } .-1 } */ + + return buffer; +} + +extern void might_take_ownership (boxed_ptr ptr); + +void test_45 (void) +{ + boxed_ptr p = boxed_malloc (1024); + might_take_ownership (p); +} + +/* Free of function, and of label within function. */ + +void test_50a (void) +{ +} + +void test_50b (void) +{ + boxed_ptr ptr; + ptr.value = test_50a; + free (ptr.value); /* { dg-warning "'free' of '&test_50a' which points to memory not on the heap \\\[CWE-590\\\]" } */ +} + +void test_50c (void) +{ + my_label: + boxed_ptr ptr; + ptr.value = &&my_label; + free (ptr.value); /* { dg-warning "'free' of '&my_label' which points to memory not on the heap \\\[CWE-590\\\]" } */ +} + +/* { dg-prune-output "\\\[-Wfree-nonheap-object" } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/taint-alloc-5.c b/gcc/testsuite/gcc.dg/analyzer/taint-alloc-5.c new file mode 100644 index 00000000000..9a159800c61 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/taint-alloc-5.c @@ -0,0 +1,21 @@ +// TODO: remove need for this option +/* { dg-additional-options "-fanalyzer-checker=taint" } */ + +#include "analyzer-decls.h" + +struct foo +{ + int num; +}; + +/* malloc with tainted size from a field. */ + +void * __attribute__ ((tainted_args)) +test_1 (struct foo f) +{ + __analyzer_dump_state ("taint", f.num); /* { dg-warning "state: 'tainted'" } */ + __analyzer_dump_state ("taint", f.num * 16); /* { dg-warning "state: 'tainted'" } */ + + return __builtin_malloc (f.num * 16); /* { dg-warning "use of attacker-controlled value 'f\\.num \\* 16' as allocation size without upper-bounds checking" "warning" } */ + /* { dg-message "\\(\[0-9\]+\\) use of attacker-controlled value 'f\\.num \\* 16' as allocation size without upper-bounds checking" "final event with expr" { target *-*-* } .-1 } */ +} diff --git a/gcc/testsuite/gcc.dg/analyzer/torture/boxed-int-1.c b/gcc/testsuite/gcc.dg/analyzer/torture/boxed-int-1.c new file mode 100644 index 00000000000..94111e66a8b --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/torture/boxed-int-1.c @@ -0,0 +1,170 @@ +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } { "" } } */ + +#include "../analyzer-decls.h" + +typedef struct boxed_int { int value; } boxed_int; + +extern boxed_int boxed_int_add (boxed_int a, boxed_int b); +extern boxed_int boxed_int_mul (boxed_int a, boxed_int b); + +boxed_int __attribute__((noinline)) +noinline_boxed_int_add (boxed_int a, boxed_int b) +{ + boxed_int result; + result.value = a.value + b.value; + return result; +} + +static inline boxed_int +inline_boxed_int_add (boxed_int a, boxed_int b) +{ + boxed_int result; + result.value = a.value + b.value; + return result; +} + +boxed_int +test_1 (boxed_int a, boxed_int b) +{ + boxed_int result = boxed_int_add (boxed_int_mul (a, a), + boxed_int_mul (b, b)); + return result; +} + +void +test_2a (void) +{ + boxed_int arr[4]; + arr[0].value = 1; + arr[1].value = 2; + arr[2].value = 3; + arr[3].value = 4; + boxed_int sum; + sum.value = arr[0].value + arr[1].value + arr[2].value + arr[3].value; + __analyzer_eval (sum.value == 10); /* { dg-warning "TRUE" } */ +} + +void +test_2b (void) +{ + boxed_int a, b, c, d; + a.value = 1; + b.value = 2; + c.value = 3; + d.value = 4; + boxed_int sum; + sum.value = a.value + b.value + c.value + d.value; + __analyzer_eval (sum.value == 10); /* { dg-warning "TRUE" } */ +} + +void +test_2c (void) +{ + boxed_int a, b, c, d; + a.value = 1; + b.value = 2; + c.value = 3; + d.value = 4; + boxed_int sum = inline_boxed_int_add (inline_boxed_int_add (a, b), + inline_boxed_int_add (c, d)); + __analyzer_eval (sum.value == 10); /* { dg-warning "TRUE" } */ +} + +void +test_2d (void) +{ + boxed_int a, b, c, d; + a.value = 1; + b.value = 2; + c.value = 3; + d.value = 4; + boxed_int sum = noinline_boxed_int_add (noinline_boxed_int_add (a, b), + noinline_boxed_int_add (c, d)); + __analyzer_eval (sum.value == 10); /* { dg-warning "TRUE" } */ +} + +/* Pointer to a local. */ + +void test_4 (void) +{ + boxed_int i; + int *p = &i.value; + i.value = 1; + *p = 2; + __analyzer_eval (i.value == 2); /* { dg-warning "TRUE" } */ +} + +/* Local array. */ + +void test_5 (void) +{ + boxed_int a[10]; + a[3].value = 5; /* ARRAY_REF. */ + __analyzer_eval (a[3].value == 5); /* { dg-warning "TRUE" } */ +} + +/* Local array, but using an unknown index. */ + +void test_5a (int idx) +{ + boxed_int a[10]; + a[idx].value = 5; /* ARRAY_REF. */ + __analyzer_eval (a[idx].value == 5); /* { dg-warning "TRUE" } */ +} + +/* Array passed in as a param. */ + +void test_6 (boxed_int a[10]) +{ + /* POINTER_PLUS_EXPR then a MEM_REF. */ + __analyzer_eval (a[3].value == 42); /* { dg-warning "UNKNOWN" } */ + a[3].value = 42; + __analyzer_eval (a[3].value == 42); /* { dg-warning "TRUE" } */ +} + +/* Array passed in as a param ptr. */ + +void test_7 (boxed_int *a) +{ + __analyzer_eval (a[3].value == 42); /* { dg-warning "UNKNOWN" } */ + a[3].value = 42; + __analyzer_eval (a[3].value == 42); /* { dg-warning "TRUE" } */ +} + +/* Globals. */ + +boxed_int glob_a; + +void test_10 (void) +{ + __analyzer_eval (glob_a.value == 42); /* { dg-warning "UNKNOWN" } */ + glob_a.value = 42; + __analyzer_eval (glob_a.value == 42); /* { dg-warning "TRUE" } */ +} + +/* Use of uninit value. */ +int test_12a (void) +{ + boxed_int i; /* { dg-message "region created on stack here" } */ + return i.value; /* { dg-warning "use of uninitialized value 'i.value'" } */ +} + +/* Use of uninit value. */ +boxed_int test_12b (void) +{ + boxed_int i; /* { dg-message "region created on stack here" } */ + return i; /* { dg-warning "use of uninitialized value '\[^\n\r\]*'" } */ +} + +void test_loop (void) +{ + boxed_int i; + + __analyzer_dump_exploded_nodes (0); /* { dg-warning "1 processed enode" } */ + + for (i.value=0; i.value<256; i.value++) { + __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */ + } + + __analyzer_dump_exploded_nodes (0); /* { dg-warning "1 processed enode" } */ +} diff --git a/gcc/testsuite/gcc.dg/analyzer/torture/boxed-ptr-1.c b/gcc/testsuite/gcc.dg/analyzer/torture/boxed-ptr-1.c new file mode 100644 index 00000000000..8db93f109c7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/torture/boxed-ptr-1.c @@ -0,0 +1,82 @@ +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } { "" } } */ + +#include +#include "../analyzer-decls.h" + +typedef struct boxed_ptr { void *value; } boxed_ptr; + +boxed_ptr __attribute__((noinline)) +boxed_malloc (size_t sz) +{ + boxed_ptr result; + result.value = malloc (sz); + return result; +} + +boxed_ptr __attribute__((noinline)) +boxed_free (boxed_ptr ptr) +{ + free (ptr.value); +} + +const boxed_ptr boxed_null = {NULL}; + +boxed_ptr test_1 (int flag) +{ + boxed_ptr ptr = boxed_malloc (sizeof (int)); + + if (flag) /* { dg-message "following 'false' branch" } */ + if (!ptr.value) + return boxed_null; + + *((int *)ptr.value) = 42; /* { dg-warning "dereference of possibly-NULL '\[^\n\r\]*'" } */ + + return ptr; +} + +void test_2 (int flag) +{ + boxed_ptr ptr; + + if (flag) + ptr = boxed_malloc (4096); + else + ptr = boxed_malloc (1024); + + __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */ + + boxed_free (ptr); + + __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */ + /* TODO: ideally we would have purged the state of "ptr", and there would be + just 1 enode here (PR analyzer/104943). */ +} + +void test_3 (int kind) +{ + boxed_ptr ptr; + + switch (kind) + { + default: + ptr = boxed_malloc (4096); + break; + case 0: + ptr = boxed_malloc (128); + break; + case 1: + ptr = boxed_malloc (1024); + break; + case 2: + ptr = boxed_malloc (65536); + break; + } + + __analyzer_dump_exploded_nodes (0); /* { dg-warning "4 processed enodes" } */ + + boxed_free (ptr); + + __analyzer_dump_exploded_nodes (0); /* { dg-warning "4 processed enodes" } */ + /* TODO: ideally we would have purged the state of "ptr", and there would be + just 1 enode here (PR analyzer/104943). */ +}