From: Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
To: David Malcolm <dmalcolm@redhat.com>
Cc: Tim Lange <mail@tim-lange.me>, gcc-patches@gcc.gnu.org
Subject: Re: Floating-point allocation sizes? (was Re: [PATCH] analyzer: Fix handling of non-ints inside allocation size checker [PR106181])
Date: Wed, 6 Jul 2022 03:27:58 +0530 [thread overview]
Message-ID: <CAAgBjMkd-xybhAWL3eGUcs5-W6Nyc_c1xFaX++Wz2JJDHXLhPQ@mail.gmail.com> (raw)
In-Reply-To: <77cd3d305523a14adb7f3cf7f4079b6fb21e429c.camel@redhat.com>
On Wed, 6 Jul 2022 at 03:08, David Malcolm via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> On Tue, 2022-07-05 at 21:49 +0200, Tim Lange wrote:
> > This patch fixes the ICE reported in PR106181 by Arseny Solokha. With
> > this patch, the allocation size checker tries to handle floating-point
> > operands of allocation size arguments. Constant sizes get implicitly
> > converted and symbolic sizes are handled as long as the floating-point
> > operand could also be represented as a positive integer. In all other
> > cases and on unhandled constants, the checker falls back to not
> > emitting a warning.
> > Also, I unified the logic on zero byte allocations.
>
> Hi Tim
>
> Thanks for the patch.
>
> We definitely don't want to crash, but my "gut reaction" to the
> testsuite examples was that we ought to be warning on them - using
> floating point when calculating an allocation size seems like asking
> for trouble.
>
> In particular test_16's:
> int32_t *ptr = malloc (n * 3.1);
> feels to me like it deserves a warning. I suppose it could be valid if
> n is a multiple of 40 (so that the buffer is a multiple of 31 * 4 and
> thus a multiple of 4), for small enough n that we don't lose precision,
> but that code seems very questionable - the comment says "just assume
> that the programmer knows what they are doing", but I think anyone
> using -fanalyzer is opting-in to have more fussy checking and would
> probably want to be warned about such code.
>
> I also wondered what happens on NAN, with e.g.
>
> #include <math.h>
>
> void test_nan (void)
> {
> int *p = malloc (NAN * sizeof (int));
> }
>
> but we issue -Woverflow on that.
>
> I'm thinking that perhaps we should have a new warning for floating
> point buffer size calculations, though I'm not yet sure exactly how it
> should work and how fussy it should be (e.g. complain about floating
> point calculations vs complain about *any* floating point used as a
> buffer size, etc).
Hi David,
For the former, I was wondering if it'd be a good idea to complain if
alloc_size is floating type,
and floor(alloc_size) != alloc_size ?
So we warn for:
int *p = malloc(4.5);
but not for
int *p = malloc(4.0);
For the latter, I guess -Wconversion should be sufficient ?
Thanks,
Prathamesh
>
> Does anyone know of real world code that uses floating point in buffer-
> size calculations? (updating Subject accordingly) Is there code out
> there that does this? It seems broken to me, but maybe there's a valid
> use-case that I can't think of.
>
> The closest such rule I can think of is CERT-C's
> "FLP02-C. Avoid using floating-point numbers when precise computation
> is needed":
> https://wiki.sei.cmu.edu/confluence/display/c/FLP02-C.+Avoid+using+floating-point+numbers+when+precise+computation+is+needed
>
>
> Dave
>
>
> >
> > Regression-tested on x86_64 linux.
> >
> > 2022-07-05 Tim Lange <mail@tim-lange.me>
> >
> > gcc/analyzer/ChangeLog:
> >
> > PR analyzer/106181
> > * region-model.cc (capacity_compatible_with_type):
> > Can handle non-integer constants now.
> > (region_model::check_region_size): Adapted to the new signature
> > of
> > capacity_compatible_with_type.
> >
> > gcc/testsuite/ChangeLog:
> >
> > PR analyzer/106181
> > * gcc.dg/analyzer/allocation-size-1.c: New tests.
> > * gcc.dg/analyzer/allocation-size-2.c: New tests.
> > * gcc.dg/analyzer/pr106181.c: New test.
> >
> > ---
> > gcc/analyzer/region-model.cc | 44 ++++++++++++++++---
> > .../gcc.dg/analyzer/allocation-size-1.c | 29 +++++++++++-
> > .../gcc.dg/analyzer/allocation-size-2.c | 22 ++++++++++
> > gcc/testsuite/gcc.dg/analyzer/pr106181.c | 7 +++
> > 4 files changed, 95 insertions(+), 7 deletions(-)
> > create mode 100644 gcc/testsuite/gcc.dg/analyzer/pr106181.c
> >
> > diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-
> > model.cc
> > index 5d939327e01..e097ecb3c07 100644
> > --- a/gcc/analyzer/region-model.cc
> > +++ b/gcc/analyzer/region-model.cc
> > @@ -2904,13 +2904,45 @@ private:
> >
> > static bool
> > capacity_compatible_with_type (tree cst, tree pointee_size_tree,
> > - bool is_struct)
> > + bool is_struct, bool floor_real)
> > {
> > - gcc_assert (TREE_CODE (cst) == INTEGER_CST);
> > gcc_assert (TREE_CODE (pointee_size_tree) == INTEGER_CST);
> > -
> > unsigned HOST_WIDE_INT pointee_size = TREE_INT_CST_LOW
> > (pointee_size_tree);
> > - unsigned HOST_WIDE_INT alloc_size = TREE_INT_CST_LOW (cst);
> > +
> > + unsigned HOST_WIDE_INT alloc_size;
> > + switch (TREE_CODE (cst))
> > + {
> > + default:
> > + /* Assume all unhandled operands are compatible. */
> > + return true;
> > + case INTEGER_CST:
> > + alloc_size = TREE_INT_CST_LOW (cst);
> > + break;
> > + case REAL_CST:
> > + {
> > + const REAL_VALUE_TYPE *rv = TREE_REAL_CST_PTR (cst);
> > + if (floor_real)
> > + {
> > + /* If the size is constant real at compile-time,
> > + we can model the conversion. */
> > + alloc_size = real_to_integer (rv);
> > + }
> > + else
> > + {
> > + /* On expressions where the value of one operator isn't
> > + representable as an integer or is negative, we give up
> > and
> > + just assume that the programmer knows what they are
> > doing. */
> > + HOST_WIDE_INT i;
> > + if (real_isneg (rv) || !real_isinteger (rv, &i))
> > + return true;
> > + alloc_size = i;
> > + }
> > + }
> > + break;
> > + }
> > +
> > + if (alloc_size == 0)
> > + return true;
> >
> > if (is_struct)
> > return alloc_size >= pointee_size;
> > @@ -2920,7 +2952,7 @@ capacity_compatible_with_type (tree cst, tree
> > pointee_size_tree,
> > static bool
> > capacity_compatible_with_type (tree cst, tree pointee_size_tree)
> > {
> > - return capacity_compatible_with_type (cst, pointee_size_tree,
> > false);
> > + return capacity_compatible_with_type (cst, pointee_size_tree, false,
> > false);
> > }
> >
> > /* Checks whether SVAL could be a multiple of SIZE_CST.
> > @@ -3145,7 +3177,7 @@ region_model::check_region_size (const region
> > *lhs_reg, const svalue *rhs_sval,
> > = as_a <const constant_svalue *> (capacity);
> > tree cst_cap = cst_cap_sval->get_constant ();
> > if (!capacity_compatible_with_type (cst_cap, pointee_size_tree,
> > - is_struct))
> > + is_struct, true))
> > ctxt->warn (new dubious_allocation_size (lhs_reg, rhs_reg,
> > cst_cap));
> > }
> > diff --git a/gcc/testsuite/gcc.dg/analyzer/allocation-size-1.c
> > b/gcc/testsuite/gcc.dg/analyzer/allocation-size-1.c
> > index 4a78a81d054..1a1c8e75c98 100644
> > --- a/gcc/testsuite/gcc.dg/analyzer/allocation-size-1.c
> > +++ b/gcc/testsuite/gcc.dg/analyzer/allocation-size-1.c
> > @@ -114,4 +114,31 @@ void test_10 (int32_t n)
> > {
> > char *ptr = malloc (7 * n);
> > free (ptr);
> > -}
> > \ No newline at end of file
> > +}
> > +
> > +void test_11 ()
> > +{
> > + int32_t *ptr = malloc (3.0); /* { dg-line malloc11 } */
> > + free (ptr);
> > + /* { dg-warning "allocated buffer size is not a multiple of the
> > pointee's size \\\[CWE-131\\\]" "warning" { target *-*-* } malloc11 }
> > */
> > + /* { dg-message "'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})?
> > here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note"
> > { target *-*-* } malloc11 } */
> > +}
> > +
> > +void test_12 ()
> > +{
> > + int32_t *ptr = malloc (4.0);
> > + free (ptr);
> > +}
> > +
> > +void test_13 ()
> > +{
> > + int32_t *ptr = malloc (4.7);
> > + free (ptr);
> > +}
> > +
> > +void test_14 ()
> > +{
> > + /* Test round towards zero. */
> > + int32_t *ptr = malloc (-0.9);
> > + free (ptr);
> > +}
> > diff --git a/gcc/testsuite/gcc.dg/analyzer/allocation-size-2.c
> > b/gcc/testsuite/gcc.dg/analyzer/allocation-size-2.c
> > index d541d5ef8db..babf9ae668d 100644
> > --- a/gcc/testsuite/gcc.dg/analyzer/allocation-size-2.c
> > +++ b/gcc/testsuite/gcc.dg/analyzer/allocation-size-2.c
> > @@ -154,3 +154,25 @@ void test_13 (void)
> > else
> > free (ptr);
> > }
> > +
> > +void test_14 (int32_t n)
> > +{
> > + int32_t *ptr = malloc (n * 3.0); /* { dg-line malloc14 } */
> > + free (ptr);
> > + /* { dg-warning "allocated buffer size is not a multiple of the
> > pointee's size \\\[CWE-131\\\]" "warning" { target *-*-* } malloc14 }
> > */
> > + /* { dg-message "'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})?
> > here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note"
> > { target *-*-* } malloc14 } */
> > +}
> > +
> > +void test_15 (int32_t n)
> > +{
> > + int32_t *ptr = malloc (n * 4.0);
> > + free (ptr);
> > +}
> > +
> > +void test_16 (int32_t n)
> > +{
> > + /* Should not emit a warning because we can not reason whether the
> > result
> > + of the floating-point arithmetic actually is a valid size or
> > not. */
> > + int32_t *ptr = malloc (n * 3.1);
> > + free (ptr);
> > +}
> > diff --git a/gcc/testsuite/gcc.dg/analyzer/pr106181.c
> > b/gcc/testsuite/gcc.dg/analyzer/pr106181.c
> > new file mode 100644
> > index 00000000000..6df4e4538c0
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/analyzer/pr106181.c
> > @@ -0,0 +1,7 @@
> > +#include <stdint.h>
> > +
> > +int32_t *
> > +foo (int32_t x)
> > +{
> > + return __builtin_calloc (x * 1.1, 1);
> > +}
>
>
next prev parent reply other threads:[~2022-07-05 21:58 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-07-05 19:49 [PATCH] analyzer: Fix handling of non-ints inside allocation size checker [PR106181] Tim Lange
2022-07-05 21:37 ` Floating-point allocation sizes? (was Re: [PATCH] analyzer: Fix handling of non-ints inside allocation size checker [PR106181]) David Malcolm
2022-07-05 21:57 ` Prathamesh Kulkarni [this message]
2022-07-05 23:12 ` Tim Lange
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CAAgBjMkd-xybhAWL3eGUcs5-W6Nyc_c1xFaX++Wz2JJDHXLhPQ@mail.gmail.com \
--to=prathamesh.kulkarni@linaro.org \
--cc=dmalcolm@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=mail@tim-lange.me \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).