From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 7884) id CE91A3858D28; Fri, 12 Aug 2022 09:14:07 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CE91A3858D28 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Tim Lange To: gcc-cvs@gcc.gnu.org Subject: [gcc r13-2028] analyzer: consider that realloc could shrink the buffer [PR106539] X-Act-Checkin: gcc X-Git-Author: Tim Lange X-Git-Refname: refs/heads/master X-Git-Oldrev: 1595794f804ed3e925dcdf5f21b7fa762c74ca15 X-Git-Newrev: 2b75b3b6a4ddc0d65a84a0cc4b00c47ae70e52c0 Message-Id: <20220812091407.CE91A3858D28@sourceware.org> Date: Fri, 12 Aug 2022 09:14:07 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 12 Aug 2022 09:14:07 -0000 https://gcc.gnu.org/g:2b75b3b6a4ddc0d65a84a0cc4b00c47ae70e52c0 commit r13-2028-g2b75b3b6a4ddc0d65a84a0cc4b00c47ae70e52c0 Author: Tim Lange Date: Fri Aug 12 10:26:14 2022 +0200 analyzer: consider that realloc could shrink the buffer [PR106539] This patch adds the "shrinks buffer" case to the success_with_move modelling of realloc. Regression-tested on Linux x86-64, further ran the analyzer tests with the -m32 option. 2022-08-11 Tim Lange gcc/analyzer/ChangeLog: PR analyzer/106539 * region-model-impl-calls.cc (region_model::impl_call_realloc): Use the result of get_copied_size as the size for the sized_regions in realloc. (success_with_move::get_copied_size): New function. gcc/testsuite/ChangeLog: PR analyzer/106539 * gcc.dg/analyzer/pr106539.c: New test. * gcc.dg/analyzer/realloc-5.c: New test. Diff: --- gcc/analyzer/region-model-impl-calls.cc | 48 +++++++++++++++++++++++++++---- gcc/testsuite/gcc.dg/analyzer/pr106539.c | 15 ++++++++++ gcc/testsuite/gcc.dg/analyzer/realloc-5.c | 44 ++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 6 deletions(-) diff --git a/gcc/analyzer/region-model-impl-calls.cc b/gcc/analyzer/region-model-impl-calls.cc index 3f821ff07e1..8eebd122d42 100644 --- a/gcc/analyzer/region-model-impl-calls.cc +++ b/gcc/analyzer/region-model-impl-calls.cc @@ -849,15 +849,17 @@ region_model::impl_call_realloc (const call_details &cd) const svalue *old_size_sval = model->get_dynamic_extents (freed_reg); if (old_size_sval) { - const region *sized_old_reg + const svalue *copied_size_sval + = get_copied_size (old_size_sval, new_size_sval); + const region *copied_old_reg = model->m_mgr->get_sized_region (freed_reg, NULL, - old_size_sval); + copied_size_sval); const svalue *buffer_content_sval - = model->get_store_value (sized_old_reg, cd.get_ctxt ()); - const region *sized_new_reg + = model->get_store_value (copied_old_reg, cd.get_ctxt ()); + const region *copied_new_reg = model->m_mgr->get_sized_region (new_reg, NULL, - old_size_sval); - model->set_value (sized_new_reg, buffer_content_sval, + copied_size_sval); + model->set_value (copied_new_reg, buffer_content_sval, cd.get_ctxt ()); } else @@ -891,6 +893,40 @@ region_model::impl_call_realloc (const call_details &cd) else return true; } + + private: + /* Return the lesser of OLD_SIZE_SVAL and NEW_SIZE_SVAL. + If either one is symbolic, the symbolic svalue is returned. */ + const svalue *get_copied_size (const svalue *old_size_sval, + const svalue *new_size_sval) const + { + tree old_size_cst = old_size_sval->maybe_get_constant (); + tree new_size_cst = new_size_sval->maybe_get_constant (); + + if (old_size_cst && new_size_cst) + { + /* Both are constants and comparable. */ + tree cmp = fold_binary (LT_EXPR, boolean_type_node, + old_size_cst, new_size_cst); + + if (cmp == boolean_true_node) + return old_size_sval; + else + return new_size_sval; + } + else if (new_size_cst) + { + /* OLD_SIZE_SVAL is symbolic, so return that. */ + return old_size_sval; + } + else + { + /* NEW_SIZE_SVAL is symbolic or both are symbolic. + Return NEW_SIZE_SVAL, because implementations of realloc + probably only moves the buffer if the new size is larger. */ + return new_size_sval; + } + } }; /* Body of region_model::impl_call_realloc. */ diff --git a/gcc/testsuite/gcc.dg/analyzer/pr106539.c b/gcc/testsuite/gcc.dg/analyzer/pr106539.c new file mode 100644 index 00000000000..fd270868e36 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/pr106539.c @@ -0,0 +1,15 @@ +#include + +void *test (void) +{ + void **p = (void **)malloc (sizeof (void *) * 2); + if (!p) + return NULL; + p[0] = malloc(10); + p[1] = malloc(20); /* { dg-message "allocated here" } */ + void *q = realloc (p, sizeof (void *)); /* { dg-message "when 'realloc' succeeds, moving buffer" } */ + if (!q) + /* { dg-warning "leak of ''" "leak of unknown" { target *-*-* } .-1 } */ + return p; + return q; +} diff --git a/gcc/testsuite/gcc.dg/analyzer/realloc-5.c b/gcc/testsuite/gcc.dg/analyzer/realloc-5.c new file mode 100644 index 00000000000..433c513d7f5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/realloc-5.c @@ -0,0 +1,44 @@ +#include "analyzer-decls.h" + +typedef __SIZE_TYPE__ size_t; + +#define NULL ((void *)0) + +extern void *malloc (size_t __size) + __attribute__ ((__nothrow__ , __leaf__)) + __attribute__ ((__malloc__)) + __attribute__ ((__alloc_size__ (1))); +extern void *realloc (void *__ptr, size_t __size) + __attribute__ ((__nothrow__ , __leaf__)) + __attribute__ ((__warn_unused_result__)) + __attribute__ ((__alloc_size__ (2))); +extern void free (void *__ptr) + __attribute__ ((__nothrow__ , __leaf__)); +extern void *memset (void *__ptr, int __value, size_t __size); + +/* realloc where the region shrinks on success_with_move. */ + +void test_1 () +{ + char *p = malloc (16); + if (!p) + return; + memset (p, 1, 16); + + char *q = realloc (p, 8); + if (!q) + { + free (p); + return; + } + else if (p != q) + { + __analyzer_dump_capacity (q); /* { dg-warning "capacity: '\\(\[^\n\r\]*\\)8'" } */ + __analyzer_eval (q[8] == 1); /* { dg-line eval } */ + + /* { dg-warning "UNKNOWN" "warning" { target *-*-* } eval } */ + /* { dg-warning "use of uninitialized value" "warning" { target *-*-* } eval } */ + } + + free (q); +}