diff options
author | Tim Lange <mail@tim-lange.me> | 2022-08-12 10:26:14 +0200 |
---|---|---|
committer | Tim Lange <mail@tim-lange.me> | 2022-08-12 10:37:26 +0200 |
commit | 2b75b3b6a4ddc0d65a84a0cc4b00c47ae70e52c0 (patch) | |
tree | 7781fbbb7f03c5e253ef55313521fdae98dcc935 /gcc/analyzer | |
parent | 1595794f804ed3e925dcdf5f21b7fa762c74ca15 (diff) | |
download | gcc-2b75b3b6a4ddc0d65a84a0cc4b00c47ae70e52c0.zip gcc-2b75b3b6a4ddc0d65a84a0cc4b00c47ae70e52c0.tar.gz gcc-2b75b3b6a4ddc0d65a84a0cc4b00c47ae70e52c0.tar.bz2 |
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 <mail@tim-lange.me>
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.
Diffstat (limited to 'gcc/analyzer')
-rw-r--r-- | gcc/analyzer/region-model-impl-calls.cc | 48 |
1 files changed, 42 insertions, 6 deletions
diff --git a/gcc/analyzer/region-model-impl-calls.cc b/gcc/analyzer/region-model-impl-calls.cc index 3f821ff..8eebd12 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. */ |