Re: One question on the source code of tree-object-size.cc

2023-08-01 Thread Siddhesh Poyarekar

On 2023-08-01 17:35, Qing Zhao wrote:

typedef struct
{
   int a;
} A;
size_t f()
{
   A *p = malloc (1);
   return __builtin_object_size (p, 0);


Correction, that should be __builtin_object_size (p->a, 0).


Actually, it should be __builtin_object_size(p->a, 1).
For __builtin_object_size(p->a,0), gcc always uses the allocation size for the 
whole object.


Right, sorry, I mistyped, twice in fact; it should have been 
__bos(>a, 1) :)




GCC’s current behavior is:

For the size of the whole object, GCC currently always uses the allocation size.
And for the size in the sub-object, GCC chose the smaller one among the 
allocation size and the TYPE_SIZE.

Is this correct behavior?


Yes, it's deliberate; it specifically checks on var != pt_var, which can 
only be true for subobjects.


Thanks,
Sid


Re: [C PATCH]: Add Walloc-type to warn about insufficient size in allocations

2023-07-31 Thread Siddhesh Poyarekar

On 2023-07-21 07:21, Martin Uecker via Gcc-patches wrote:



This patch adds a warning for allocations with insufficient size
based on the "alloc_size" attribute and the type of the pointer
the result is assigned to. While it is theoretically legal to
assign to the wrong pointer type and cast it to the right type
later, this almost always indicates an error. Since this catches
common mistakes and is simple to diagnose, it is suggested to
add this warning.
  


Bootstrapped and regression tested on x86.


Martin



Add option Walloc-type that warns about allocations that have
insufficient storage for the target type of the pointer the
storage is assigned to.

gcc:
* doc/invoke.texi: Document -Wstrict-flex-arrays option.

gcc/c-family:

* c.opt (Walloc-type): New option.

gcc/c:
* c-typeck.cc (convert_for_assignment): Add Walloc-type warning.

gcc/testsuite:

* gcc.dg/Walloc-type-1.c: New test.


diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 4abdc8d0e77..8b9d148582b 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -319,6 +319,10 @@ Walloca
  C ObjC C++ ObjC++ Var(warn_alloca) Warning
  Warn on any use of alloca.
  
+Walloc-type

+C ObjC Var(warn_alloc_type) Warning
+Warn when allocating insufficient storage for the target type of the
assigned pointer.
+
  Walloc-size-larger-than=
  C ObjC C++ LTO ObjC++ Var(warn_alloc_size_limit) Joined Host_Wide_Int
ByteSize Warning Init(HOST_WIDE_INT_MAX)
  -Walloc-size-larger-than=Warn for calls to allocation
functions that
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 7cf411155c6..2e392f9c952 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -7343,6 +7343,32 @@ convert_for_assignment (location_t location,
location_t expr_loc, tree type,
"request for implicit conversion "
"from %qT to %qT not permitted in C++", rhstype,
type);
  
+  /* Warn of new allocations are not big enough for the target

type.  */
+  tree fndecl;
+  if (warn_alloc_type
+ && TREE_CODE (rhs) == CALL_EXPR
+ && (fndecl = get_callee_fndecl (rhs)) != NULL_TREE
+ && DECL_IS_MALLOC (fndecl))
+   {
+ tree fntype = TREE_TYPE (fndecl);
+ tree fntypeattrs = TYPE_ATTRIBUTES (fntype);
+ tree alloc_size = lookup_attribute ("alloc_size",
fntypeattrs);
+ if (alloc_size)
+   {
+ tree args = TREE_VALUE (alloc_size);
+ int idx = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1;
+ /* For calloc only use the second argument.  */
+ if (TREE_CHAIN (args))
+   idx = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN
(args))) - 1;
+ tree arg = CALL_EXPR_ARG (rhs, idx);
+ if (TREE_CODE (arg) == INTEGER_CST
+ && tree_int_cst_lt (arg, TYPE_SIZE_UNIT (ttl)))
+warning_at (location, OPT_Walloc_type, "allocation of
"
+"insufficient size %qE for type %qT with
"
+"size %qE", arg, ttl, TYPE_SIZE_UNIT
(ttl));
+   }
+   }
+


Wouldn't this be much more useful in later phases with ranger feedback 
like with the warn_access warnings?  That way the comparison won't be 
limited to constant sizes.


Thanks,
Sid


Re: One question on the source code of tree-object-size.cc

2023-07-31 Thread Siddhesh Poyarekar

On 2023-07-31 14:13, Qing Zhao wrote:

Okay. I see.

Then if the size info from the TYPE is smaller than the size info from the 
malloc,
  then based on the current code, we use the smaller one between these two,
  i.e, the size info from the TYPE.  (Even for the OST_MAXIMUM).

Is such behavior correct?


Yes, it's correct even for OST_MAXIMUM.  The smaller one between the two 
is the more precise estimate, which is why the mode doesn't matter.




This is for the new “counted_by” attribute and how to use it in 
__builtin_dynamic_object_size.
for example:

===

struct annotated {
 size_t foo;
 int array[] __attribute__((counted_by (foo)));
};

#define noinline __attribute__((__noinline__))
#define SIZE_BUMP 2

/* in the following function, malloc allocated more space than the value
of counted_by attribute.  Then what's the correct behavior we expect
the __builtin_dynamic_object_size should have?  */

static struct annotated * noinline alloc_buf (int index)
{
   struct annotated *p;
   p = malloc(sizeof (*p) + (index + SIZE_BUMP) * sizeof (int));
   p->foo = index;

   /*when checking the observed access p->array, we have info on both
 observered allocation and observed access,
 A. from observed allocation: (index + SIZE_BUMP) * sizeof (int)
 B. from observed access: p->foo * sizeof (int)

 in the above, p->foo = index.
*/

   /* for MAXIMUM size, based on the current code, we will use the size info 
from the TYPE,
  i.e, the “counted_by” attribute, which is the smaller one.   */
   expect(__builtin_dynamic_object_size(p->array, 1), (p->foo) * sizeof(int));


If the counted_by is less than what is allocated, it is the more correct 
value to return because that's what the application asked for through 
the attribute.  If the allocated size is less, we return the allocated 
size because in that case, despite what the application said, the actual 
allocated size is less and hence that's the safer value.


In fact in the latter case it may even make sense to emit a warning 
because it is more likely than not to be a bug.


Thanks,
Sid


Re: One question on the source code of tree-object-size.cc

2023-07-31 Thread Siddhesh Poyarekar

On 2023-07-31 13:03, Siddhesh Poyarekar wrote:

On 2023-07-31 12:47, Qing Zhao wrote:

Hi, Sid and Jakub,

I have a question in the following source portion of the routine 
“addr_object_size” of gcc/tree-object-size.cc:


  743   bytes = compute_object_offset (TREE_OPERAND (ptr, 0), var);
  744   if (bytes != error_mark_node)
  745 {
  746   bytes = size_for_offset (var_size, bytes);
  747   if (var != pt_var && pt_var_size && TREE_CODE (pt_var) 
== MEM_REF)

  748 {
  749   tree bytes2 = compute_object_offset (TREE_OPERAND 
(ptr, 0),

  750    pt_var);
  751   if (bytes2 != error_mark_node)
  752 {
  753   bytes2 = size_for_offset (pt_var_size, bytes2);
  754   bytes = size_binop (MIN_EXPR, bytes, bytes2);
  755 }
  756 }
  757 }

At line 754, why we always use “MIN_EXPR” whenever it’s for 
OST_MINIMUM or not?

Shall we use

(object_size_type & OST_MINIMUM
 ? MIN_EXPR : MAX_EXPR)



That MIN_EXPR is not for OST_MINIMUM.  It is to cater for allocations 
like this:


typedef struct
{
   int a;
} A;

size_t f()
{
   A *p = malloc (1);

   return __builtin_object_size (p, 0);


Correction, that should be __builtin_object_size (>a, 0)


}

where the returned size should be 1 and not sizeof (int).  The mode 
doesn't really matter in this case.


HTH.

Sid



Re: One question on the source code of tree-object-size.cc

2023-07-31 Thread Siddhesh Poyarekar

On 2023-07-31 12:47, Qing Zhao wrote:

Hi, Sid and Jakub,

I have a question in the following source portion of the routine 
“addr_object_size” of gcc/tree-object-size.cc:

  743   bytes = compute_object_offset (TREE_OPERAND (ptr, 0), var);
  744   if (bytes != error_mark_node)
  745 {
  746   bytes = size_for_offset (var_size, bytes);
  747   if (var != pt_var && pt_var_size && TREE_CODE (pt_var) == 
MEM_REF)
  748 {
  749   tree bytes2 = compute_object_offset (TREE_OPERAND (ptr, 0),
  750pt_var);
  751   if (bytes2 != error_mark_node)
  752 {
  753   bytes2 = size_for_offset (pt_var_size, bytes2);
  754   bytes = size_binop (MIN_EXPR, bytes, bytes2);
  755 }
  756 }
  757 }

At line 754, why we always use “MIN_EXPR” whenever it’s for OST_MINIMUM or not?
Shall we use

(object_size_type & OST_MINIMUM
 ? MIN_EXPR : MAX_EXPR)



That MIN_EXPR is not for OST_MINIMUM.  It is to cater for allocations 
like this:


typedef struct
{
  int a;
} A;

size_t f()
{
  A *p = malloc (1);

  return __builtin_object_size (p, 0);
}

where the returned size should be 1 and not sizeof (int).  The mode 
doesn't really matter in this case.


HTH.

Sid


[PATCH] testsuite/110763: Ensure zero return from test

2023-07-21 Thread Siddhesh Poyarekar
The test deliberately reads beyond bounds to exersize ubsan and the
return value may be anything, based on previous allocations.  The OFF
test caters for it by ANDing the return with 0, do the same for the DYN
test.

gcc/testsuite/ChangeLog:

PR testsuite/110763
* gcc.dg/ubsan/object-size-dyn.c (dyn): New parameter RET.
(main): Use it.

Signed-off-by: Siddhesh Poyarekar 
---
 gcc/testsuite/gcc.dg/ubsan/object-size-dyn.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/ubsan/object-size-dyn.c 
b/gcc/testsuite/gcc.dg/ubsan/object-size-dyn.c
index 0159f5b9820..49c3abe2e72 100644
--- a/gcc/testsuite/gcc.dg/ubsan/object-size-dyn.c
+++ b/gcc/testsuite/gcc.dg/ubsan/object-size-dyn.c
@@ -5,12 +5,12 @@
 
 int
 __attribute__ ((noinline))
-dyn (int size, int i)
+dyn (int size, int i, int ret)
 {
   __builtin_printf ("dyn\n");
   fflush (stdout);
   int *alloc = __builtin_calloc (size, sizeof (int));
-  int ret = alloc[i];
+  ret = ret & alloc[i];
   __builtin_free (alloc);
   return ret;
 }
@@ -28,7 +28,7 @@ off (int size, int i, int ret)
 int
 main (void)
 {
-  int ret = dyn (2, 2);
+  int ret = dyn (2, 2, 0);
 
   ret |= off (4, 4, 0);
 
-- 
2.41.0



Re: [PATCH] Implement range-op entry for sin/cos.

2023-04-24 Thread Siddhesh Poyarekar

On 2023-04-24 12:03, Jakub Jelinek wrote:

On Thu, Apr 20, 2023 at 01:57:55PM -0400, Siddhesh Poyarekar wrote:

Similarly for other functions which have other ranges, perhaps not with so
nice round numbers.  Say asin has [-pi/2, pi/2] range, those numbers aren't
exactly representable, but is it any worse to round those values to -inf or
+inf or worse give something 1-5 ulps further from that interval comparing
to other 1-5ulps errors?


I've extended my hack^^^test to include sqrt and this time it seems
that the boundary in that case holds even for non-standard rounding modes
for glibc:


IIRC the standard _requires_ sqrt to be correctly rounded.

Sid


Re: [PATCH] Implement range-op entry for sin/cos.

2023-04-21 Thread Siddhesh Poyarekar

On 2023-04-21 02:52, Jakub Jelinek wrote:

On Thu, Apr 20, 2023 at 09:14:10PM -0400, Siddhesh Poyarekar wrote:

On 2023-04-20 13:57, Siddhesh Poyarekar wrote:

For bounds that aren't representable, one could get error bounds from
libm-test-ulps data in glibc, although I reckon those won't be
exhaustive.  From a quick peek at the sin/cos data, the arc target seems
to be among the worst performers at about 7ulps, although if you include
the complex routines we get close to 13 ulps.  The very worst
imprecision among all math routines (that's gamma) is at 16 ulps for
power in glibc tests, so maybe allowing about 25-30 ulps error in bounds
might work across the board.


I was thinking about this a bit more and it seems like limiting ranges to
targets that can generate sane results (i.e. error bounds within, say, 5-6
ulps) and for the rest, avoid emitting the ranges altogether. Emitting a bad
range for all architectures seems like a net worse solution again.


Well, at least for basic arithmetics when libm functions aren't involved,
there is no point in disabling ranges altogether.


Oh yeah, I did mean only franges for math function call results.


And, for libm functions, my plan was to introduce a target hook, which
would have combined_fn argument to tell which function is queried,
machine_mode to say which floating point format and perhaps a bool whether
it is ulps for these basic math boundaries or results somewhere in between,
and would return in unsigned int ulps, 0 for 0.5ulps precision.
So, we could say for CASE_CFN_SIN: CASE_CFN_COS: in the glibc handler
say that ulps is say 3 inside of the ranges and 0 on the boundaries if
!flag_rounding_math and 6 and 2 with flag_rounding_math or whatever.
And in the generic code don't assume anything if ulps is say 100 or more.
The hooks would need to be a union of precision of supported versions of
the library through the history, including say libmvec because function
calls could be vectorized.
And default could be that infinite precision.
Back in November I've posted a proglet that can generate some ulps from
random number testing, plus on glibc we could pick maximums from ulps files.
And if needed, say powerpc*-linux could override the generic glibc
version for some subset of functions and call default otherwise (say at
least for __ibm128).


Ack, that sounds like a plan.

Thanks,
Sid


Re: [PATCH] Implement range-op entry for sin/cos.

2023-04-20 Thread Siddhesh Poyarekar

On 2023-04-20 13:57, Siddhesh Poyarekar wrote:
For bounds that aren't representable, one could get error bounds from 
libm-test-ulps data in glibc, although I reckon those won't be 
exhaustive.  From a quick peek at the sin/cos data, the arc target seems 
to be among the worst performers at about 7ulps, although if you include 
the complex routines we get close to 13 ulps.  The very worst 
imprecision among all math routines (that's gamma) is at 16 ulps for 
power in glibc tests, so maybe allowing about 25-30 ulps error in bounds 
might work across the board.


I was thinking about this a bit more and it seems like limiting ranges 
to targets that can generate sane results (i.e. error bounds within, 
say, 5-6 ulps) and for the rest, avoid emitting the ranges altogether. 
Emitting a bad range for all architectures seems like a net worse 
solution again.


Thanks,
Sid


Re: [PATCH] Implement range-op entry for sin/cos.

2023-04-20 Thread Siddhesh Poyarekar

On 2023-04-20 11:52, Jakub Jelinek wrote:

Why?  Unless an implementation guarantees <= 0.5ulps errors, it can be one
or more ulps off, why is an error at or near 1.0 or -1.0 error any worse
than similar errors for other values?


In a general sense, maybe not, but in the sense of breaching the bounds 
of admissible values, especially when it can be reasonably corrected, it 
seems worse IMO to let the error slide.



Similarly for other functions which have other ranges, perhaps not with so
nice round numbers.  Say asin has [-pi/2, pi/2] range, those numbers aren't
exactly representable, but is it any worse to round those values to -inf or
+inf or worse give something 1-5 ulps further from that interval comparing
to other 1-5ulps errors?


I agree the argument in favour of allowing errors breaching the 
mathematical bounds is certainly stronger for bounds that are not 
exactly representable.  I just feel like the implementation ought to 
take the additional effort when the bounds are representable and make it 
easier for the compiler.


For bounds that aren't representable, one could get error bounds from 
libm-test-ulps data in glibc, although I reckon those won't be 
exhaustive.  From a quick peek at the sin/cos data, the arc target seems 
to be among the worst performers at about 7ulps, although if you include 
the complex routines we get close to 13 ulps.  The very worst 
imprecision among all math routines (that's gamma) is at 16 ulps for 
power in glibc tests, so maybe allowing about 25-30 ulps error in bounds 
might work across the board.


But yeah, it's probably going to be guesswork.

Thanks,
Sid


Re: [PATCH] Implement range-op entry for sin/cos.

2023-04-20 Thread Siddhesh Poyarekar

On 2023-04-20 10:02, Jakub Jelinek wrote:

On x86_64-linux with glibc 2.35, I see
for i in FLOAT DOUBLE LDOUBLE FLOAT128; do for j in TONEAREST UPWARD DOWNWARD 
TOWARDZERO; do gcc -D$i -DROUND=FE_$j -g -O1 -o /tmp/sincos{,.c} -lm; 
/tmp/sincos || echo $i $j; done; done
Aborted (core dumped)
FLOAT UPWARD
Aborted (core dumped)
FLOAT DOWNWARD
On sparc-sun-solaris2.11 I see
for i in FLOAT DOUBLE LDOUBLE; do for j in TONEAREST UPWARD DOWNWARD 
TOWARDZERO; do gcc -D$i -DROUND=FE_$j -g -O1 -o sincos{,.c} -lm; ./sincos || 
echo $i $j; done; done
Abort (core dumped)
DOUBLE UPWARD
Abort (core dumped)
DOUBLE DOWNWARD
Haven't tried anything else.  So that shows (but doesn't prove) that
maybe [-1., 1.] interval is fine for -fno-rounding-math on those, but not
for -frounding-math.


Would there be a reason to not consider these as bugs?  I feel like 
these should be fixed in glibc, or any math implementation that ends up 
doing this.


I suppose one reason could be the overhead of an additional branch to 
check for result bounds, but is that serious enough to allow this 
imprecision?  The alternative of output range being defined as 
[-1.0-ulp, 1.0+ulp] avoids that conversation I guess.


Thanks,
Sid


Re: [PATCH] Implement range-op entry for sin/cos.

2023-04-20 Thread Siddhesh Poyarekar

On 2023-04-20 08:59, Jakub Jelinek via Gcc-patches wrote:

+r.set (type, dconstm1, dconst1);


See above, are we sure we can use [-1., 1.] range safely, or should that be
[-1.-Nulps, 1.+Nulps] for some kind of expected worse error margin of the
implementation?  And ditto for -frounding-math, shall we increase that
interval in that case, or is [-1., 1.] going to be ok?


Do any math implementations generate results outside of [-1., 1.]?  If 
yes, then it's a bug in those implementations IMO, not in the range 
assumption.  It feels wrong to cater for what ought to be trivially 
fixable in libraries if they ever happen to generate such results.


Thanks,
Sid


Re: [PATCH] doc: Fix typo in -Wall description

2023-02-17 Thread Siddhesh Poyarekar

On 2023-02-17 14:43, Jeff Law wrote:



On 2/17/23 06:41, Siddhesh Poyarekar wrote:

-Wall enables -Wuse-after-free=2 and not -Wuse-after-free=3.

gcc/ChangeLog:

* gcc/doc/invoke.texi (@item -Wall): Fix typo in
-Wuse-after-free.

Looks obvious to me.  If you haven't committed it already, go ahead.


Pushed, thanks.

Sid


[PATCH] doc: Fix typo in -Wall description

2023-02-17 Thread Siddhesh Poyarekar
-Wall enables -Wuse-after-free=2 and not -Wuse-after-free=3.

gcc/ChangeLog:

* gcc/doc/invoke.texi (@item -Wall): Fix typo in
-Wuse-after-free.

Signed-off-by: Siddhesh Poyarekar 
---
 gcc/doc/invoke.texi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 51447a78584..20d41e19b3c 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -6083,7 +6083,7 @@ Options} and @ref{Objective-C and Objective-C++ Dialect 
Options}.
 -Wunused-label @gol
 -Wunused-value @gol
 -Wunused-variable  @gol
--Wuse-after-free=3  @gol
+-Wuse-after-free=2  @gol
 -Wvla-parameter @r{(C and Objective-C only)} @gol
 -Wvolatile-register-var  @gol
 -Wzero-length-bounds}
-- 
2.38.1



Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]

2023-02-08 Thread Siddhesh Poyarekar

On 2023-02-08 14:09, Joseph Myers wrote:

What must be avoided is -pedantic diagnostics for

struct flex1 { int n; int data[1]; };
struct out_flex_end1 { int m; struct flex1 flex_data; };

regardless of whether considered flexible or not, since that's clearly
valid in standard C.



Are you sure about "regardless of whether considered flexible or not", 
since ISTM the validity of the above in standard C is limited to when 
it's considered a non-flexible array.  So with -pedantic it shouldn't 
warn, but it also then shouldn't consider it a flexible array.


In other words, perhaps it makes sense to imply -fstrict-flex-arrays 
with -pedantic?


Sid


Re: [PATCH] tree-optimization/108522 Use component_ref_field_offset

2023-02-07 Thread Siddhesh Poyarekar




On 2023-01-25 22:32, Siddhesh Poyarekar wrote:

Instead of using TREE_OPERAND (expr, 2) directly, use
component_ref_field_offset instead, which does scaling for us.  The
function also substitutes PLACEHOLDER_EXPRs, which is probably what we
want anyway but I'm not sure if it's relevant for tree-object-size.

gcc/ChangeLog:

PR tree-optimization/108522
* tree-object-size.cc (compute_object_offset): Make EXPR
argument non-const.  Call component_ref_field_offset.

gcc/testsuite/ChangeLog:

PR tree-optimization/108522
* gcc.dg/builtin-dynamic-object-size-0.c (DEFSTRUCT): New
macro.
(test_dynarray_struct_member_b, test_dynarray_struct_member_c,
test_dynarray_struct_member_d,
test_dynarray_struct_member_subobj_b,
test_dynarray_struct_member_subobj_c,
test_dynarray_struct_member_subobj_d): New tests.
(main): Call them.

Signed-off-by: Siddhesh Poyarekar 


... and now pushed (this and the earlier commit) to gcc-12 branch.

Sid


Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]

2023-02-07 Thread Siddhesh Poyarekar

On 2023-02-06 18:14, Joseph Myers wrote:

On Mon, 6 Feb 2023, Qing Zhao via Gcc-patches wrote:


In GCC14:

1. Include this new warning -Wgnu-varaible-sized-type-not-at-end to -Wall
2. Deprecate this extension from GCC. (Or delay this to next release?).


Any deprecation, or inclusion in -Wall, would best come with evidence
about the prevalance of use (possibly unintentional, probably undesirable)
of these extensions.  For example, maybe someone could do a distribution
rebuild with a patch to enable these warnings and report the results?


FWIW, Fred from our team has been working on a mass prebuilder that can 
be used for this kind of distribution-wide validation.  I've used it for 
_FORTIFY_SOURCE validation as well as coverage analysis.


I can help you with this Qing, once you have a patch ready.

Sid

[1] https://gitlab.com/fedora/packager-tools/mass-prebuild/


Re: [PATCH 2/2] Documentation Update.

2023-02-02 Thread Siddhesh Poyarekar

On 2023-02-02 03:33, Richard Biener wrote:

looking at PR77650 what seems missing there is the semantics of this
extension as expected/required by the glibc use.  comment#5 seems
to suggest that for my example above its expected that
Y.x.data[0] aliases Y.end?!  There must be a better way to write
the glibc code and IMHO it would be best to deprecate this extension.
Definitely the middle-end wouldn't consider this aliasing for
my example - maybe it "works" when wrapped inside a union but
then for sure only when the union is visible in all accesses ...

typedef union
{
   struct __gconv_info __cd;
   struct
   {
 struct __gconv_info __cd;
 struct __gconv_step_data __data;
   } __combined;
} _G_iconv_t;

could be written as

typedef union
{
   struct __gconv_info __cd;
   char __dummy[sizeof(struct __gconv_info) + sizeof(struct
__gconv_step_data)];
} _G_iconv_t;

in case the intent is to provide a complete type with space for
a single __gconv_step_data.


I dug into this on the glibc end and it looks like this commit:

commit 63fb8f9aa9d19f85599afe4b849b567aefd70a36
Author: Zack Weinberg 
Date:   Mon Feb 5 14:13:41 2018 -0500

Post-cleanup 2: minimize _G_config.h.

ripped all of that gunk out.  AFAICT there's no use of struct 
__gconv_info anywhere else in the code.


I reckon it is safe to say now that glibc no longer needs this misfeature.

Sid


Re: [PATCH 2/2] Documentation Update.

2023-02-01 Thread Siddhesh Poyarekar

On 2023-02-01 13:24, Qing Zhao wrote:




On Feb 1, 2023, at 11:55 AM, Siddhesh Poyarekar  wrote:

On 2023-01-31 09:11, Qing Zhao wrote:

Update documentation to clarify a GCC extension on structure with
flexible array member being nested in another structure.
gcc/ChangeLog:
* doc/extend.texi: Document GCC extension on a structure containing
a flexible array member to be a member of another structure.


Should this resolve pr#77650 since the proposed action there appears to be to 
document these semantics?


My understanding of pr77650 is specifically for documentation on the following 
case:

The structure with a flexible array member is the middle field of another 
structure.

Which I added in the documentation as the 2nd situation.
However, I am still not very comfortable on my current clarification on this 
situation: how should we document on
the expected gcc behavior to handle such situation?


I reckon wording that dissuades programmers from using this might be 
appropriate, i.e. don't rely on this and if you already have such nested 
flex arrays, change code to remove them.



+In the above, @code{flex_data.data[]} is allowed to be extended flexibly to
+the padding. E.g, up to 4 elements.


"""
... Relying on space in struct padding is bad programming practice and 
any code relying on this behaviour should be modified to ensure that 
flexible array members only end up at the ends of arrays.  The 
`-pedantic` flag should help identify such uses.

"""

Although -pedantic will also flag on flex arrays nested in structs even 
if they're at the end of the parent struct, so my suggestion on the 
warning is not really perfect.


Sid


Re: [PATCH 2/2] Documentation Update.

2023-02-01 Thread Siddhesh Poyarekar

On 2023-01-31 09:11, Qing Zhao wrote:

Update documentation to clarify a GCC extension on structure with
flexible array member being nested in another structure.

gcc/ChangeLog:

* doc/extend.texi: Document GCC extension on a structure containing
a flexible array member to be a member of another structure.


Should this resolve pr#77650 since the proposed action there appears to 
be to document these semantics?


Thanks,
Sid


---
  gcc/doc/extend.texi | 35 ++-
  1 file changed, 34 insertions(+), 1 deletion(-)

diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 4a89a3eae7c..54e4baf49a9 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -1748,7 +1748,40 @@ Flexible array members may only appear as the last 
member of a
  A structure containing a flexible array member, or a union containing
  such a structure (possibly recursively), may not be a member of a
  structure or an element of an array.  (However, these uses are
-permitted by GCC as extensions.)
+permitted by GCC as extensions, see details below.)
+@end itemize
+
+GCC extension accepts a structure containing a flexible array member, or
+a union containing such a structure (possibly recursively) to be a member
+of a structure.
+
+There are two situations:
+
+@itemize @bullet
+@item
+The structure with a flexible array member is the last field of another
+structure, for example:
+
+@smallexample
+struct flex  @{ int length; char data[]; @};
+
+struct out_flex @{ int m; struct flex flex_data; @};
+@end smallexample
+
+In the above, @code{flex_data.data[]} is considered as a flexible array too.
+
+@item
+The structure with a flexible array member is the middle field of another
+structure, for example:
+
+@smallexample
+struct flex  @{ int length; char data[]; @};
+
+struct mid_flex @{ int m; struct flex flex_data; int n; @};
+@end smallexample
+
+In the above, @code{flex_data.data[]} is allowed to be extended flexibly to
+the padding. E.g, up to 4 elements.
  @end itemize
  
  Non-empty initialization of zero-length


Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]

2023-02-01 Thread Siddhesh Poyarekar

On 2023-01-31 09:11, Qing Zhao wrote:

GCC extension accepts the case when a struct with a flexible array member
is embedded into another struct (possibly recursively).
__builtin_object_size should treat such struct as flexible size per
-fstrict-flex-arrays.

PR tree-optimization/101832

gcc/ChangeLog:

PR tree-optimization/101832
* tree-object-size.cc (flexible_size_type_p): New function.
(addr_object_size): Handle structure/union type when it has
flexible size.

gcc/testsuite/ChangeLog:

PR tree-optimization/101832
* gcc.dg/builtin-object-size-pr101832-2.c: New test.
* gcc.dg/builtin-object-size-pr101832-3.c: New test.
* gcc.dg/builtin-object-size-pr101832-4.c: New test.
* gcc.dg/builtin-object-size-pr101832.c: New test.
---
  .../gcc.dg/builtin-object-size-pr101832-2.c   | 135 ++
  .../gcc.dg/builtin-object-size-pr101832-3.c   | 135 ++
  .../gcc.dg/builtin-object-size-pr101832-4.c   | 135 ++
  .../gcc.dg/builtin-object-size-pr101832.c | 119 +++
  gcc/tree-object-size.cc   | 115 +++
  5 files changed, 611 insertions(+), 28 deletions(-)
  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c

diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c 
b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
new file mode 100644
index 000..f38babc5415
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
@@ -0,0 +1,135 @@
+/* PR 101832:
+   GCC extension accepts the case when a struct with a flexible array member
+   is embedded into another struct (possibly recursively).
+   __builtin_object_size will treat such struct as flexible size per
+   -fstrict-flex-arrays.  */
+/* { dg-do run } */
+/* { dg-options "-O2 -fstrict-flex-arrays=1" } */
+
+#include 
+
+unsigned n_fails = 0;
+
+#define expect(p, _v) do { \
+  size_t v = _v; \
+  if (p == v) \
+printf("ok:  %s == %zd\n", #p, p); \
+  else {\
+printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
+n_fails++; \


I just pushed my testsuite fix, so you could use the macros in 
gcc.dg/builtin-object-size-common.h instead of accounting this yourself.


Also if you use __builtin_printf, you won't have to include stdio.h.

Thanks,
Sid


+  } \
+} while (0);
+
+struct A {
+  int n;
+  char data[];/* Content following header */
+};
+
+struct B {
+  int m;
+  struct A a;
+};
+
+struct C {
+  int q;
+  struct B b;
+};
+
+struct A0 {
+  int n;
+  char data[0];/* Content following header */
+};
+
+struct B0 {
+  int m;
+  struct A0 a;
+};
+
+struct C0 {
+  int q;
+  struct B0 b;
+};
+
+struct A1 {
+  int n;
+  char data[1];/* Content following header */
+};
+
+struct B1 {
+  int m;
+  struct A1 a;
+};
+
+struct C1 {
+  int q;
+  struct B1 b;
+};
+
+struct An {
+  int n;
+  char data[8];/* Content following header */
+};
+
+struct Bn {
+  int m;
+  struct An a;
+};
+
+struct Cn {
+  int q;
+  struct Bn b;
+};
+
+volatile void *magic1, *magic2;
+
+int main(int argc, char *argv[])
+{
+struct B *outer;
+struct C *outest;
+
+/* Make sure optimization can't find some other object size. */
+outer = (void *)magic1;
+outest = (void *)magic2;
+
+expect(__builtin_object_size(>a, 1), -1);
+expect(__builtin_object_size(>b, 1), -1);
+expect(__builtin_object_size(>b.a, 1), -1);
+
+struct B0 *outer0;
+struct C0 *outest0;
+
+/* Make sure optimization can't find some other object size. */
+outer0 = (void *)magic1;
+outest0 = (void *)magic2;
+
+expect(__builtin_object_size(>a, 1), -1);
+expect(__builtin_object_size(>b, 1), -1);
+expect(__builtin_object_size(>b.a, 1), -1);
+
+struct B1 *outer1;
+struct C1 *outest1;
+
+/* Make sure optimization can't find some other object size. */
+outer1 = (void *)magic1;
+outest1 = (void *)magic2;
+
+expect(__builtin_object_size(>a, 1), -1);
+expect(__builtin_object_size(>b, 1), -1);
+expect(__builtin_object_size(>b.a, 1), -1);
+
+struct Bn *outern;
+struct Cn *outestn;
+
+/* Make sure optimization can't find some other object size. */
+outern = (void *)magic1;
+outestn = (void *)magic2;
+
+expect(__builtin_object_size(>a, 1), sizeof(outern->a));
+expect(__builtin_object_size(>b, 1), sizeof(outestn->b));
+expect(__builtin_object_size(>b.a, 1), sizeof(outestn->b.a));
+
+if (n_fails > 0)
+  __builtin_abort ();
+
+return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c 
b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
new file mode 100644
index 000..aaae99b8d67
--- /dev/null
+++ 

[committed v2] testsuite: Run __bos tests to completion

2023-02-01 Thread Siddhesh Poyarekar
Instead of failing on first error, run all __builtin_object_size and
__builtin_dynamic_object_size tests to completion and then provide a
summary of which tests failed.

gcc/testsuite/ChangeLog:

* gcc.dg/builtin-dynamic-object-size-0.c: Move FAIL and nfail
into...
* gcc.dg/builtin-object-size-common.h: ... new file.
* g++.dg/ext/builtin-object-size1.C: Include
builtin-object-size-common.h.  Replace all abort with FAIL.
(main): Call DONE.
* g++.dg/ext/builtin-object-size2.C: Likewise.
* gcc.dg/builtin-object-size-1.c: Likewise.
* gcc.dg/builtin-object-size-12.c: Likewise.
* gcc.dg/builtin-object-size-13.c: Likewise.
* gcc.dg/builtin-object-size-15.c: Likewise.
* gcc.dg/builtin-object-size-2.c: Likewise.
* gcc.dg/builtin-object-size-3.c: Likewise.
* gcc.dg/builtin-object-size-4.c: Likewise.
* gcc.dg/builtin-object-size-6.c: Likewise.
* gcc.dg/builtin-object-size-7.c: Likewise.
* gcc.dg/builtin-object-size-8.c: Likewise.
* gcc.dg/pr101836.c: Likewise.
* gcc.dg/strict-flex-array-3.c: Likewise.

Signed-off-by: Siddhesh Poyarekar 
---
 .../g++.dg/ext/builtin-object-size1.C | 260 ---
 .../g++.dg/ext/builtin-object-size2.C | 260 ---
 .../gcc.dg/builtin-dynamic-object-size-0.c|  14 +-
 gcc/testsuite/gcc.dg/builtin-object-size-1.c  | 297 -
 gcc/testsuite/gcc.dg/builtin-object-size-12.c |  12 +-
 gcc/testsuite/gcc.dg/builtin-object-size-13.c |  15 +-
 gcc/testsuite/gcc.dg/builtin-object-size-15.c |  11 +-
 gcc/testsuite/gcc.dg/builtin-object-size-2.c  | 305 +-
 gcc/testsuite/gcc.dg/builtin-object-size-3.c  | 275 
 gcc/testsuite/gcc.dg/builtin-object-size-4.c  | 285 
 gcc/testsuite/gcc.dg/builtin-object-size-6.c  | 260 ---
 gcc/testsuite/gcc.dg/builtin-object-size-7.c  |  54 ++--
 gcc/testsuite/gcc.dg/builtin-object-size-8.c  |  15 +-
 .../gcc.dg/builtin-object-size-common.h   |  32 ++
 gcc/testsuite/gcc.dg/pr101836.c   |  10 +-
 gcc/testsuite/gcc.dg/strict-flex-array-3.c|  10 +-
 16 files changed, 1039 insertions(+), 1076 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-common.h

diff --git a/gcc/testsuite/g++.dg/ext/builtin-object-size1.C 
b/gcc/testsuite/g++.dg/ext/builtin-object-size1.C
index 8590a0bbebd..ebbeced1942 100644
--- a/gcc/testsuite/g++.dg/ext/builtin-object-size1.C
+++ b/gcc/testsuite/g++.dg/ext/builtin-object-size1.C
@@ -1,11 +1,7 @@
 // { dg-do run }
 // { dg-options "-O2" }
 
-typedef __SIZE_TYPE__ size_t;
-extern "C" void abort ();
-extern "C" void exit (int);
-extern "C" void *malloc (size_t);
-extern "C" void free (void *);
+#include "../../gcc.dg/builtin-object-size-common.h"
 
 struct A
 {
@@ -20,105 +16,105 @@ test1 (A *p)
 {
   char *c;
   if (__builtin_object_size (>a, 0) != (size_t) -1)
-abort ();
+FAIL ();
   if (__builtin_object_size (>a[0], 0) != (size_t) -1)
-abort ();
+FAIL ();
   if (__builtin_object_size (>a[3], 0) != (size_t) -1)
-abort ();
+FAIL ();
   if (__builtin_object_size (>b, 0) != (size_t) -1)
-abort ();
+FAIL ();
   if (__builtin_object_size (>c, 0) != (size_t) -1)
-abort ();
+FAIL ();
   c = p->a;
   if (__builtin_object_size (c, 0) != (size_t) -1)
-abort ();
+FAIL ();
   c = >a[0];
   if (__builtin_object_size (c, 0) != (size_t) -1)
-abort ();
+FAIL ();
   c = >a[3];
   if (__builtin_object_size (c, 0) != (size_t) -1)
-abort ();
+FAIL ();
   c = (char *) >b;
   if (__builtin_object_size (c, 0) != (size_t) -1)
-abort ();
+FAIL ();
   c = (char *) >c;
   if (__builtin_object_size (c, 0) != (size_t) -1)
-abort ();
+FAIL ();
   if (__builtin_object_size (>a, 1) != sizeof (p->a))
-abort ();
+FAIL ();
   if (__builtin_object_size (>a[0], 1) != sizeof (p->a))
-abort ();
+FAIL ();
   if (__builtin_object_size (>a[3], 1) != sizeof (p->a) - 3)
-abort ();
+FAIL ();
   if (__builtin_object_size (>b, 1) != sizeof (p->b))
-abort ();
+FAIL ();
   if (__builtin_object_size (>c, 1) != (size_t) -1)
-abort ();
+FAIL ();
   c = p->a;
   if (__builtin_object_size (c, 1) != sizeof (p->a))
-abort ();
+FAIL ();
   c = >a[0];
   if (__builtin_object_size (c, 1) != sizeof (p->a))
-abort ();
+FAIL ();
   c = >a[3];
   if (__builtin_object_size (c, 1) != sizeof (p->a) - 3)
-abort ();
+FAIL ();
   c = (char *) >b;
   if (__builtin_object_size (c, 1) != sizeof (p->b))
-abort ();
+FAIL ();
   c = (char *) >c;
   if (__builtin_object_size (c, 1) != (size_t) -1)
-abort ();
+FAIL ();
   if (__builtin_object_size (>a, 2) != 0)
-abort ();
+FAIL ();
   if (__builtin_object_size (>a

Re: [PATCH 2/2] tree-object-size: More consistent behaviour with flex arrays

2023-01-31 Thread Siddhesh Poyarekar

On 2023-01-31 07:46, Jakub Jelinek wrote:

On Wed, Dec 21, 2022 at 05:25:54PM -0500, Siddhesh Poyarekar wrote:

The tree object size pass tries to fail when it detects a flex array in
the struct, but it ends up doing the right thing only when the flex
array is in the outermost struct.  For nested cases (such as arrays
nested in a union or an inner struct), it ends up taking whatever value
the flex array is declared with, using zero for the standard flex array,
i.e. [].

Rework subobject size computation to make it more consistent across the
board, honoring -fstrict-flex-arrays.  With this change, any array at
the end of the struct will end up causing __bos to use the allocated
value of the outer object, bailing out in the maximum case when it can't
find it.  In the minimum case, it will return the subscript value or the
allocated value of the outer object, whichever is larger.


I think it is way too late in the GCC 13 cycle to change behavior here
except for when -fstrict-flex-arrays is used.


I agree.


Plus, am not really convinced it is a good idea to change the behavior
here except for the new options, programs in the wild took 2+ years
to acommodate for what we GCC requiring and am not sure they'd be willing
to be adjusted again.


The behaviour change basically does two things: better minimum object 
size estimates and more conservative object size estimates for trailing 
arrays.  ISTM that this should in fact reduce breakages due to flex 
arrays, although one could argue that protection gets reduced for 
trailing arrays without -fstrict-flex-arrays.  It wouldn't cause 
non-mitigation behaviour changes though, would it?


We don't need to rush this of course, we could consider this for gcc 14 
given that we're well into stage 4.


Thanks,
Sid


Re: [PATCH 2/2] tree-object-size: More consistent behaviour with flex arrays

2023-01-26 Thread Siddhesh Poyarekar

On 2023-01-26 11:20, Qing Zhao wrote:

Hi, Siddhesh,

Thanks a lot for this patch, after -fstrict-flex-array functionality has been 
added into GCC,
  I think that making the tree-object-size to have consistent behavior with 
flex arrays is a
valuable and natural work that need to be added.

I also like the comments you added into tree-object-size.cc, making the code 
much easier to be understood.

Minor comments below:


On Dec 21, 2022, at 5:25 PM, Siddhesh Poyarekar  wrote:

The tree object size pass tries to fail when it detects a flex array in
the struct, but it ends up doing the right thing only when the flex
array is in the outermost struct.  For nested cases (such as arrays
nested in a union or an inner struct), it ends up taking whatever value
the flex array is declared with, using zero for the standard flex array,
i.e. [].

Rework subobject size computation to make it more consistent across the
board, honoring -fstrict-flex-arrays.  With this change, any array at
the end of the struct will end up causing __bos to use the allocated
value of the outer object, bailing out in the maximum case when it can't
find it.  In the minimum case, it will return the subscript value or the
allocated value of the outer object, whichever is larger.


I see from the changes in the testing case, there are the following major 
changes for the existing behavior (can be show with the testing case)


For non-nested structures:

struct A
{
   char a[10];
   int b;
   char c[10];
};

1.  The Minimum size of the reference to the subobject that is a trailing array of a 
structure is changed from “0” to “sizeof the subobject"

-  if (__builtin_object_size (>c, 3) != 0)

+  if (__builtin_object_size (>c, 3) != 10)

For nested structures:

struct D
{
   int i;
   struct D1
   {
 char b;
 char a[10];
   } j;
};

2.   The Maximum size of the reference to the subobject that is a trailing array of 
the inner structure is changed from “sizeof the subobject” to “-1"

-  if (__builtin_object_size (>j.a[3], 1) != sizeof (d->j.a) - 3)
+  if (__builtin_object_size (>j.a[3], 1) != (size_t) -1)


.
3.  The Minimum size of the reference to the subobject that is a trailing array of 
the inner structure is changed from “0” to “sizeof the subobject"
-  if (__builtin_object_size ((char *) >j[0], 3) != 0)

+  if (__builtin_object_size ((char *) >j[0], 3) != sizeof (e->j))


All of the above is correct, thanks for the high level review!



I think that all the above changes are good. My only concern is, for the change 
of the Minimum size of the reference to the subobject that is a trailing array 
(the above case 1 and 3), will there be any negtive impact on the existing 
application that use it?


I doubt it, because the 0 return value for minimum object size is 
essentially a failure to determine minimum object size, i.e. a special 
value.  This change can be interpreted as succeeding to get the minimum 
object size in more cases.


Likewise for the maximum object size change, the change can be 
interpreted as failing to get the maximum object size in more cases. 
Does that sound reasonable?



+ /* If the subobject size cannot be easily inferred or is smaller than
+the whole size, just use the whole size.  */


Should the above comment be:

+ /* If the subobject size cannot be easily inferred or is larger than
+the whole size, just use the whole size.  */


  if (! TYPE_SIZE_UNIT (TREE_TYPE (var))
  || ! tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (var)))
  || (pt_var_size && TREE_CODE (pt_var_size) == INTEGER_CST
  && tree_int_cst_lt (pt_var_size,
  TYPE_SIZE_UNIT (TREE_TYPE (var)
var = pt_var;




Oops, yes indeed, fixed in my copy.

Thanks,
Sid


[PATCH] tree-optimization/108522 Use component_ref_field_offset

2023-01-25 Thread Siddhesh Poyarekar
Instead of using TREE_OPERAND (expr, 2) directly, use
component_ref_field_offset instead, which does scaling for us.  The
function also substitutes PLACEHOLDER_EXPRs, which is probably what we
want anyway but I'm not sure if it's relevant for tree-object-size.

gcc/ChangeLog:

PR tree-optimization/108522
* tree-object-size.cc (compute_object_offset): Make EXPR
argument non-const.  Call component_ref_field_offset.

gcc/testsuite/ChangeLog:

PR tree-optimization/108522
* gcc.dg/builtin-dynamic-object-size-0.c (DEFSTRUCT): New
macro.
(test_dynarray_struct_member_b, test_dynarray_struct_member_c,
test_dynarray_struct_member_d,
test_dynarray_struct_member_subobj_b,
test_dynarray_struct_member_subobj_c,
test_dynarray_struct_member_subobj_d): New tests.
(main): Call them.

Signed-off-by: Siddhesh Poyarekar 
---
Testing:
- Tested i686 to confirm that there are no new regressions
- Tested x86_64 bootstrap and confirmed that there are no new
  regressions
- ubsan config bootstrap in progress

 .../gcc.dg/builtin-dynamic-object-size-0.c| 81 +--
 gcc/tree-object-size.cc   |  7 +-
 2 files changed, 77 insertions(+), 11 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
index 569c0a87722..76079d8702e 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -315,19 +315,70 @@ test_dynarray_struct_subobj2 (size_t sz, size_t off, 
size_t *objsz)
 }
 
 /* See pr #108522.  */
+
+#define DEFSTRUCT(_s, _n) \
+  struct DS  \
+{\
+  char a[_n];\
+  unsigned long long b;  \
+  int c; \
+  char d[2 * _n];\
+} _s
+
 size_t
 __attribute__ ((noinline))
-test_dynarray_struct_member (size_t sz)
+test_dynarray_struct_member_b (size_t sz)
 {
-  struct
-{
-  char a[sz];
-  char b;
-} s;
+  DEFSTRUCT (s, sz);
 
   return __builtin_dynamic_object_size (, 0);
 }
 
+size_t
+__attribute__ ((noinline))
+test_dynarray_struct_member_c (size_t sz)
+{
+  DEFSTRUCT (s, sz);
+
+  return __builtin_dynamic_object_size (, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_dynarray_struct_member_d (size_t sz, size_t offset)
+{
+  DEFSTRUCT (s, sz);
+
+  return __builtin_dynamic_object_size ([offset], 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_dynarray_struct_member_subobj_b (size_t sz)
+{
+  DEFSTRUCT (s, sz);
+
+  return __builtin_dynamic_object_size (, 1);
+}
+
+size_t
+__attribute__ ((noinline))
+test_dynarray_struct_member_subobj_c (size_t sz)
+{
+  DEFSTRUCT (s, sz);
+
+  return __builtin_dynamic_object_size (, 1);
+}
+
+size_t
+__attribute__ ((noinline))
+test_dynarray_struct_member_subobj_d (size_t sz, size_t offset)
+{
+  DEFSTRUCT (s, sz);
+
+  return __builtin_dynamic_object_size ([offset], 1);
+}
+
 size_t
 __attribute__ ((noinline))
 test_substring (size_t sz, size_t off)
@@ -633,7 +684,23 @@ main (int argc, char **argv)
   if (test_dynarray_struct_subobj2 (42, 4, )
 != objsz - 4 - sizeof (long) - sizeof (int))
 FAIL ();
-  if (test_dynarray_struct_member (42) != sizeof (char))
+  DEFSTRUCT(ds, 64);
+  const size_t n = sizeof (ds.a);
+  if (test_dynarray_struct_member_b (n)
+  != sizeof (ds) - __builtin_offsetof (struct DS, b))
+FAIL ();
+  if (test_dynarray_struct_member_c (n)
+  != sizeof (ds) - __builtin_offsetof (struct DS, c))
+FAIL ();
+  if (test_dynarray_struct_member_d (n, 0)
+  != sizeof (ds) - __builtin_offsetof (struct DS, d))
+FAIL ();
+  if (test_dynarray_struct_member_subobj_b (n) != sizeof (ds.b))
+FAIL ();
+  if (test_dynarray_struct_member_subobj_c (n) != sizeof (ds.c))
+FAIL ();
+  if (test_dynarray_struct_member_subobj_d (n, n - 2)
+  != sizeof (ds) - __builtin_offsetof (struct DS, d) - n + 2)
 FAIL ();
   if (test_substring_ptrplus (128, 4) != (128 - 4) * sizeof (int))
 FAIL ();
diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
index de93ffad9c9..9a936a91983 100644
--- a/gcc/tree-object-size.cc
+++ b/gcc/tree-object-size.cc
@@ -56,7 +56,7 @@ struct GTY(()) object_size
   tree wholesize;
 };
 
-static tree compute_object_offset (const_tree, const_tree);
+static tree compute_object_offset (tree, const_tree);
 static bool addr_object_size (struct object_size_info *,
  const_tree, int, tree *, tree *t = NULL);
 static tree alloc_object_size (const gcall *, int);
@@ -396,7 +396,7 @@ size_for_offset (tree sz, tree offset, tree wholesize

Re: [PATCH] tree-optimization/108522 Use COMPONENT_REF offset when available

2023-01-25 Thread Siddhesh Poyarekar

On 2023-01-25 02:44, Richard Biener wrote:

t = TREE_OPERAND (expr, 1);
-  off = size_binop (PLUS_EXPR, DECL_FIELD_OFFSET (t),
+  off = size_binop (PLUS_EXPR,
+   (TREE_OPERAND (expr, 2) ? TREE_OPERAND (expr, 2)
+: DECL_FIELD_OFFSET (t)),


That isn't correct - operand 2 is the field offset in units of
DECL_OFFSET_ALIGN (t) / BITS_PER_UNIT.
See component_ref_filed_offset (), maybe you should be using that
function instead?


Ahh, and it passed my testing only because I was testing a char. 
Thanks, I'll test and send an update with additional tests.


Thanks,
Sid


[PATCH] tree-optimization/108522 Use COMPONENT_REF offset when available

2023-01-24 Thread Siddhesh Poyarekar
Use the offset in TREE_OPERAND(component_ref, 2) when available instead
of DECL_FIELD_OFFSET when trying to compute offset for a COMPONENT_REF.

OK for gcc 13 and gcc 12?

Co-authored-by: Jakub Jelinek 

gcc/ChangeLog:

PR tree-optimization/108522
* tree-object-size.cc (compute_object_offset): Use
TREE_OPERAND(ref, 2) for COMPONENT_REF when available.

gcc/testsuite/ChangeLog:

PR tree-optimization/108522
* builtin-dynamic-object-size-0.c (test_dynarray_struct_member):
new test.
(main): Call it.

Signed-off-by: Siddhesh Poyarekar 
---
Testing:

- Bootstrapped on x86_64, I'm checking to confirm if a couple of
  seemingly unrelated failures are in fact unrelated.
- ubsan config bootstrap and i686 tests in progress

 .../gcc.dg/builtin-dynamic-object-size-0.c   | 16 
 gcc/tree-object-size.cc  |  4 +++-
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
index f9047a037d9..569c0a87722 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -314,6 +314,20 @@ test_dynarray_struct_subobj2 (size_t sz, size_t off, 
size_t *objsz)
   return __builtin_dynamic_object_size ([off], 1);
 }
 
+/* See pr #108522.  */
+size_t
+__attribute__ ((noinline))
+test_dynarray_struct_member (size_t sz)
+{
+  struct
+{
+  char a[sz];
+  char b;
+} s;
+
+  return __builtin_dynamic_object_size (, 0);
+}
+
 size_t
 __attribute__ ((noinline))
 test_substring (size_t sz, size_t off)
@@ -619,6 +633,8 @@ main (int argc, char **argv)
   if (test_dynarray_struct_subobj2 (42, 4, )
 != objsz - 4 - sizeof (long) - sizeof (int))
 FAIL ();
+  if (test_dynarray_struct_member (42) != sizeof (char))
+FAIL ();
   if (test_substring_ptrplus (128, 4) != (128 - 4) * sizeof (int))
 FAIL ();
   if (test_substring_ptrplus (128, 142) != 0)
diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
index 356591c22cc..de93ffad9c9 100644
--- a/gcc/tree-object-size.cc
+++ b/gcc/tree-object-size.cc
@@ -412,7 +412,9 @@ compute_object_offset (const_tree expr, const_tree var)
return base;
 
   t = TREE_OPERAND (expr, 1);
-  off = size_binop (PLUS_EXPR, DECL_FIELD_OFFSET (t),
+  off = size_binop (PLUS_EXPR,
+   (TREE_OPERAND (expr, 2) ? TREE_OPERAND (expr, 2)
+: DECL_FIELD_OFFSET (t)),
size_int (tree_to_uhwi (DECL_FIELD_BIT_OFFSET (t))
  / BITS_PER_UNIT));
   break;
-- 
2.38.1



[ping3][PATCH 0/2] __bos and flex arrays

2023-01-20 Thread Siddhesh Poyarekar

ping!

On 2022-12-21 17:25, Siddhesh Poyarekar wrote:

Hi,

The first patch in the series is just a minor test cleanup that I did to
make sure all tests in a test case run (instead of aborting at first
failure) and print the ones that failed.  The second patch is the actual
fix.

The patch intends to make __bos/__bdos do the right thing with structs
containing flex arrays, either directly or within nested structs and
unions.  This should improve minimum object size estimation in some
cases and also bail out more consistently so that flex arrays don't
cause false positives in fortification.

I've tested this with a bootstrap on x86_64 and also with
--with-build-config=bootstrap-ubsan to make sure that there are no new
failures due to this change.

Siddhesh Poyarekar (2):
   testsuite: Run __bos tests to completion
   tree-object-size: More consistent behaviour with flex arrays

  .../g++.dg/ext/builtin-object-size1.C | 267 
  .../g++.dg/ext/builtin-object-size2.C | 267 
  .../gcc.dg/builtin-dynamic-object-size-0.c|  14 +-
  gcc/testsuite/gcc.dg/builtin-object-size-1.c  | 263 
  gcc/testsuite/gcc.dg/builtin-object-size-12.c |  12 +-
  gcc/testsuite/gcc.dg/builtin-object-size-13.c |  17 +-
  gcc/testsuite/gcc.dg/builtin-object-size-15.c |  11 +-
  gcc/testsuite/gcc.dg/builtin-object-size-2.c  | 287 +-
  gcc/testsuite/gcc.dg/builtin-object-size-3.c  | 263 
  gcc/testsuite/gcc.dg/builtin-object-size-4.c  | 267 
  gcc/testsuite/gcc.dg/builtin-object-size-6.c  | 267 
  gcc/testsuite/gcc.dg/builtin-object-size-7.c  |  52 ++--
  gcc/testsuite/gcc.dg/builtin-object-size-8.c  |  17 +-
  .../gcc.dg/builtin-object-size-common.h   |  12 +
  .../gcc.dg/builtin-object-size-flex-common.h  |  90 ++
  ...n-object-size-flex-nested-struct-nonzero.c |   6 +
  ...ltin-object-size-flex-nested-struct-zero.c |   6 +
  .../builtin-object-size-flex-nested-struct.c  |  22 ++
  ...in-object-size-flex-nested-union-nonzero.c |   6 +
  ...iltin-object-size-flex-nested-union-zero.c |   6 +
  .../builtin-object-size-flex-nested-union.c   |  28 ++
  .../gcc.dg/builtin-object-size-flex-nonzero.c |   6 +
  .../gcc.dg/builtin-object-size-flex-zero.c|   6 +
  .../gcc.dg/builtin-object-size-flex.c |  18 ++
  gcc/testsuite/gcc.dg/pr101836.c   |  11 +-
  gcc/testsuite/gcc.dg/strict-flex-array-3.c|  11 +-
  gcc/tree-object-size.cc   | 150 -
  27 files changed, 1275 insertions(+), 1107 deletions(-)
  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-common.h
  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-flex-common.h
  create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-struct-nonzero.c
  create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-struct-zero.c
  create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-struct.c
  create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-union-nonzero.c
  create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-union-zero.c
  create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-union.c
  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-flex-nonzero.c
  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-flex-zero.c
  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-flex.c



[ping2][PATCH 0/2] __bos and flex arrays

2023-01-11 Thread Siddhesh Poyarekar

Ping!

On 2022-12-21 17:25, Siddhesh Poyarekar wrote:

Hi,

The first patch in the series is just a minor test cleanup that I did to
make sure all tests in a test case run (instead of aborting at first
failure) and print the ones that failed.  The second patch is the actual
fix.

The patch intends to make __bos/__bdos do the right thing with structs
containing flex arrays, either directly or within nested structs and
unions.  This should improve minimum object size estimation in some
cases and also bail out more consistently so that flex arrays don't
cause false positives in fortification.

I've tested this with a bootstrap on x86_64 and also with
--with-build-config=bootstrap-ubsan to make sure that there are no new
failures due to this change.

Siddhesh Poyarekar (2):
   testsuite: Run __bos tests to completion
   tree-object-size: More consistent behaviour with flex arrays

  .../g++.dg/ext/builtin-object-size1.C | 267 
  .../g++.dg/ext/builtin-object-size2.C | 267 
  .../gcc.dg/builtin-dynamic-object-size-0.c|  14 +-
  gcc/testsuite/gcc.dg/builtin-object-size-1.c  | 263 
  gcc/testsuite/gcc.dg/builtin-object-size-12.c |  12 +-
  gcc/testsuite/gcc.dg/builtin-object-size-13.c |  17 +-
  gcc/testsuite/gcc.dg/builtin-object-size-15.c |  11 +-
  gcc/testsuite/gcc.dg/builtin-object-size-2.c  | 287 +-
  gcc/testsuite/gcc.dg/builtin-object-size-3.c  | 263 
  gcc/testsuite/gcc.dg/builtin-object-size-4.c  | 267 
  gcc/testsuite/gcc.dg/builtin-object-size-6.c  | 267 
  gcc/testsuite/gcc.dg/builtin-object-size-7.c  |  52 ++--
  gcc/testsuite/gcc.dg/builtin-object-size-8.c  |  17 +-
  .../gcc.dg/builtin-object-size-common.h   |  12 +
  .../gcc.dg/builtin-object-size-flex-common.h  |  90 ++
  ...n-object-size-flex-nested-struct-nonzero.c |   6 +
  ...ltin-object-size-flex-nested-struct-zero.c |   6 +
  .../builtin-object-size-flex-nested-struct.c  |  22 ++
  ...in-object-size-flex-nested-union-nonzero.c |   6 +
  ...iltin-object-size-flex-nested-union-zero.c |   6 +
  .../builtin-object-size-flex-nested-union.c   |  28 ++
  .../gcc.dg/builtin-object-size-flex-nonzero.c |   6 +
  .../gcc.dg/builtin-object-size-flex-zero.c|   6 +
  .../gcc.dg/builtin-object-size-flex.c |  18 ++
  gcc/testsuite/gcc.dg/pr101836.c   |  11 +-
  gcc/testsuite/gcc.dg/strict-flex-array-3.c|  11 +-
  gcc/tree-object-size.cc   | 150 -
  27 files changed, 1275 insertions(+), 1107 deletions(-)
  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-common.h
  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-flex-common.h
  create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-struct-nonzero.c
  create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-struct-zero.c
  create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-struct.c
  create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-union-nonzero.c
  create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-union-zero.c
  create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-union.c
  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-flex-nonzero.c
  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-flex-zero.c
  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-flex.c



Re: [PATCH] tree-optimization/105043: Object Size Checking docs cleanup

2023-01-03 Thread Siddhesh Poyarekar

On 2022-12-27 13:25, Jeff Law wrote:



On 12/15/22 12:25, Siddhesh Poyarekar wrote:

Break the _FORTIFY_SOURCE-specific builtins out into a separate
subsection from Object Size Checking built-ins and mention
_FORTIFY_SOURCE in there so that the link between the object size
checking builtins, the helper builtins (e.g. __builtin___memcpy_chk) and
_FORTIFY_SOURCE is clearer.

gcc/ChangeLog:

PR tree-optimization/105043
* doc/extend.texi (Object Size Checking): Split out into two
subsections and mention _FORTIFY_SOURCE.

OK
jeff



Thanks, pushed.

Sid


[ping][PATCH 0/2] __bos and flex arrays

2023-01-03 Thread Siddhesh Poyarekar

Ping!

On 2022-12-21 17:25, Siddhesh Poyarekar wrote:

Hi,

The first patch in the series is just a minor test cleanup that I did to
make sure all tests in a test case run (instead of aborting at first
failure) and print the ones that failed.  The second patch is the actual
fix.

The patch intends to make __bos/__bdos do the right thing with structs
containing flex arrays, either directly or within nested structs and
unions.  This should improve minimum object size estimation in some
cases and also bail out more consistently so that flex arrays don't
cause false positives in fortification.

I've tested this with a bootstrap on x86_64 and also with
--with-build-config=bootstrap-ubsan to make sure that there are no new
failures due to this change.

Siddhesh Poyarekar (2):
   testsuite: Run __bos tests to completion
   tree-object-size: More consistent behaviour with flex arrays

  .../g++.dg/ext/builtin-object-size1.C | 267 
  .../g++.dg/ext/builtin-object-size2.C | 267 
  .../gcc.dg/builtin-dynamic-object-size-0.c|  14 +-
  gcc/testsuite/gcc.dg/builtin-object-size-1.c  | 263 
  gcc/testsuite/gcc.dg/builtin-object-size-12.c |  12 +-
  gcc/testsuite/gcc.dg/builtin-object-size-13.c |  17 +-
  gcc/testsuite/gcc.dg/builtin-object-size-15.c |  11 +-
  gcc/testsuite/gcc.dg/builtin-object-size-2.c  | 287 +-
  gcc/testsuite/gcc.dg/builtin-object-size-3.c  | 263 
  gcc/testsuite/gcc.dg/builtin-object-size-4.c  | 267 
  gcc/testsuite/gcc.dg/builtin-object-size-6.c  | 267 
  gcc/testsuite/gcc.dg/builtin-object-size-7.c  |  52 ++--
  gcc/testsuite/gcc.dg/builtin-object-size-8.c  |  17 +-
  .../gcc.dg/builtin-object-size-common.h   |  12 +
  .../gcc.dg/builtin-object-size-flex-common.h  |  90 ++
  ...n-object-size-flex-nested-struct-nonzero.c |   6 +
  ...ltin-object-size-flex-nested-struct-zero.c |   6 +
  .../builtin-object-size-flex-nested-struct.c  |  22 ++
  ...in-object-size-flex-nested-union-nonzero.c |   6 +
  ...iltin-object-size-flex-nested-union-zero.c |   6 +
  .../builtin-object-size-flex-nested-union.c   |  28 ++
  .../gcc.dg/builtin-object-size-flex-nonzero.c |   6 +
  .../gcc.dg/builtin-object-size-flex-zero.c|   6 +
  .../gcc.dg/builtin-object-size-flex.c |  18 ++
  gcc/testsuite/gcc.dg/pr101836.c   |  11 +-
  gcc/testsuite/gcc.dg/strict-flex-array-3.c|  11 +-
  gcc/tree-object-size.cc   | 150 -
  27 files changed, 1275 insertions(+), 1107 deletions(-)
  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-common.h
  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-flex-common.h
  create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-struct-nonzero.c
  create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-struct-zero.c
  create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-struct.c
  create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-union-nonzero.c
  create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-union-zero.c
  create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-union.c
  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-flex-nonzero.c
  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-flex-zero.c
  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-flex.c



[PATCH 1/2] testsuite: Run __bos tests to completion

2022-12-21 Thread Siddhesh Poyarekar
Instead of failing on first error, run all __builtin_object_size and
__builtin_dynamic_object_size tests to completion and then provide a
summary of which tests failed.

gcc/testsuite/ChangeLog:

* gcc.dg/builtin-dynamic-object-size-0.c: Move FAIL and nfail
into...
* gcc.dg/builtin-object-size-common.h: ... new file.
* g++.dg/ext/builtin-object-size1.C: Include
builtin-object-size-common.h.  Replace all abort with FAIL.
(main): Call DONE.
* g++.dg/ext/builtin-object-size2.C: Likewise.
* gcc.dg/builtin-object-size-1.c: Likewise.
* gcc.dg/builtin-object-size-12.c: Likewise.
* gcc.dg/builtin-object-size-13.c: Likewise.
* gcc.dg/builtin-object-size-15.c: Likewise.
* gcc.dg/builtin-object-size-2.c: Likewise.
* gcc.dg/builtin-object-size-3.c: Likewise.
* gcc.dg/builtin-object-size-4.c: Likewise.
* gcc.dg/builtin-object-size-6.c: Likewise.
* gcc.dg/builtin-object-size-7.c: Likewise.
* gcc.dg/builtin-object-size-8.c: Likewise.
* gcc.dg/pr101836.c: Likewise.
* gcc.dg/strict-flex-array-3.c: Likewise.

Signed-off-by: Siddhesh Poyarekar 
---
 .../g++.dg/ext/builtin-object-size1.C | 257 
 .../g++.dg/ext/builtin-object-size2.C | 257 
 .../gcc.dg/builtin-dynamic-object-size-0.c|  14 +-
 gcc/testsuite/gcc.dg/builtin-object-size-1.c  | 263 
 gcc/testsuite/gcc.dg/builtin-object-size-12.c |  12 +-
 gcc/testsuite/gcc.dg/builtin-object-size-13.c |  13 +-
 gcc/testsuite/gcc.dg/builtin-object-size-15.c |  11 +-
 gcc/testsuite/gcc.dg/builtin-object-size-2.c  | 287 +-
 gcc/testsuite/gcc.dg/builtin-object-size-3.c  | 263 
 gcc/testsuite/gcc.dg/builtin-object-size-4.c  | 267 
 gcc/testsuite/gcc.dg/builtin-object-size-6.c  | 257 
 gcc/testsuite/gcc.dg/builtin-object-size-7.c  |  52 ++--
 gcc/testsuite/gcc.dg/builtin-object-size-8.c  |  13 +-
 .../gcc.dg/builtin-object-size-common.h   |  12 +
 gcc/testsuite/gcc.dg/pr101836.c   |  11 +-
 gcc/testsuite/gcc.dg/strict-flex-array-3.c|  11 +-
 16 files changed, 1010 insertions(+), 990 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-common.h

diff --git a/gcc/testsuite/g++.dg/ext/builtin-object-size1.C 
b/gcc/testsuite/g++.dg/ext/builtin-object-size1.C
index 8590a0bbebd..165b415683b 100644
--- a/gcc/testsuite/g++.dg/ext/builtin-object-size1.C
+++ b/gcc/testsuite/g++.dg/ext/builtin-object-size1.C
@@ -1,8 +1,9 @@
 // { dg-do run }
 // { dg-options "-O2" }
 
+#include "../../gcc.dg/builtin-object-size-common.h"
+
 typedef __SIZE_TYPE__ size_t;
-extern "C" void abort ();
 extern "C" void exit (int);
 extern "C" void *malloc (size_t);
 extern "C" void free (void *);
@@ -20,105 +21,105 @@ test1 (A *p)
 {
   char *c;
   if (__builtin_object_size (>a, 0) != (size_t) -1)
-abort ();
+FAIL ();
   if (__builtin_object_size (>a[0], 0) != (size_t) -1)
-abort ();
+FAIL ();
   if (__builtin_object_size (>a[3], 0) != (size_t) -1)
-abort ();
+FAIL ();
   if (__builtin_object_size (>b, 0) != (size_t) -1)
-abort ();
+FAIL ();
   if (__builtin_object_size (>c, 0) != (size_t) -1)
-abort ();
+FAIL ();
   c = p->a;
   if (__builtin_object_size (c, 0) != (size_t) -1)
-abort ();
+FAIL ();
   c = >a[0];
   if (__builtin_object_size (c, 0) != (size_t) -1)
-abort ();
+FAIL ();
   c = >a[3];
   if (__builtin_object_size (c, 0) != (size_t) -1)
-abort ();
+FAIL ();
   c = (char *) >b;
   if (__builtin_object_size (c, 0) != (size_t) -1)
-abort ();
+FAIL ();
   c = (char *) >c;
   if (__builtin_object_size (c, 0) != (size_t) -1)
-abort ();
+FAIL ();
   if (__builtin_object_size (>a, 1) != sizeof (p->a))
-abort ();
+FAIL ();
   if (__builtin_object_size (>a[0], 1) != sizeof (p->a))
-abort ();
+FAIL ();
   if (__builtin_object_size (>a[3], 1) != sizeof (p->a) - 3)
-abort ();
+FAIL ();
   if (__builtin_object_size (>b, 1) != sizeof (p->b))
-abort ();
+FAIL ();
   if (__builtin_object_size (>c, 1) != (size_t) -1)
-abort ();
+FAIL ();
   c = p->a;
   if (__builtin_object_size (c, 1) != sizeof (p->a))
-abort ();
+FAIL ();
   c = >a[0];
   if (__builtin_object_size (c, 1) != sizeof (p->a))
-abort ();
+FAIL ();
   c = >a[3];
   if (__builtin_object_size (c, 1) != sizeof (p->a) - 3)
-abort ();
+FAIL ();
   c = (char *) >b;
   if (__builtin_object_size (c, 1) != sizeof (p->b))
-abort ();
+FAIL ();
   c = (char *) >c;
   if (__builtin_object_size (c, 1) != (size_t) -1)
-abort ();
+FAIL ();
   if (__builtin_object_size (>a, 2) != 0)
-abort ();
+FAIL ();
   if (__builtin_object_size (>a[0], 2) !

[PATCH 2/2] tree-object-size: More consistent behaviour with flex arrays

2022-12-21 Thread Siddhesh Poyarekar
The tree object size pass tries to fail when it detects a flex array in
the struct, but it ends up doing the right thing only when the flex
array is in the outermost struct.  For nested cases (such as arrays
nested in a union or an inner struct), it ends up taking whatever value
the flex array is declared with, using zero for the standard flex array,
i.e. [].

Rework subobject size computation to make it more consistent across the
board, honoring -fstrict-flex-arrays.  With this change, any array at
the end of the struct will end up causing __bos to use the allocated
value of the outer object, bailing out in the maximum case when it can't
find it.  In the minimum case, it will return the subscript value or the
allocated value of the outer object, whichever is larger.

gcc/ChangeLog:

PR tree-optimization/107952
* tree-object-size.cc (size_from_objects): New function.
(addr_object_size): Call it.  Fully rely on
array_ref_flexible_size_p call to determine flex array.

gcc/testsuite/ChangeLog:

PR tree-optimization/107952
* g++.dg/ext/builtin-object-size1.C (test1, test6, test7,
test8): Adjust expected result for object size type 3 and 1.
* g++.dg/ext/builtin-object-size2.C (test1, test6, test7,
test8): Likewise.
* gcc.dg/builtin-object-size-13.c (main): Likewise.
* gcc.dg/builtin-object-size-6.c (test1, test6, test7, test8):
Likewise.
* gcc.dg/builtin-object-size-8.c (main): Likewise.
* gcc.dg/builtin-object-size-flex-common.h: Common code for new
tests.
* gcc.dg/builtin-object-size-flex-nested-struct-nonzero.c: New
test.
* gcc.dg/builtin-object-size-flex-nested-struct-zero.c: New
test.
* gcc.dg/builtin-object-size-flex-nested-struct.c: New test.
* gcc.dg/builtin-object-size-flex-nested-union-nonzero.c: New
test.
* gcc.dg/builtin-object-size-flex-nested-union-zero.c: New test.
* gcc.dg/builtin-object-size-flex-nested-union.c: New test.
* gcc.dg/builtin-object-size-flex-nonzero.c: New test.
* gcc.dg/builtin-object-size-flex-zero.c: New test.
* gcc.dg/builtin-object-size-flex.c: New test.

Signed-off-by: Siddhesh Poyarekar 
---
 .../g++.dg/ext/builtin-object-size1.C |  10 +-
 .../g++.dg/ext/builtin-object-size2.C |  10 +-
 gcc/testsuite/gcc.dg/builtin-object-size-13.c |   4 +-
 gcc/testsuite/gcc.dg/builtin-object-size-6.c  |  10 +-
 gcc/testsuite/gcc.dg/builtin-object-size-8.c  |   4 +-
 .../gcc.dg/builtin-object-size-flex-common.h  |  90 +++
 ...n-object-size-flex-nested-struct-nonzero.c |   6 +
 ...ltin-object-size-flex-nested-struct-zero.c |   6 +
 .../builtin-object-size-flex-nested-struct.c  |  22 +++
 ...in-object-size-flex-nested-union-nonzero.c |   6 +
 ...iltin-object-size-flex-nested-union-zero.c |   6 +
 .../builtin-object-size-flex-nested-union.c   |  28 
 .../gcc.dg/builtin-object-size-flex-nonzero.c |   6 +
 .../gcc.dg/builtin-object-size-flex-zero.c|   6 +
 .../gcc.dg/builtin-object-size-flex.c |  18 +++
 gcc/tree-object-size.cc   | 150 ++
 16 files changed, 265 insertions(+), 117 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-flex-common.h
 create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-struct-nonzero.c
 create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-struct-zero.c
 create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-struct.c
 create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-union-nonzero.c
 create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-union-zero.c
 create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-union.c
 create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-flex-nonzero.c
 create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-flex-zero.c
 create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-flex.c

diff --git a/gcc/testsuite/g++.dg/ext/builtin-object-size1.C 
b/gcc/testsuite/g++.dg/ext/builtin-object-size1.C
index 165b415683b..5b863637123 100644
--- a/gcc/testsuite/g++.dg/ext/builtin-object-size1.C
+++ b/gcc/testsuite/g++.dg/ext/builtin-object-size1.C
@@ -103,7 +103,7 @@ test1 (A *p)
 FAIL ();
   if (__builtin_object_size (>b, 3) != sizeof (p->b))
 FAIL ();
-  if (__builtin_object_size (>c, 3) != 0)
+  if (__builtin_object_size (>c, 3) != 10)
 FAIL ();
   c = p->a;
   if (__builtin_object_size (c, 3) != sizeof (p->a))
@@ -118,7 +118,7 @@ test1 (A *p)
   if (__builtin_object_size (c, 3) != sizeof (p->b))
 FAIL ();
   c = (char *) >c;
-  if (__builtin_object_size (c, 3) != 0)
+  if (__builtin_object_size (c, 3) != 10)
 FAIL ();
 }
 
@@ -344,7 +344,7 @@ test6 (struct D *d)
 {
   if (__builtin_object_size (>j.a[3], 0) != (size_t) -1)
 FAIL ();
-  if (__builtin_object_

[PATCH 0/2] __bos and flex arrays

2022-12-21 Thread Siddhesh Poyarekar
Hi,

The first patch in the series is just a minor test cleanup that I did to
make sure all tests in a test case run (instead of aborting at first
failure) and print the ones that failed.  The second patch is the actual
fix.

The patch intends to make __bos/__bdos do the right thing with structs
containing flex arrays, either directly or within nested structs and
unions.  This should improve minimum object size estimation in some
cases and also bail out more consistently so that flex arrays don't
cause false positives in fortification.

I've tested this with a bootstrap on x86_64 and also with
--with-build-config=bootstrap-ubsan to make sure that there are no new
failures due to this change.

Siddhesh Poyarekar (2):
  testsuite: Run __bos tests to completion
  tree-object-size: More consistent behaviour with flex arrays

 .../g++.dg/ext/builtin-object-size1.C | 267 
 .../g++.dg/ext/builtin-object-size2.C | 267 
 .../gcc.dg/builtin-dynamic-object-size-0.c|  14 +-
 gcc/testsuite/gcc.dg/builtin-object-size-1.c  | 263 
 gcc/testsuite/gcc.dg/builtin-object-size-12.c |  12 +-
 gcc/testsuite/gcc.dg/builtin-object-size-13.c |  17 +-
 gcc/testsuite/gcc.dg/builtin-object-size-15.c |  11 +-
 gcc/testsuite/gcc.dg/builtin-object-size-2.c  | 287 +-
 gcc/testsuite/gcc.dg/builtin-object-size-3.c  | 263 
 gcc/testsuite/gcc.dg/builtin-object-size-4.c  | 267 
 gcc/testsuite/gcc.dg/builtin-object-size-6.c  | 267 
 gcc/testsuite/gcc.dg/builtin-object-size-7.c  |  52 ++--
 gcc/testsuite/gcc.dg/builtin-object-size-8.c  |  17 +-
 .../gcc.dg/builtin-object-size-common.h   |  12 +
 .../gcc.dg/builtin-object-size-flex-common.h  |  90 ++
 ...n-object-size-flex-nested-struct-nonzero.c |   6 +
 ...ltin-object-size-flex-nested-struct-zero.c |   6 +
 .../builtin-object-size-flex-nested-struct.c  |  22 ++
 ...in-object-size-flex-nested-union-nonzero.c |   6 +
 ...iltin-object-size-flex-nested-union-zero.c |   6 +
 .../builtin-object-size-flex-nested-union.c   |  28 ++
 .../gcc.dg/builtin-object-size-flex-nonzero.c |   6 +
 .../gcc.dg/builtin-object-size-flex-zero.c|   6 +
 .../gcc.dg/builtin-object-size-flex.c |  18 ++
 gcc/testsuite/gcc.dg/pr101836.c   |  11 +-
 gcc/testsuite/gcc.dg/strict-flex-array-3.c|  11 +-
 gcc/tree-object-size.cc   | 150 -
 27 files changed, 1275 insertions(+), 1107 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-common.h
 create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-flex-common.h
 create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-struct-nonzero.c
 create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-struct-zero.c
 create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-struct.c
 create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-union-nonzero.c
 create mode 100644 
gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-union-zero.c
 create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-flex-nested-union.c
 create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-flex-nonzero.c
 create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-flex-zero.c
 create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-flex.c

-- 
2.38.1



[PATCH] tree-optimization/105043: Object Size Checking docs cleanup

2022-12-15 Thread Siddhesh Poyarekar
Break the _FORTIFY_SOURCE-specific builtins out into a separate
subsection from Object Size Checking built-ins and mention
_FORTIFY_SOURCE in there so that the link between the object size
checking builtins, the helper builtins (e.g. __builtin___memcpy_chk) and
_FORTIFY_SOURCE is clearer.

gcc/ChangeLog:

PR tree-optimization/105043
* doc/extend.texi (Object Size Checking): Split out into two
subsections and mention _FORTIFY_SOURCE.

Signed-off-by: Siddhesh Poyarekar 
---
 gcc/doc/extend.texi | 20 ++--
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 608ff54f845..8cff7dd65dd 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -12796,7 +12796,9 @@ __atomic_store_n(, 0, 
__ATOMIC_RELEASE|__ATOMIC_HLE_RELEASE);
 @end smallexample
 
 @node Object Size Checking
-@section Object Size Checking Built-in Functions
+@section Object Size Checking
+
+@subsection Object Size Checking Built-in Functions
 @findex __builtin_object_size
 @findex __builtin_dynamic_object_size
 @findex __builtin___memcpy_chk
@@ -12878,11 +12880,17 @@ which objects @var{ptr} points to at compile time are 
the same as in the case
 of @code{__builtin_object_size}.
 @end deftypefn
 
-There are built-in functions added for many common string operation
-functions, e.g., for @code{memcpy} @code{__builtin___memcpy_chk}
-built-in is provided.  This built-in has an additional last argument,
-which is the number of bytes remaining in the object the @var{dest}
-argument points to or @code{(size_t) -1} if the size is not known.
+@subsection Object Size Checking and Source Fortification
+
+Hardening of function calls using the @code{_FORTIFY_SOURCE} macro is
+one of the key uses of the object size checking built-in functions.  To
+make implementation of these features more convenient and improve
+optimization and diagnostics, there are built-in functions added for
+many common string operation functions, e.g., for @code{memcpy}
+@code{__builtin___memcpy_chk} built-in is provided.  This built-in has
+an additional last argument, which is the number of bytes remaining in
+the object the @var{dest} argument points to or @code{(size_t) -1} if
+the size is not known.
 
 The built-in functions are optimized into the normal string functions
 like @code{memcpy} if the last argument is @code{(size_t) -1} or if
-- 
2.38.1



Re: [PATCH] doc: Fix documentation for __builtin_dynamic_object_size

2022-12-15 Thread Siddhesh Poyarekar

On 2022-12-15 12:09, Jakub Jelinek wrote:

-This is a propagation pass similar to CCP that tries to remove calls
-to @code{__builtin_object_size} when the size of the object can be
-computed at compile-time.  This pass is located in
-@file{tree-object-size.cc} and is described by
+This is a propagation pass similar to CCP that tries to remove calls to
+@code{__builtin_object_size} or @code{__builtin_dynamic_object_size}
+when the size of the object can be computed at compile-time.  This pass


Can be computed at compile-time is only true for __bos, for
__bdos is if it can be computed.


How about:


This is a propagation pass similar to CCP that tries to remove calls to
@code{__builtin_object_size} when the size of the object can be computed 
at compile-time.  It also tries to replace calls to 


@code{__builtin_dynamic_object_size} with an expression that evaluates
the size of the object.  This pass is located in
@file{tree-object-size.cc} and is described by @code{pass_object_sizes}.


[PATCH] doc: Fix documentation for __builtin_dynamic_object_size

2022-12-15 Thread Siddhesh Poyarekar
__builtin_dynamic_object_size is missing from the full list of builtins,
so add it.  Also mention it alongside __builtin_object_size in the
passes description.

gcc/ChangeLog:

* doc/extend.texi (__builtin_dynamic_object_size): Document
builtin.
* doc/passes.texi
(Optimize calls to @code{__builtin_object_size}): Also mention
__builtin_dynamic_object_size.

Signed-off-by: Siddhesh Poyarekar 
---
 gcc/doc/extend.texi | 10 --
 gcc/doc/passes.texi | 11 ++-
 2 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index d3812fa55b0..608ff54f845 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -14291,8 +14291,14 @@ and GCC does not issue a warning.
 @end deftypefn
 
 @deftypefn {Built-in Function}{size_t} __builtin_object_size (const void * 
@var{ptr}, int @var{type})
-Returns the size of an object pointed to by @var{ptr}.  @xref{Object Size
-Checking}, for a detailed description of the function.
+Returns a constant size estimate of an object pointed to by @var{ptr}.
+@xref{Object Size Checking}, for a detailed description of the function.
+@end deftypefn
+
+@deftypefn {Built-in Function}{size_t} __builtin_dynamic_object_size (const 
void * @var{ptr}, int @var{type})
+Similar to @code{__builtin_object_size} except that the return value
+need not be a constant.  @xref{Object Size Checking}, for a detailed
+description of the function.
 @end deftypefn
 
 @deftypefn {Built-in Function} double __builtin_huge_val (void)
diff --git a/gcc/doc/passes.texi b/gcc/doc/passes.texi
index 9e8b4f50ad6..d649db72bbe 100644
--- a/gcc/doc/passes.texi
+++ b/gcc/doc/passes.texi
@@ -843,12 +843,13 @@ foo()}, this pass tries to change the call so that the 
address of
 pass is located in @code{tree-nrv.cc} and is described by
 @code{pass_return_slot}.
 
-@item Optimize calls to @code{__builtin_object_size}
+@item Optimize calls to @code{__builtin_object_size} or
+@code{__builtin_dynamic_object_size}
 
-This is a propagation pass similar to CCP that tries to remove calls
-to @code{__builtin_object_size} when the size of the object can be
-computed at compile-time.  This pass is located in
-@file{tree-object-size.cc} and is described by
+This is a propagation pass similar to CCP that tries to remove calls to
+@code{__builtin_object_size} or @code{__builtin_dynamic_object_size}
+when the size of the object can be computed at compile-time.  This pass
+is located in @file{tree-object-size.cc} and is described by
 @code{pass_object_sizes}.
 
 @item Loop invariant motion
-- 
2.38.1



[PATCH] middle-end/70090: Document that -fsanitize=object-size uses dynamic size

2022-12-15 Thread Siddhesh Poyarekar
Fix the documentation to say that object sizes are deduced using
__builtin_dynamic_object_size.

gcc/ChangeLog:

PR middle-end/70090
* gcc/doc/invoke.texi (-fsanitize=object-size): Use
__builtin_dynamic_object_size instead of
__builtin_object_size.

Signed-off-by: Siddhesh Poyarekar 
---
 gcc/doc/invoke.texi | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index f48df64cc2a..a50417a4ab7 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -16744,8 +16744,8 @@ or when a method or constructor is invoked on 
insufficiently aligned object.
 @item -fsanitize=object-size
 @opindex fsanitize=object-size
 This option enables instrumentation of memory references using the
-@code{__builtin_object_size} function.  Various out of bounds pointer
-accesses are detected.
+@code{__builtin_dynamic_object_size} function.  Various out of bounds
+pointer accesses are detected.
 
 @item -fsanitize=float-divide-by-zero
 @opindex fsanitize=float-divide-by-zero
-- 
2.38.1



Re: [PATCH] testsuite: Fix leaks in tree-dynamic-object-size-0.c

2022-12-05 Thread Siddhesh Poyarekar

On 2022-12-05 11:38, Jeff Law wrote:



On 12/5/22 07:28, Siddhesh Poyarekar wrote:

In commit e5cfb9cac1d7aba9a8ea73bfe7922cfaff9d61f3 I introduced tests
for strdup and strndup with leaks.  Fix those leaks.

gcc/testsuite/ChangeLog:

* gcc.dg/builtin-dynamic-object-size-0.c (test_strdup,
test_strndup, test_strdup_min, test_strndup_min): Free RES
before returning from function.
We don't generally worry about these kinds of issues in the testsuite. 
My only worry would be compromising the test.  By adding the free calls 
the compiler might match up the allocation and release and potentially 
turn it into an alloca.  I don't think we're likely to do that in this 
case, but it's worth keeping in mind.


Ack, thanks, I'll keep that in mind.

So OK as long as you've verified the test still does what it's supposed 
to do.


I have verified that the test still works correctly and the optimizer 
hasn't done anything funny with the calls, i.e. the str*dup calls and 
free calls are as is.


Thanks,
Sid


[PATCH] testsuite: Fix leaks in tree-dynamic-object-size-0.c

2022-12-05 Thread Siddhesh Poyarekar
In commit e5cfb9cac1d7aba9a8ea73bfe7922cfaff9d61f3 I introduced tests
for strdup and strndup with leaks.  Fix those leaks.

gcc/testsuite/ChangeLog:

* gcc.dg/builtin-dynamic-object-size-0.c (test_strdup,
test_strndup, test_strdup_min, test_strndup_min): Free RES
before returning from function.
---
 .../gcc.dg/builtin-dynamic-object-size-0.c| 20 +++
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
index 4f1606a486b..f9047a037d9 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -486,7 +486,10 @@ __attribute__ ((noinline))
 test_strdup (const char *in)
 {
   char *res = __builtin_strdup (in);
-  return __builtin_dynamic_object_size (res, 0);
+  size_t sz = __builtin_dynamic_object_size (res, 0);
+
+  __builtin_free (res);
+  return sz;
 }
 
 size_t
@@ -494,7 +497,10 @@ __attribute__ ((noinline))
 test_strndup (const char *in, size_t bound)
 {
   char *res = __builtin_strndup (in, bound);
-  return __builtin_dynamic_object_size (res, 0);
+  size_t sz = __builtin_dynamic_object_size (res, 0);
+
+  __builtin_free (res);
+  return sz;
 }
 
 size_t
@@ -502,7 +508,10 @@ __attribute__ ((noinline))
 test_strdup_min (const char *in)
 {
   char *res = __builtin_strdup (in);
-  return __builtin_dynamic_object_size (res, 2);
+  size_t sz = __builtin_dynamic_object_size (res, 2);
+
+  __builtin_free (res);
+  return sz;
 }
 
 size_t
@@ -510,7 +519,10 @@ __attribute__ ((noinline))
 test_strndup_min (const char *in, size_t bound)
 {
   char *res = __builtin_strndup (in, bound);
-  return __builtin_dynamic_object_size (res, 2);
+  size_t sz = __builtin_dynamic_object_size (res, 2);
+
+  __builtin_free (res);
+  return sz;
 }
 
 /* Other tests.  */
-- 
2.38.1



Re: [V2][PATCH 1/1] Add a new warning option -Wstrict-flex-arrays.

2022-12-01 Thread Siddhesh Poyarekar

On 2022-12-01 18:19, Kees Cook wrote:

On Thu, Dec 01, 2022 at 10:27:41PM +, Qing Zhao wrote:

Hi, Sid,

Thanks a lot for the input.

After more thinking based on your and Kees’ comments, I have the following 
thought:

1. -fstrict-flex-arrays=level should control both GCC code gen and warnings 
consistently;
2. We need warnings specifically for -fstrict-flex-arrays=level to report any 
misuse of flexible
  array corresponding to the “level” to gradually encourage language 
standard.

So, based on the above two, I think what I did in this current patch is correct:

1.  We eliminate the control from -Warray-bounds=level on treating flex arrays,
  now only "-fstrict-flex-arrasy=level" controls how the warning treating 
the flex arrays.
2.  We add a separate new warning -Wstrict-flex-arrays to report any misuse 
corresponding to
  the different level of -fstrict-flex-arrays.

Although we can certainly merge these new warnings into -Warray-bounds, 
however, as Sid mentioned,
-Warray-bounds does issue a lot more warnings than just flexible arrays misuse. 
I think it’s necessary
To provide a seperate warning to only issue flexible array misuse.

Let me know if you have any more comments on this.


That's how I understood Richard's comment.


Okay, that seems good. Given that -Warray-bounds is part of -Wall, what
should happen for -Wstrict-flex-arrays=N?


I suppose it would be independent of -Wall, dependent completely on 
-fstrict-flex-arrays.


Thanks,
Sid


Re: [V2][PATCH 1/1] Add a new warning option -Wstrict-flex-arrays.

2022-12-01 Thread Siddhesh Poyarekar

On 2022-12-01 11:42, Kees Cook wrote:

On Wed, Nov 30, 2022 at 02:25:56PM +, Qing Zhao wrote:

'-Wstrict-flex-arrays'
  Warn about inproper usages of flexible array members according to
  the LEVEL of the 'strict_flex_array (LEVEL)' attribute attached to
  the trailing array field of a structure if it's available,
  otherwise according to the LEVEL of the option
  '-fstrict-flex-arrays=LEVEL'.

  This option is effective only when LEVEL is bigger than 0.
  Otherwise, it will be ignored with a warning.

  when LEVEL=1, warnings will be issued for a trailing array
  reference of a structure that have 2 or more elements if the
  trailing array is referenced as a flexible array member.

  when LEVEL=2, in addition to LEVEL=1, additional warnings will be
  issued for a trailing one-element array reference of a structure if
  the array is referenced as a flexible array member.

  when LEVEL=3, in addition to LEVEL=2, additional warnings will be
  issued for a trailing zero-length array reference of a structure if
  the array is referenced as a flexible array member.

At the same time, -Warray-bounds is updated:


Why is there both -Wstrict-flex-arrays and -Warray-bounds? I thought
only the latter was going to exist?


Oh my understanding of the consensus was to move flex array related 
diagnosis from -Warray-bounds to -Wstring-flex-arrays as Qing has done. 
If only the former exists then instead of removing the flex array 
related statement in the documentation as Richard suggested, we need to 
enhance it to say that behaviour of -Warray-bounds will depend on 
-fstrict-flex-arrays.


-Warray-bounds does diagnosis beyond just flexible arrays, in case 
that's the confusion.


Sid


Re: [PATCH v2] tree-object-size: Support strndup and strdup

2022-11-22 Thread Siddhesh Poyarekar

On 2022-11-22 15:43, Jeff Law wrote:


On 11/21/22 07:27, Siddhesh Poyarekar wrote:

On 2022-11-20 10:42, Jeff Law wrote:


On 11/4/22 06:48, Siddhesh Poyarekar wrote:
Use string length of input to strdup to determine the usable size of 
the

resulting object.  Avoid doing the same for strndup since there's a
chance that the input may be too large, resulting in an unnecessary
overhead or worse, the input may not be NULL terminated, resulting in a
crash where there would otherwise have been none.

gcc/ChangeLog:

* tree-object-size.cc (todo): New variable.
(object_sizes_execute): Use it.
(strdup_object_size): New function.
(call_object_size): Use it.

gcc/testsuite/ChangeLog:

* gcc.dg/builtin-dynamic-object-size-0.c (test_strdup,
test_strndup, test_strdup_min, test_strndup_min): New tests.
(main): Call them.
* gcc.dg/builtin-dynamic-object-size-1.c: Silence overread
warnings.
* gcc.dg/builtin-dynamic-object-size-2.c: Likewise.
* gcc.dg/builtin-dynamic-object-size-3.c: Likewise.
* gcc.dg/builtin-dynamic-object-size-4.c: Likewise.
* gcc.dg/builtin-object-size-1.c: Silence overread warnings.
Declare free, strdup and strndup.
(test11): New test.
(main): Call it.
* gcc.dg/builtin-object-size-2.c: Silence overread warnings.
Declare free, strdup and strndup.
(test9): New test.
(main): Call it.
* gcc.dg/builtin-object-size-3.c: Silence overread warnings.
Declare free, strdup and strndup.
(test11): New test.
(main): Call it.
* gcc.dg/builtin-object-size-4.c: Silence overread warnings.
Declare free, strdup and strndup.
(test9): New test.
(main): Call it.


I'm struggling to see how the SSA updating is correct.  Yes we need 
to update the virtuals due to the introduction of the call to strlen, 
particularly when SRC is not a string constant.  But do we need to do 
more?


Don't we end up gimplifying the 1 + strlenfn (src) expression? Can 
that possibly create new SSA_NAMEs?  Do those need to be put into SSA 
form? I feel like I'm missing something here...


We do all of that manually in gimplify_size_expressions, the only 
thing left to do is updating virtuals AFAICT.


I guess it's actually buried down in force_gimple_operand and I guess 
for temporaries they're not going to be alive across the new gimple 
sequence and each destination gets its own SSA_NAME, so it ought to be 
safe.  Just had to work a bit further through things.


OK for the trunk.


Thanks, pushed with the trivial fixup that Prathamesh suggested, i.e. 
replaced 'if (!strndup)' with 'else'.


Sid


Re: [PATCH v2] tree-object-size: Support strndup and strdup

2022-11-21 Thread Siddhesh Poyarekar

On 2022-11-20 10:42, Jeff Law wrote:


On 11/4/22 06:48, Siddhesh Poyarekar wrote:

Use string length of input to strdup to determine the usable size of the
resulting object.  Avoid doing the same for strndup since there's a
chance that the input may be too large, resulting in an unnecessary
overhead or worse, the input may not be NULL terminated, resulting in a
crash where there would otherwise have been none.

gcc/ChangeLog:

* tree-object-size.cc (todo): New variable.
(object_sizes_execute): Use it.
(strdup_object_size): New function.
(call_object_size): Use it.

gcc/testsuite/ChangeLog:

* gcc.dg/builtin-dynamic-object-size-0.c (test_strdup,
test_strndup, test_strdup_min, test_strndup_min): New tests.
(main): Call them.
* gcc.dg/builtin-dynamic-object-size-1.c: Silence overread
warnings.
* gcc.dg/builtin-dynamic-object-size-2.c: Likewise.
* gcc.dg/builtin-dynamic-object-size-3.c: Likewise.
* gcc.dg/builtin-dynamic-object-size-4.c: Likewise.
* gcc.dg/builtin-object-size-1.c: Silence overread warnings.
Declare free, strdup and strndup.
(test11): New test.
(main): Call it.
* gcc.dg/builtin-object-size-2.c: Silence overread warnings.
Declare free, strdup and strndup.
(test9): New test.
(main): Call it.
* gcc.dg/builtin-object-size-3.c: Silence overread warnings.
Declare free, strdup and strndup.
(test11): New test.
(main): Call it.
* gcc.dg/builtin-object-size-4.c: Silence overread warnings.
Declare free, strdup and strndup.
(test9): New test.
(main): Call it.


I'm struggling to see how the SSA updating is correct.  Yes we need to 
update the virtuals due to the introduction of the call to strlen, 
particularly when SRC is not a string constant.  But do we need to do more?


Don't we end up gimplifying the 1 + strlenfn (src) expression? Can that 
possibly create new SSA_NAMEs?  Do those need to be put into SSA form? I 
feel like I'm missing something here...


We do all of that manually in gimplify_size_expressions, the only thing 
left to do is updating virtuals AFAICT.


Thanks,
Sid


Re: [PATCH v2] tree-object-size: Support strndup and strdup

2022-11-17 Thread Siddhesh Poyarekar

Ping!

On 2022-11-04 08:48, Siddhesh Poyarekar wrote:

Use string length of input to strdup to determine the usable size of the
resulting object.  Avoid doing the same for strndup since there's a
chance that the input may be too large, resulting in an unnecessary
overhead or worse, the input may not be NULL terminated, resulting in a
crash where there would otherwise have been none.

gcc/ChangeLog:

* tree-object-size.cc (todo): New variable.
(object_sizes_execute): Use it.
(strdup_object_size): New function.
(call_object_size): Use it.

gcc/testsuite/ChangeLog:

* gcc.dg/builtin-dynamic-object-size-0.c (test_strdup,
test_strndup, test_strdup_min, test_strndup_min): New tests.
(main): Call them.
* gcc.dg/builtin-dynamic-object-size-1.c: Silence overread
warnings.
* gcc.dg/builtin-dynamic-object-size-2.c: Likewise.
* gcc.dg/builtin-dynamic-object-size-3.c: Likewise.
* gcc.dg/builtin-dynamic-object-size-4.c: Likewise.
* gcc.dg/builtin-object-size-1.c: Silence overread warnings.
Declare free, strdup and strndup.
(test11): New test.
(main): Call it.
* gcc.dg/builtin-object-size-2.c: Silence overread warnings.
Declare free, strdup and strndup.
(test9): New test.
(main): Call it.
* gcc.dg/builtin-object-size-3.c: Silence overread warnings.
Declare free, strdup and strndup.
(test11): New test.
(main): Call it.
* gcc.dg/builtin-object-size-4.c: Silence overread warnings.
Declare free, strdup and strndup.
(test9): New test.
(main): Call it.
---
Tested:

- x86_64 bootstrap and testsuite run
- i686 build and testsuite run
- ubsan bootstrap

  .../gcc.dg/builtin-dynamic-object-size-0.c| 43 +
  .../gcc.dg/builtin-dynamic-object-size-1.c|  2 +-
  .../gcc.dg/builtin-dynamic-object-size-2.c|  2 +-
  .../gcc.dg/builtin-dynamic-object-size-3.c|  2 +-
  .../gcc.dg/builtin-dynamic-object-size-4.c|  2 +-
  gcc/testsuite/gcc.dg/builtin-object-size-1.c  | 94 +-
  gcc/testsuite/gcc.dg/builtin-object-size-2.c  | 94 +-
  gcc/testsuite/gcc.dg/builtin-object-size-3.c  | 95 ++-
  gcc/testsuite/gcc.dg/builtin-object-size-4.c  | 94 +-
  gcc/tree-object-size.cc   | 84 +++-
  10 files changed, 502 insertions(+), 10 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
index 01a280b2d7b..4f1606a486b 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -479,6 +479,40 @@ test_loop (int *obj, size_t sz, size_t start, size_t end, 
int incr)
return __builtin_dynamic_object_size (ptr, 0);
  }
  
+/* strdup/strndup.  */

+
+size_t
+__attribute__ ((noinline))
+test_strdup (const char *in)
+{
+  char *res = __builtin_strdup (in);
+  return __builtin_dynamic_object_size (res, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_strndup (const char *in, size_t bound)
+{
+  char *res = __builtin_strndup (in, bound);
+  return __builtin_dynamic_object_size (res, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_strdup_min (const char *in)
+{
+  char *res = __builtin_strdup (in);
+  return __builtin_dynamic_object_size (res, 2);
+}
+
+size_t
+__attribute__ ((noinline))
+test_strndup_min (const char *in, size_t bound)
+{
+  char *res = __builtin_strndup (in, bound);
+  return __builtin_dynamic_object_size (res, 2);
+}
+
  /* Other tests.  */
  
  struct TV4

@@ -651,6 +685,15 @@ main (int argc, char **argv)
int *t = test_pr105736 ();
if (__builtin_dynamic_object_size (t, 0) != -1)
  FAIL ();
+  const char *str = "hello world";
+  if (test_strdup (str) != __builtin_strlen (str) + 1)
+FAIL ();
+  if (test_strndup (str, 4) != 5)
+FAIL ();
+  if (test_strdup_min (str) != __builtin_strlen (str) + 1)
+FAIL ();
+  if (test_strndup_min (str, 4) != 1)
+FAIL ();
  
if (nfails > 0)

  __builtin_abort ();
diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
index 7cc8b1c9488..8f17c8edcaf 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
@@ -1,5 +1,5 @@
  /* { dg-do run } */
-/* { dg-options "-O2" } */
+/* { dg-options "-O2 -Wno-stringop-overread" } */
  /* { dg-require-effective-target alloca } */
  
  #define __builtin_object_size __builtin_dynamic_object_size

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
index 267dbf48ca7..3677782ff1c 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
@@ -1,5 +1,5 @@
  /* 

Re: [PATCH v2] tree-object-size: Support strndup and strdup

2022-11-04 Thread Siddhesh Poyarekar

On 2022-11-04 09:43, Prathamesh Kulkarni wrote:

On Fri, 4 Nov 2022 at 18:18, Siddhesh Poyarekar  wrote:


Use string length of input to strdup to determine the usable size of the
resulting object.  Avoid doing the same for strndup since there's a
chance that the input may be too large, resulting in an unnecessary
overhead or worse, the input may not be NULL terminated, resulting in a
crash where there would otherwise have been none.

gcc/ChangeLog:

 * tree-object-size.cc (todo): New variable.
 (object_sizes_execute): Use it.
 (strdup_object_size): New function.
 (call_object_size): Use it.

gcc/testsuite/ChangeLog:

 * gcc.dg/builtin-dynamic-object-size-0.c (test_strdup,
 test_strndup, test_strdup_min, test_strndup_min): New tests.
 (main): Call them.
 * gcc.dg/builtin-dynamic-object-size-1.c: Silence overread
 warnings.
 * gcc.dg/builtin-dynamic-object-size-2.c: Likewise.
 * gcc.dg/builtin-dynamic-object-size-3.c: Likewise.
 * gcc.dg/builtin-dynamic-object-size-4.c: Likewise.
 * gcc.dg/builtin-object-size-1.c: Silence overread warnings.
 Declare free, strdup and strndup.
 (test11): New test.
 (main): Call it.
 * gcc.dg/builtin-object-size-2.c: Silence overread warnings.
 Declare free, strdup and strndup.
 (test9): New test.
 (main): Call it.
 * gcc.dg/builtin-object-size-3.c: Silence overread warnings.
 Declare free, strdup and strndup.
 (test11): New test.
 (main): Call it.
 * gcc.dg/builtin-object-size-4.c: Silence overread warnings.
 Declare free, strdup and strndup.
 (test9): New test.
 (main): Call it.
---
Tested:

- x86_64 bootstrap and testsuite run
- i686 build and testsuite run
- ubsan bootstrap

  .../gcc.dg/builtin-dynamic-object-size-0.c| 43 +
  .../gcc.dg/builtin-dynamic-object-size-1.c|  2 +-
  .../gcc.dg/builtin-dynamic-object-size-2.c|  2 +-
  .../gcc.dg/builtin-dynamic-object-size-3.c|  2 +-
  .../gcc.dg/builtin-dynamic-object-size-4.c|  2 +-
  gcc/testsuite/gcc.dg/builtin-object-size-1.c  | 94 +-
  gcc/testsuite/gcc.dg/builtin-object-size-2.c  | 94 +-
  gcc/testsuite/gcc.dg/builtin-object-size-3.c  | 95 ++-
  gcc/testsuite/gcc.dg/builtin-object-size-4.c  | 94 +-
  gcc/tree-object-size.cc   | 84 +++-
  10 files changed, 502 insertions(+), 10 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
index 01a280b2d7b..4f1606a486b 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -479,6 +479,40 @@ test_loop (int *obj, size_t sz, size_t start, size_t end, 
int incr)
return __builtin_dynamic_object_size (ptr, 0);
  }

+/* strdup/strndup.  */
+
+size_t
+__attribute__ ((noinline))
+test_strdup (const char *in)
+{
+  char *res = __builtin_strdup (in);
+  return __builtin_dynamic_object_size (res, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_strndup (const char *in, size_t bound)
+{
+  char *res = __builtin_strndup (in, bound);
+  return __builtin_dynamic_object_size (res, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_strdup_min (const char *in)
+{
+  char *res = __builtin_strdup (in);
+  return __builtin_dynamic_object_size (res, 2);
+}
+
+size_t
+__attribute__ ((noinline))
+test_strndup_min (const char *in, size_t bound)
+{
+  char *res = __builtin_strndup (in, bound);
+  return __builtin_dynamic_object_size (res, 2);
+}
+
  /* Other tests.  */

  struct TV4
@@ -651,6 +685,15 @@ main (int argc, char **argv)
int *t = test_pr105736 ();
if (__builtin_dynamic_object_size (t, 0) != -1)
  FAIL ();
+  const char *str = "hello world";
+  if (test_strdup (str) != __builtin_strlen (str) + 1)
+FAIL ();
+  if (test_strndup (str, 4) != 5)
+FAIL ();
+  if (test_strdup_min (str) != __builtin_strlen (str) + 1)
+FAIL ();
+  if (test_strndup_min (str, 4) != 1)
+FAIL ();

if (nfails > 0)
  __builtin_abort ();
diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
index 7cc8b1c9488..8f17c8edcaf 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
@@ -1,5 +1,5 @@
  /* { dg-do run } */
-/* { dg-options "-O2" } */
+/* { dg-options "-O2 -Wno-stringop-overread" } */
  /* { dg-require-effective-target alloca } */

  #define __builtin_object_size __builtin_dynamic_object_size
diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
index 267dbf48ca7..3677782ff1c 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
+++ b/gcc

[PATCH v2] tree-object-size: Support strndup and strdup

2022-11-04 Thread Siddhesh Poyarekar
Use string length of input to strdup to determine the usable size of the
resulting object.  Avoid doing the same for strndup since there's a
chance that the input may be too large, resulting in an unnecessary
overhead or worse, the input may not be NULL terminated, resulting in a
crash where there would otherwise have been none.

gcc/ChangeLog:

* tree-object-size.cc (todo): New variable.
(object_sizes_execute): Use it.
(strdup_object_size): New function.
(call_object_size): Use it.

gcc/testsuite/ChangeLog:

* gcc.dg/builtin-dynamic-object-size-0.c (test_strdup,
test_strndup, test_strdup_min, test_strndup_min): New tests.
(main): Call them.
* gcc.dg/builtin-dynamic-object-size-1.c: Silence overread
warnings.
* gcc.dg/builtin-dynamic-object-size-2.c: Likewise.
* gcc.dg/builtin-dynamic-object-size-3.c: Likewise.
* gcc.dg/builtin-dynamic-object-size-4.c: Likewise.
* gcc.dg/builtin-object-size-1.c: Silence overread warnings.
Declare free, strdup and strndup.
(test11): New test.
(main): Call it.
* gcc.dg/builtin-object-size-2.c: Silence overread warnings.
Declare free, strdup and strndup.
(test9): New test.
(main): Call it.
* gcc.dg/builtin-object-size-3.c: Silence overread warnings.
Declare free, strdup and strndup.
(test11): New test.
(main): Call it.
* gcc.dg/builtin-object-size-4.c: Silence overread warnings.
Declare free, strdup and strndup.
(test9): New test.
(main): Call it.
---
Tested:

- x86_64 bootstrap and testsuite run
- i686 build and testsuite run
- ubsan bootstrap

 .../gcc.dg/builtin-dynamic-object-size-0.c| 43 +
 .../gcc.dg/builtin-dynamic-object-size-1.c|  2 +-
 .../gcc.dg/builtin-dynamic-object-size-2.c|  2 +-
 .../gcc.dg/builtin-dynamic-object-size-3.c|  2 +-
 .../gcc.dg/builtin-dynamic-object-size-4.c|  2 +-
 gcc/testsuite/gcc.dg/builtin-object-size-1.c  | 94 +-
 gcc/testsuite/gcc.dg/builtin-object-size-2.c  | 94 +-
 gcc/testsuite/gcc.dg/builtin-object-size-3.c  | 95 ++-
 gcc/testsuite/gcc.dg/builtin-object-size-4.c  | 94 +-
 gcc/tree-object-size.cc   | 84 +++-
 10 files changed, 502 insertions(+), 10 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
index 01a280b2d7b..4f1606a486b 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -479,6 +479,40 @@ test_loop (int *obj, size_t sz, size_t start, size_t end, 
int incr)
   return __builtin_dynamic_object_size (ptr, 0);
 }
 
+/* strdup/strndup.  */
+
+size_t
+__attribute__ ((noinline))
+test_strdup (const char *in)
+{
+  char *res = __builtin_strdup (in);
+  return __builtin_dynamic_object_size (res, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_strndup (const char *in, size_t bound)
+{
+  char *res = __builtin_strndup (in, bound);
+  return __builtin_dynamic_object_size (res, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_strdup_min (const char *in)
+{
+  char *res = __builtin_strdup (in);
+  return __builtin_dynamic_object_size (res, 2);
+}
+
+size_t
+__attribute__ ((noinline))
+test_strndup_min (const char *in, size_t bound)
+{
+  char *res = __builtin_strndup (in, bound);
+  return __builtin_dynamic_object_size (res, 2);
+}
+
 /* Other tests.  */
 
 struct TV4
@@ -651,6 +685,15 @@ main (int argc, char **argv)
   int *t = test_pr105736 ();
   if (__builtin_dynamic_object_size (t, 0) != -1)
 FAIL ();
+  const char *str = "hello world";
+  if (test_strdup (str) != __builtin_strlen (str) + 1)
+FAIL ();
+  if (test_strndup (str, 4) != 5)
+FAIL ();
+  if (test_strdup_min (str) != __builtin_strlen (str) + 1)
+FAIL ();
+  if (test_strndup_min (str, 4) != 1)
+FAIL ();
 
   if (nfails > 0)
 __builtin_abort ();
diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
index 7cc8b1c9488..8f17c8edcaf 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2" } */
+/* { dg-options "-O2 -Wno-stringop-overread" } */
 /* { dg-require-effective-target alloca } */
 
 #define __builtin_object_size __builtin_dynamic_object_size
diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
index 267dbf48ca7..3677782ff1c 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2" } */
+/* { dg-options "-O2 -Wno-stringop-overread" } */
 /* { 

Re: [PATCH] tree-object-size: Support strndup and strdup

2022-11-02 Thread Siddhesh Poyarekar

On 2022-09-23 09:02, Jakub Jelinek wrote:

Oh, so can addr_object_size be simplified to use get_base_address too?


You can try.  As you can see in get_base_address, that function
handles something that the above doesn't (looking through some MEM_REFs too).



I went down this rabbithole and it actually simplifies some cases but 
got sucked into flex array related issues that I need more time to 
figure out.  I'll stick to using get_base_address for now since I want 
to make sure this makes the stage 1 deadline.


Thanks,
Sid


Re: [PATCH] tree-object-size: Support strndup and strdup

2022-09-22 Thread Siddhesh Poyarekar

On 2022-09-22 09:02, Jakub Jelinek wrote:

On Mon, Aug 15, 2022 at 03:23:11PM -0400, Siddhesh Poyarekar wrote:

--- a/gcc/tree-object-size.cc
+++ b/gcc/tree-object-size.cc
@@ -495,6 +495,18 @@ decl_init_size (tree decl, bool min)
return size;
  }
  
+/* Get the outermost object that PTR may point into.  */

+
+static tree
+get_whole_object (const_tree ptr)
+{
+  tree pt_var = TREE_OPERAND (ptr, 0);
+  while (handled_component_p (pt_var))
+pt_var = TREE_OPERAND (pt_var, 0);
+
+  return pt_var;
+}


Not sure why you want a new function for this.
This is essentially get_base_address (TREE_OPERAND (ptr, 0)).


Oh, so can addr_object_size be simplified to use get_base_address too?


  /* Compute __builtin_object_size for PTR, which is a ADDR_EXPR.
 OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
 If unknown, return size_unknown (object_size_type).  */
+  if (!size_valid_p (sz, object_size_type)
+   || size_unknown_p (sz, object_size_type))
+{
+  tree wholesrc = NULL_TREE;
+  if (TREE_CODE (src) == ADDR_EXPR)
+   wholesrc = get_whole_object (src);
+
+  if (!(object_size_type & OST_MINIMUM)
+ || (wholesrc && TREE_CODE (wholesrc) == STRING_CST))


Is this safe?  I mean get_whole_object will also skip ARRAY_REFs with
variable indexes etc. and the STRING_CST could have embedded '\0's
in it.
Even if c_strlen (src, 1) is constant, I don't see what you can assume
for object size of strndup ("abcd\0efgh", n); for minimum, except 1.


Can't we assume MIN(5, n) for STRING_CST?

For ARRAY_REFs, it may end up being MIN(array_size, n) and not account 
for the NUL termination but I was thinking of that as being a better 
option than bailing out.  Should we try harder here and return, e.g. 
strlen or some equivalent?



But on the other side, 1 is a safe minimum for OST_MINIMUM of both
strdup and strndup if you don't find anything more specific (exact strlen
for strndup) because the terminating '\0' will be always there.


OK, I can return size_one_node as the final return value for OST_MINIMUM 
if we don't find a suitable expression.



Other than that you'd need to consider INTEGER_CST second strndup argument
or ranges of the second argument etc.
E.g. maximum for OST_DYNAMIC could be for strndup (src, n)
MIN (__bdos (src, ?), n + 1).


Yeah, that's what I return in the end:

  return fold_build2 (MIN_EXPR, sizetype,
 fold_build2 (PLUS_EXPR, sizetype, size_one_node,n),
 sz);

where sz is __bdos(src)




@@ -2113,7 +2177,7 @@ const pass_data pass_data_object_sizes =
PROP_objsz, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
-  0, /* todo_flags_finish */
+  TODO_update_ssa_no_phi, /* todo_flags_finish */
  };
  
  class pass_object_sizes : public gimple_opt_pass

@@ -2153,7 +2217,7 @@ const pass_data pass_data_early_object_sizes =
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
-  0, /* todo_flags_finish */
+  TODO_update_ssa_no_phi, /* todo_flags_finish */
  };


This is quite expensive.  Do you really need full ssa update, or just
TODO_update_ssa_only_virtuals would be enough (is it for the missing
vuse on the strlen call if you emit it)?
In any case, would be better not to do that always, but only if you
really need it (emitted the strlen call somewhere; e.g. if __bdos is
never used, only __bos, it is certainly not needed), todo flags
can be both in todo_flags_finish and in return value from execute method.


Thanks, I'll find a cheaper way to do this.

Thanks,
Sid


Re: [PATCH] tree-object-size: Support strndup and strdup

2022-09-15 Thread Siddhesh Poyarekar

Ping!

On 2022-09-07 15:21, Siddhesh Poyarekar wrote:

Ping!

On 2022-08-29 10:16, Siddhesh Poyarekar wrote:

Ping!

On 2022-08-15 15:23, Siddhesh Poyarekar wrote:

Use string length of input to strdup to determine the usable size of the
resulting object.  Avoid doing the same for strndup since there's a
chance that the input may be too large, resulting in an unnecessary
overhead or worse, the input may not be NULL terminated, resulting in a
crash where there would otherwise have been none.

gcc/ChangeLog:

* tree-object-size.cc (get_whole_object): New function.
(addr_object_size): Use it.
(strdup_object_size): New function.
(call_object_size): Use it.
(pass_data_object_sizes, pass_data_early_object_sizes): Set
todo_flags_finish to TODO_update_ssa_no_phi.

gcc/testsuite/ChangeLog:

* gcc.dg/builtin-dynamic-object-size-0.c (test_strdup,
test_strndup, test_strdup_min, test_strndup_min): New tests.
(main): Call them.
* gcc.dg/builtin-dynamic-object-size-1.c: Silence overread
warnings.
* gcc.dg/builtin-dynamic-object-size-2.c: Likewise.
* gcc.dg/builtin-dynamic-object-size-3.c: Likewise.
* gcc.dg/builtin-dynamic-object-size-4.c: Likewise.
* gcc.dg/builtin-object-size-1.c: Silence overread warnings.
Declare free, strdup and strndup.
(test11): New test.
(main): Call it.
* gcc.dg/builtin-object-size-2.c: Silence overread warnings.
Declare free, strdup and strndup.
(test9): New test.
(main): Call it.
* gcc.dg/builtin-object-size-3.c: Silence overread warnings.
Declare free, strdup and strndup.
(test11): New test.
(main): Call it.
* gcc.dg/builtin-object-size-4.c: Silence overread warnings.
Declare free, strdup and strndup.
(test9): New test.
(main): Call it.
---
  .../gcc.dg/builtin-dynamic-object-size-0.c    | 43 +++
  .../gcc.dg/builtin-dynamic-object-size-1.c    |  2 +-
  .../gcc.dg/builtin-dynamic-object-size-2.c    |  2 +-
  .../gcc.dg/builtin-dynamic-object-size-3.c    |  2 +-
  .../gcc.dg/builtin-dynamic-object-size-4.c    |  2 +-
  gcc/testsuite/gcc.dg/builtin-object-size-1.c  | 64 +++-
  gcc/testsuite/gcc.dg/builtin-object-size-2.c  | 63 ++-
  gcc/testsuite/gcc.dg/builtin-object-size-3.c  | 63 ++-
  gcc/testsuite/gcc.dg/builtin-object-size-4.c  | 63 ++-
  gcc/tree-object-size.cc   | 76 +--
  10 files changed, 366 insertions(+), 14 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c

index 01a280b2d7b..7f023708b15 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -479,6 +479,40 @@ test_loop (int *obj, size_t sz, size_t start, 
size_t end, int incr)

    return __builtin_dynamic_object_size (ptr, 0);
  }
+/* strdup/strndup.  */
+
+size_t
+__attribute__ ((noinline))
+test_strdup (const char *in)
+{
+  char *res = __builtin_strdup (in);
+  return __builtin_dynamic_object_size (res, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_strndup (const char *in, size_t bound)
+{
+  char *res = __builtin_strndup (in, bound);
+  return __builtin_dynamic_object_size (res, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_strdup_min (const char *in)
+{
+  char *res = __builtin_strdup (in);
+  return __builtin_dynamic_object_size (res, 2);
+}
+
+size_t
+__attribute__ ((noinline))
+test_strndup_min (const char *in, size_t bound)
+{
+  char *res = __builtin_strndup (in, bound);
+  return __builtin_dynamic_object_size (res, 2);
+}
+
  /* Other tests.  */
  struct TV4
@@ -651,6 +685,15 @@ main (int argc, char **argv)
    int *t = test_pr105736 ();
    if (__builtin_dynamic_object_size (t, 0) != -1)
  FAIL ();
+  const char *str = "hello world";
+  if (test_strdup (str) != __builtin_strlen (str) + 1)
+    FAIL ();
+  if (test_strndup (str, 4) != 5)
+    FAIL ();
+  if (test_strdup_min (str) != __builtin_strlen (str) + 1)
+    FAIL ();
+  if (test_strndup_min (str, 4) != 0)
+    FAIL ();
    if (nfails > 0)
  __builtin_abort ();
diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c

index 7cc8b1c9488..8f17c8edcaf 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
@@ -1,5 +1,5 @@
  /* { dg-do run } */
-/* { dg-options "-O2" } */
+/* { dg-options "-O2 -Wno-stringop-overread" } */
  /* { dg-require-effective-target alloca } */
  #define __builtin_object_size __builtin_dynamic_object_size
diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c

index 267dbf48ca7..3677782ff1c 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
@@ -1,5 +1,5 

Re: [PATCH] tree-object-size: Support strndup and strdup

2022-09-07 Thread Siddhesh Poyarekar

Ping!

On 2022-08-29 10:16, Siddhesh Poyarekar wrote:

Ping!

On 2022-08-15 15:23, Siddhesh Poyarekar wrote:

Use string length of input to strdup to determine the usable size of the
resulting object.  Avoid doing the same for strndup since there's a
chance that the input may be too large, resulting in an unnecessary
overhead or worse, the input may not be NULL terminated, resulting in a
crash where there would otherwise have been none.

gcc/ChangeLog:

* tree-object-size.cc (get_whole_object): New function.
(addr_object_size): Use it.
(strdup_object_size): New function.
(call_object_size): Use it.
(pass_data_object_sizes, pass_data_early_object_sizes): Set
todo_flags_finish to TODO_update_ssa_no_phi.

gcc/testsuite/ChangeLog:

* gcc.dg/builtin-dynamic-object-size-0.c (test_strdup,
test_strndup, test_strdup_min, test_strndup_min): New tests.
(main): Call them.
* gcc.dg/builtin-dynamic-object-size-1.c: Silence overread
warnings.
* gcc.dg/builtin-dynamic-object-size-2.c: Likewise.
* gcc.dg/builtin-dynamic-object-size-3.c: Likewise.
* gcc.dg/builtin-dynamic-object-size-4.c: Likewise.
* gcc.dg/builtin-object-size-1.c: Silence overread warnings.
Declare free, strdup and strndup.
(test11): New test.
(main): Call it.
* gcc.dg/builtin-object-size-2.c: Silence overread warnings.
Declare free, strdup and strndup.
(test9): New test.
(main): Call it.
* gcc.dg/builtin-object-size-3.c: Silence overread warnings.
Declare free, strdup and strndup.
(test11): New test.
(main): Call it.
* gcc.dg/builtin-object-size-4.c: Silence overread warnings.
Declare free, strdup and strndup.
(test9): New test.
(main): Call it.
---
  .../gcc.dg/builtin-dynamic-object-size-0.c    | 43 +++
  .../gcc.dg/builtin-dynamic-object-size-1.c    |  2 +-
  .../gcc.dg/builtin-dynamic-object-size-2.c    |  2 +-
  .../gcc.dg/builtin-dynamic-object-size-3.c    |  2 +-
  .../gcc.dg/builtin-dynamic-object-size-4.c    |  2 +-
  gcc/testsuite/gcc.dg/builtin-object-size-1.c  | 64 +++-
  gcc/testsuite/gcc.dg/builtin-object-size-2.c  | 63 ++-
  gcc/testsuite/gcc.dg/builtin-object-size-3.c  | 63 ++-
  gcc/testsuite/gcc.dg/builtin-object-size-4.c  | 63 ++-
  gcc/tree-object-size.cc   | 76 +--
  10 files changed, 366 insertions(+), 14 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c

index 01a280b2d7b..7f023708b15 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -479,6 +479,40 @@ test_loop (int *obj, size_t sz, size_t start, 
size_t end, int incr)

    return __builtin_dynamic_object_size (ptr, 0);
  }
+/* strdup/strndup.  */
+
+size_t
+__attribute__ ((noinline))
+test_strdup (const char *in)
+{
+  char *res = __builtin_strdup (in);
+  return __builtin_dynamic_object_size (res, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_strndup (const char *in, size_t bound)
+{
+  char *res = __builtin_strndup (in, bound);
+  return __builtin_dynamic_object_size (res, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_strdup_min (const char *in)
+{
+  char *res = __builtin_strdup (in);
+  return __builtin_dynamic_object_size (res, 2);
+}
+
+size_t
+__attribute__ ((noinline))
+test_strndup_min (const char *in, size_t bound)
+{
+  char *res = __builtin_strndup (in, bound);
+  return __builtin_dynamic_object_size (res, 2);
+}
+
  /* Other tests.  */
  struct TV4
@@ -651,6 +685,15 @@ main (int argc, char **argv)
    int *t = test_pr105736 ();
    if (__builtin_dynamic_object_size (t, 0) != -1)
  FAIL ();
+  const char *str = "hello world";
+  if (test_strdup (str) != __builtin_strlen (str) + 1)
+    FAIL ();
+  if (test_strndup (str, 4) != 5)
+    FAIL ();
+  if (test_strdup_min (str) != __builtin_strlen (str) + 1)
+    FAIL ();
+  if (test_strndup_min (str, 4) != 0)
+    FAIL ();
    if (nfails > 0)
  __builtin_abort ();
diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c

index 7cc8b1c9488..8f17c8edcaf 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
@@ -1,5 +1,5 @@
  /* { dg-do run } */
-/* { dg-options "-O2" } */
+/* { dg-options "-O2 -Wno-stringop-overread" } */
  /* { dg-require-effective-target alloca } */
  #define __builtin_object_size __builtin_dynamic_object_size
diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c

index 267dbf48ca7..3677782ff1c 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
@@ -1,5 +1,5 @@
  /* { dg-do run } */
-/* { dg-options "-O2&quo

Re: [PATCH] tree-object-size: Support strndup and strdup

2022-08-29 Thread Siddhesh Poyarekar

Ping!

On 2022-08-15 15:23, Siddhesh Poyarekar wrote:

Use string length of input to strdup to determine the usable size of the
resulting object.  Avoid doing the same for strndup since there's a
chance that the input may be too large, resulting in an unnecessary
overhead or worse, the input may not be NULL terminated, resulting in a
crash where there would otherwise have been none.

gcc/ChangeLog:

* tree-object-size.cc (get_whole_object): New function.
(addr_object_size): Use it.
(strdup_object_size): New function.
(call_object_size): Use it.
(pass_data_object_sizes, pass_data_early_object_sizes): Set
todo_flags_finish to TODO_update_ssa_no_phi.

gcc/testsuite/ChangeLog:

* gcc.dg/builtin-dynamic-object-size-0.c (test_strdup,
test_strndup, test_strdup_min, test_strndup_min): New tests.
(main): Call them.
* gcc.dg/builtin-dynamic-object-size-1.c: Silence overread
warnings.
* gcc.dg/builtin-dynamic-object-size-2.c: Likewise.
* gcc.dg/builtin-dynamic-object-size-3.c: Likewise.
* gcc.dg/builtin-dynamic-object-size-4.c: Likewise.
* gcc.dg/builtin-object-size-1.c: Silence overread warnings.
Declare free, strdup and strndup.
(test11): New test.
(main): Call it.
* gcc.dg/builtin-object-size-2.c: Silence overread warnings.
Declare free, strdup and strndup.
(test9): New test.
(main): Call it.
* gcc.dg/builtin-object-size-3.c: Silence overread warnings.
Declare free, strdup and strndup.
(test11): New test.
(main): Call it.
* gcc.dg/builtin-object-size-4.c: Silence overread warnings.
Declare free, strdup and strndup.
(test9): New test.
(main): Call it.
---
  .../gcc.dg/builtin-dynamic-object-size-0.c| 43 +++
  .../gcc.dg/builtin-dynamic-object-size-1.c|  2 +-
  .../gcc.dg/builtin-dynamic-object-size-2.c|  2 +-
  .../gcc.dg/builtin-dynamic-object-size-3.c|  2 +-
  .../gcc.dg/builtin-dynamic-object-size-4.c|  2 +-
  gcc/testsuite/gcc.dg/builtin-object-size-1.c  | 64 +++-
  gcc/testsuite/gcc.dg/builtin-object-size-2.c  | 63 ++-
  gcc/testsuite/gcc.dg/builtin-object-size-3.c  | 63 ++-
  gcc/testsuite/gcc.dg/builtin-object-size-4.c  | 63 ++-
  gcc/tree-object-size.cc   | 76 +--
  10 files changed, 366 insertions(+), 14 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
index 01a280b2d7b..7f023708b15 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -479,6 +479,40 @@ test_loop (int *obj, size_t sz, size_t start, size_t end, 
int incr)
return __builtin_dynamic_object_size (ptr, 0);
  }
  
+/* strdup/strndup.  */

+
+size_t
+__attribute__ ((noinline))
+test_strdup (const char *in)
+{
+  char *res = __builtin_strdup (in);
+  return __builtin_dynamic_object_size (res, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_strndup (const char *in, size_t bound)
+{
+  char *res = __builtin_strndup (in, bound);
+  return __builtin_dynamic_object_size (res, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_strdup_min (const char *in)
+{
+  char *res = __builtin_strdup (in);
+  return __builtin_dynamic_object_size (res, 2);
+}
+
+size_t
+__attribute__ ((noinline))
+test_strndup_min (const char *in, size_t bound)
+{
+  char *res = __builtin_strndup (in, bound);
+  return __builtin_dynamic_object_size (res, 2);
+}
+
  /* Other tests.  */
  
  struct TV4

@@ -651,6 +685,15 @@ main (int argc, char **argv)
int *t = test_pr105736 ();
if (__builtin_dynamic_object_size (t, 0) != -1)
  FAIL ();
+  const char *str = "hello world";
+  if (test_strdup (str) != __builtin_strlen (str) + 1)
+FAIL ();
+  if (test_strndup (str, 4) != 5)
+FAIL ();
+  if (test_strdup_min (str) != __builtin_strlen (str) + 1)
+FAIL ();
+  if (test_strndup_min (str, 4) != 0)
+FAIL ();
  
if (nfails > 0)

  __builtin_abort ();
diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
index 7cc8b1c9488..8f17c8edcaf 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
@@ -1,5 +1,5 @@
  /* { dg-do run } */
-/* { dg-options "-O2" } */
+/* { dg-options "-O2 -Wno-stringop-overread" } */
  /* { dg-require-effective-target alloca } */
  
  #define __builtin_object_size __builtin_dynamic_object_size

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
index 267dbf48ca7..3677782ff1c 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size

[PATCH] tree-object-size: Support strndup and strdup

2022-08-15 Thread Siddhesh Poyarekar
Use string length of input to strdup to determine the usable size of the
resulting object.  Avoid doing the same for strndup since there's a
chance that the input may be too large, resulting in an unnecessary
overhead or worse, the input may not be NULL terminated, resulting in a
crash where there would otherwise have been none.

gcc/ChangeLog:

* tree-object-size.cc (get_whole_object): New function.
(addr_object_size): Use it.
(strdup_object_size): New function.
(call_object_size): Use it.
(pass_data_object_sizes, pass_data_early_object_sizes): Set
todo_flags_finish to TODO_update_ssa_no_phi.

gcc/testsuite/ChangeLog:

* gcc.dg/builtin-dynamic-object-size-0.c (test_strdup,
test_strndup, test_strdup_min, test_strndup_min): New tests.
(main): Call them.
* gcc.dg/builtin-dynamic-object-size-1.c: Silence overread
warnings.
* gcc.dg/builtin-dynamic-object-size-2.c: Likewise.
* gcc.dg/builtin-dynamic-object-size-3.c: Likewise.
* gcc.dg/builtin-dynamic-object-size-4.c: Likewise.
* gcc.dg/builtin-object-size-1.c: Silence overread warnings.
Declare free, strdup and strndup.
(test11): New test.
(main): Call it.
* gcc.dg/builtin-object-size-2.c: Silence overread warnings.
Declare free, strdup and strndup.
(test9): New test.
(main): Call it.
* gcc.dg/builtin-object-size-3.c: Silence overread warnings.
Declare free, strdup and strndup.
(test11): New test.
(main): Call it.
* gcc.dg/builtin-object-size-4.c: Silence overread warnings.
Declare free, strdup and strndup.
(test9): New test.
(main): Call it.
---
 .../gcc.dg/builtin-dynamic-object-size-0.c| 43 +++
 .../gcc.dg/builtin-dynamic-object-size-1.c|  2 +-
 .../gcc.dg/builtin-dynamic-object-size-2.c|  2 +-
 .../gcc.dg/builtin-dynamic-object-size-3.c|  2 +-
 .../gcc.dg/builtin-dynamic-object-size-4.c|  2 +-
 gcc/testsuite/gcc.dg/builtin-object-size-1.c  | 64 +++-
 gcc/testsuite/gcc.dg/builtin-object-size-2.c  | 63 ++-
 gcc/testsuite/gcc.dg/builtin-object-size-3.c  | 63 ++-
 gcc/testsuite/gcc.dg/builtin-object-size-4.c  | 63 ++-
 gcc/tree-object-size.cc   | 76 +--
 10 files changed, 366 insertions(+), 14 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
index 01a280b2d7b..7f023708b15 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -479,6 +479,40 @@ test_loop (int *obj, size_t sz, size_t start, size_t end, 
int incr)
   return __builtin_dynamic_object_size (ptr, 0);
 }
 
+/* strdup/strndup.  */
+
+size_t
+__attribute__ ((noinline))
+test_strdup (const char *in)
+{
+  char *res = __builtin_strdup (in);
+  return __builtin_dynamic_object_size (res, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_strndup (const char *in, size_t bound)
+{
+  char *res = __builtin_strndup (in, bound);
+  return __builtin_dynamic_object_size (res, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_strdup_min (const char *in)
+{
+  char *res = __builtin_strdup (in);
+  return __builtin_dynamic_object_size (res, 2);
+}
+
+size_t
+__attribute__ ((noinline))
+test_strndup_min (const char *in, size_t bound)
+{
+  char *res = __builtin_strndup (in, bound);
+  return __builtin_dynamic_object_size (res, 2);
+}
+
 /* Other tests.  */
 
 struct TV4
@@ -651,6 +685,15 @@ main (int argc, char **argv)
   int *t = test_pr105736 ();
   if (__builtin_dynamic_object_size (t, 0) != -1)
 FAIL ();
+  const char *str = "hello world";
+  if (test_strdup (str) != __builtin_strlen (str) + 1)
+FAIL ();
+  if (test_strndup (str, 4) != 5)
+FAIL ();
+  if (test_strdup_min (str) != __builtin_strlen (str) + 1)
+FAIL ();
+  if (test_strndup_min (str, 4) != 0)
+FAIL ();
 
   if (nfails > 0)
 __builtin_abort ();
diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
index 7cc8b1c9488..8f17c8edcaf 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2" } */
+/* { dg-options "-O2 -Wno-stringop-overread" } */
 /* { dg-require-effective-target alloca } */
 
 #define __builtin_object_size __builtin_dynamic_object_size
diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
index 267dbf48ca7..3677782ff1c 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2" } */
+/* { dg-options "-O2 -Wno-stringop-overread" } */
 

Re: [PATCH] middle-end/104854: Avoid overread warning for strnlen and strndup

2022-07-10 Thread Siddhesh Poyarekar

On 10/07/2022 21:44, Jeff Law wrote:
This may all argue that these warnings don't belong in -Wall, which is 
obviously a distinct, but vitally important discussion.  I've always 
believed that we can make an educated guess about whether or not to 
include any given warning in -Wall, but we have to be flexible enough to 
take in feedback and adjust.  That's why I was always so interested in 
using Fedora mass builds to get data to drive these decisions.


Yeah, that's the thing I'm trying to find some time to do, hopefully 
later in the year.


Thanks,
Sid


Re: [PATCH] middle-end/104854: Avoid overread warning for strnlen and strndup

2022-07-09 Thread Siddhesh Poyarekar

On 10/07/2022 08:59, Jeff Law via Gcc-patches wrote:



On 3/9/2022 5:39 PM, Siddhesh Poyarekar wrote:

The size argument larger than size of SRC for strnlen and strndup is
problematic only if SRC is not NULL terminated, which invokes undefined
behaviour.  In all other cases, as long as SRC is large enough to have a
NULL char (i.e. size 1 or more), a larger N should not invoke a warning
during compilation.

Such a warning may be a suitable check for the static analyzer instead
with slightly different wording suggesting that choice of size argument
makes the function call equivalent to strlen/strdup.

This change results in the following code going through without a
warning:

--
char *buf;

char *
foo (void)
{
   buf = __builtin_malloc (4);
   __builtin_memset (buf, 'A', 4);

   return __builtin_strndup (buf,  5);
}

int
main ()
{
   __builtin_printf ("%s\n", foo ());
}
--

but the problem above is a missing NULL, not N being larger than the
size of SRC and the overread warning in this context is confusing at
best and misleading (and hinting at the wrong solution) in the worst
case.

gcc/ChangeLog:

middle-end/104854
* gimple-ssa-warn-access.cc (check_access):
New parameter.  Skip warning if in read-only mode, source string
is NULL terminated and has non-zero object size.
(check_access): New parameter.
(check_access): Adjust.
(check_read_access): New parameter.  Adjust for check_access
change.
(pass_waccess::check_builtin): Adjust check_read_access call for
memcmp, memchr.
(pass_waccess::maybe_check_access_sizes): Likewise.

gcc/testsuite/ChangeLog:

middle-end/104854
* gcc.dg/Wstringop-overread.c
(test_strnlen_array, test_strndup_array): Don't expect warning
for non-zero source sizes.
* gcc.dg/attr-nonstring-4.c (strnlen_range): Likewise.
* gcc.dg/pr78902.c: Likewise.
* gcc.dg/warn-strnlen-no-nul.c: Likewise.
I know this is old and the BZ has been set as CLOSED/INVALID.  But it 
was in my TODO list,  and I've got thoughts here so I might as well 
chime in ;-)


The potential overread warning for that code seems quite reasonable to 
me.    Yes it is the case that the length argument is sometimes 
unrelated to the source string.  But even then where's the line for when 
we should and should not warn?


The argument I was trying to make in the context of strnlen and strndup 
was that it is more likely in practice for the length argument to be a 
function of some other property, e.g. a destination buffer or an 
external limit that it is to be related to the source string.  However I 
don't have any concrete evidence (or the cycles to find it at the 
moment) to either back up my claim or refute it.  strndup for example 
seems popular for a substring alloc+copy and also for a general string 
copy with an application-specific upper bound, e.g. PATH_MAX.


Thanks,
Sid


Re: [PATCH v1.1] tree-optimization/105736: Don't let error_mark_node escape for ADDR_EXPR

2022-06-21 Thread Siddhesh Poyarekar

On 20/06/2022 15:20, Jakub Jelinek wrote:

On Tue, Jun 14, 2022 at 09:01:54PM +0530, Siddhesh Poyarekar wrote:

The addr_expr computation does not check for error_mark_node before
returning the size expression.  This used to work in the constant case
because the conversion to uhwi would end up causing it to return
size_unknown, but that won't work for the dynamic case.


Regarding subject/first line of commit, it should be something like:

tree-object-size: Don't let error_mark_node escape for ADDR_EXPR [PR105736]
instead of what you have.


Modify the control flow to explicitly return size_unknown if the offset
computation returns an error_mark_node.

gcc/ChangeLog:

PR tree-optimization/105736
* tree-object-size.cc (addr_object_size): Return size_unknown
when object offset computation returns an error.

gcc/testsuite/ChangeLog:

PR tree-optimization/105736
* gcc.dg/builtin-dynamic-object-size-0.c (TV4, val3,
test_pr105736): New struct declaration, variable and function to
test PR.


If you want to spell the exact changes in the test, it would be better
to do it separately when it is different changes.


Thanks, fixed up before pushing to master.


* gcc.dg/builtin-dynamic-object-size-0.c (struct TV4): New type.
(val3): New variable.
(test_pr105736): New function.

(main): Use them.


Otherwise LGTM, but for GCC 13, it would be nice to add support
for BIT_FIELD_REF if both second and third arguments are multiples of
BITS_PER_UNIT.


Ack, I'll test and post this as a separate change.


Signed-off-by: Siddhesh Poyarekar 
---
Changes from v1:
- Used FAIL() instead of __builtin_abort() in the test.

Tested:

- x86_64 bootstrap and test
- --with-build-config=bootstrap-ubsan build

May I also backport this to gcc12?


Ok.


Thanks, I'll give it a couple of days in master and then cherry-pick.

Sid


[ping][PATCH v1.1] tree-optimization/105736: Don't let error_mark_node escape for ADDR_EXPR

2022-06-19 Thread Siddhesh Poyarekar

Hello,

ping!

On 14/06/2022 21:01, Siddhesh Poyarekar wrote:

The addr_expr computation does not check for error_mark_node before
returning the size expression.  This used to work in the constant case
because the conversion to uhwi would end up causing it to return
size_unknown, but that won't work for the dynamic case.

Modify the control flow to explicitly return size_unknown if the offset
computation returns an error_mark_node.

gcc/ChangeLog:

PR tree-optimization/105736
* tree-object-size.cc (addr_object_size): Return size_unknown
when object offset computation returns an error.

gcc/testsuite/ChangeLog:

PR tree-optimization/105736
* gcc.dg/builtin-dynamic-object-size-0.c (TV4, val3,
test_pr105736): New struct declaration, variable and function to
test PR.
(main): Use them.

Signed-off-by: Siddhesh Poyarekar 
---
Changes from v1:
- Used FAIL() instead of __builtin_abort() in the test.

Tested:

- x86_64 bootstrap and test
- --with-build-config=bootstrap-ubsan build

May I also backport this to gcc12?

  .../gcc.dg/builtin-dynamic-object-size-0.c| 18 +
  gcc/tree-object-size.cc   | 20 ++-
  2 files changed, 29 insertions(+), 9 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
index b5b0b3a677c..01a280b2d7b 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -479,6 +479,20 @@ test_loop (int *obj, size_t sz, size_t start, size_t end, 
int incr)
return __builtin_dynamic_object_size (ptr, 0);
  }
  
+/* Other tests.  */

+
+struct TV4
+{
+  __attribute__((vector_size (sizeof (int) * 4))) int v;
+};
+
+struct TV4 val3;
+int *
+test_pr105736 (struct TV4 *a)
+{
+  return >v[0];
+}
+
  unsigned nfails = 0;
  
  #define FAIL() ({ \

@@ -633,6 +647,10 @@ main (int argc, char **argv)
  FAIL ();
if (test_loop (arr, 42, 20, 52, 1) != 0)
  FAIL ();
+  /* pr105736.  */
+  int *t = test_pr105736 ();
+  if (__builtin_dynamic_object_size (t, 0) != -1)
+FAIL ();
  
if (nfails > 0)

  __builtin_abort ();
diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
index 5ca87ae3504..12bc0868b77 100644
--- a/gcc/tree-object-size.cc
+++ b/gcc/tree-object-size.cc
@@ -695,19 +695,21 @@ addr_object_size (struct object_size_info *osi, 
const_tree ptr,
var_size = pt_var_size;
bytes = compute_object_offset (TREE_OPERAND (ptr, 0), var);
if (bytes != error_mark_node)
-   bytes = size_for_offset (var_size, bytes);
-  if (var != pt_var
- && pt_var_size
- && TREE_CODE (pt_var) == MEM_REF
- && bytes != error_mark_node)
{
- tree bytes2 = compute_object_offset (TREE_OPERAND (ptr, 0), pt_var);
- if (bytes2 != error_mark_node)
+ bytes = size_for_offset (var_size, bytes);
+ if (var != pt_var && pt_var_size && TREE_CODE (pt_var) == MEM_REF)
{
- bytes2 = size_for_offset (pt_var_size, bytes2);
- bytes = size_binop (MIN_EXPR, bytes, bytes2);
+ tree bytes2 = compute_object_offset (TREE_OPERAND (ptr, 0),
+  pt_var);
+ if (bytes2 != error_mark_node)
+   {
+ bytes2 = size_for_offset (pt_var_size, bytes2);
+ bytes = size_binop (MIN_EXPR, bytes, bytes2);
+   }
}
}
+  else
+   bytes = size_unknown (object_size_type);
  
wholebytes

= object_size_type & OST_SUBOBJECT ? var_size : pt_var_wholesize;




[PATCH v1.1] tree-optimization/105736: Don't let error_mark_node escape for ADDR_EXPR

2022-06-14 Thread Siddhesh Poyarekar
The addr_expr computation does not check for error_mark_node before
returning the size expression.  This used to work in the constant case
because the conversion to uhwi would end up causing it to return
size_unknown, but that won't work for the dynamic case.

Modify the control flow to explicitly return size_unknown if the offset
computation returns an error_mark_node.

gcc/ChangeLog:

PR tree-optimization/105736
* tree-object-size.cc (addr_object_size): Return size_unknown
when object offset computation returns an error.

gcc/testsuite/ChangeLog:

PR tree-optimization/105736
* gcc.dg/builtin-dynamic-object-size-0.c (TV4, val3,
test_pr105736): New struct declaration, variable and function to
test PR.
(main): Use them.

Signed-off-by: Siddhesh Poyarekar 
---
Changes from v1:
- Used FAIL() instead of __builtin_abort() in the test.

Tested:

- x86_64 bootstrap and test
- --with-build-config=bootstrap-ubsan build

May I also backport this to gcc12?

 .../gcc.dg/builtin-dynamic-object-size-0.c| 18 +
 gcc/tree-object-size.cc   | 20 ++-
 2 files changed, 29 insertions(+), 9 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
index b5b0b3a677c..01a280b2d7b 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -479,6 +479,20 @@ test_loop (int *obj, size_t sz, size_t start, size_t end, 
int incr)
   return __builtin_dynamic_object_size (ptr, 0);
 }
 
+/* Other tests.  */
+
+struct TV4
+{
+  __attribute__((vector_size (sizeof (int) * 4))) int v;
+};
+
+struct TV4 val3;
+int *
+test_pr105736 (struct TV4 *a)
+{
+  return >v[0];
+}
+
 unsigned nfails = 0;
 
 #define FAIL() ({ \
@@ -633,6 +647,10 @@ main (int argc, char **argv)
 FAIL ();
   if (test_loop (arr, 42, 20, 52, 1) != 0)
 FAIL ();
+  /* pr105736.  */
+  int *t = test_pr105736 ();
+  if (__builtin_dynamic_object_size (t, 0) != -1)
+FAIL ();
 
   if (nfails > 0)
 __builtin_abort ();
diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
index 5ca87ae3504..12bc0868b77 100644
--- a/gcc/tree-object-size.cc
+++ b/gcc/tree-object-size.cc
@@ -695,19 +695,21 @@ addr_object_size (struct object_size_info *osi, 
const_tree ptr,
var_size = pt_var_size;
   bytes = compute_object_offset (TREE_OPERAND (ptr, 0), var);
   if (bytes != error_mark_node)
-   bytes = size_for_offset (var_size, bytes);
-  if (var != pt_var
- && pt_var_size
- && TREE_CODE (pt_var) == MEM_REF
- && bytes != error_mark_node)
{
- tree bytes2 = compute_object_offset (TREE_OPERAND (ptr, 0), pt_var);
- if (bytes2 != error_mark_node)
+ bytes = size_for_offset (var_size, bytes);
+ if (var != pt_var && pt_var_size && TREE_CODE (pt_var) == MEM_REF)
{
- bytes2 = size_for_offset (pt_var_size, bytes2);
- bytes = size_binop (MIN_EXPR, bytes, bytes2);
+ tree bytes2 = compute_object_offset (TREE_OPERAND (ptr, 0),
+  pt_var);
+ if (bytes2 != error_mark_node)
+   {
+ bytes2 = size_for_offset (pt_var_size, bytes2);
+ bytes = size_binop (MIN_EXPR, bytes, bytes2);
+   }
}
}
+  else
+   bytes = size_unknown (object_size_type);
 
   wholebytes
= object_size_type & OST_SUBOBJECT ? var_size : pt_var_wholesize;
-- 
2.35.3



[PATCH] tree-optimization/105736: Don't let error_mark_node escape for ADDR_EXPR

2022-06-14 Thread Siddhesh Poyarekar
The addr_expr computation does not check for error_mark_node before
returning the size expression.  This used to work in the constant case
because the conversion to uhwi would end up causing it to return
size_unknown, but that won't work for the dynamic case.

Modify the control flow to explicitly return size_unknown if the offset
computation returns an error_mark_node.

gcc/ChangeLog:

PR tree-optimization/105736
* tree-object-size.cc (addr_object_size): Return size_unknown
when object offset computation returns an error.

gcc/testsuite/ChangeLog:

PR tree-optimization/105736
* gcc.dg/builtin-dynamic-object-size-0.c (TV4, val3,
test_pr105736): New struct declaration, variable and function to
test PR.
(main): Use them.

Signed-off-by: Siddhesh Poyarekar 
---

Tested:

- x86_64 bootstrap and test
- --with-build-config=bootstrap-ubsan build

May I also backport this to gcc12?

 .../gcc.dg/builtin-dynamic-object-size-0.c| 19 ++
 gcc/tree-object-size.cc   | 20 ++-
 2 files changed, 30 insertions(+), 9 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
index b5b0b3a677c..90f303ef40e 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -479,6 +479,20 @@ test_loop (int *obj, size_t sz, size_t start, size_t end, 
int incr)
   return __builtin_dynamic_object_size (ptr, 0);
 }
 
+/* Other tests.  */
+
+struct TV4
+{
+  __attribute__((vector_size (sizeof (int) * 4))) int v;
+};
+
+struct TV4 val3;
+int *
+test_pr105736 (struct TV4 *a)
+{
+  return >v[0];
+}
+
 unsigned nfails = 0;
 
 #define FAIL() ({ \
@@ -633,6 +647,11 @@ main (int argc, char **argv)
 FAIL ();
   if (test_loop (arr, 42, 20, 52, 1) != 0)
 FAIL ();
+  /* pr105736.  */
+  int *t = test_pr105736 ();
+  if (__builtin_dynamic_object_size (t, 0) != -1)
+__builtin_abort ();
+
 
   if (nfails > 0)
 __builtin_abort ();
diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
index 5ca87ae3504..12bc0868b77 100644
--- a/gcc/tree-object-size.cc
+++ b/gcc/tree-object-size.cc
@@ -695,19 +695,21 @@ addr_object_size (struct object_size_info *osi, 
const_tree ptr,
var_size = pt_var_size;
   bytes = compute_object_offset (TREE_OPERAND (ptr, 0), var);
   if (bytes != error_mark_node)
-   bytes = size_for_offset (var_size, bytes);
-  if (var != pt_var
- && pt_var_size
- && TREE_CODE (pt_var) == MEM_REF
- && bytes != error_mark_node)
{
- tree bytes2 = compute_object_offset (TREE_OPERAND (ptr, 0), pt_var);
- if (bytes2 != error_mark_node)
+ bytes = size_for_offset (var_size, bytes);
+ if (var != pt_var && pt_var_size && TREE_CODE (pt_var) == MEM_REF)
{
- bytes2 = size_for_offset (pt_var_size, bytes2);
- bytes = size_binop (MIN_EXPR, bytes, bytes2);
+ tree bytes2 = compute_object_offset (TREE_OPERAND (ptr, 0),
+  pt_var);
+ if (bytes2 != error_mark_node)
+   {
+ bytes2 = size_for_offset (pt_var_size, bytes2);
+ bytes = size_binop (MIN_EXPR, bytes, bytes2);
+   }
}
}
+  else
+   bytes = size_unknown (object_size_type);
 
   wholebytes
= object_size_type & OST_SUBOBJECT ? var_size : pt_var_wholesize;
-- 
2.35.3



[PATCH] middle-end/70090: Register __bdos for sanitizers if necessary

2022-05-10 Thread Siddhesh Poyarekar
The asan initializer registers __builtin_object_size for languages that
don't have it, e.g. Fortran.  Register __builtin_dynamic_object_size too
(we need both because __builtin_dynamic_object_size computation may
involve generating __builtin_object_size as a fallback) so that
gfortran.dg/ubsan/bind-c-intent-out-2.f90 does not crash anymore.

gcc/ChangeLog:

PR middle-end/70090
* asan.cc (initialize_sanitizer_builtins): Register
__builtin_dynamic_object_size if necessary.

Signed-off-by: Siddhesh Poyarekar 
---
Testing:
- I realized that for some reason I was looking only at gcc.log in the
  testsuite, so expanded my checks to look at failures in the entire check
  output.  Verified that gfortran.dg/ubsan/bind-c-intent-out-2.f90 failed on
  master and passed with this patch.
- Bootstrapped and tested on x86_64
- Bootstrapped --with-build-config=bootstrap-ubsan
- i686 build and test

 gcc/asan.cc | 24 
 1 file changed, 16 insertions(+), 8 deletions(-)

diff --git a/gcc/asan.cc b/gcc/asan.cc
index ef59b77ebc2..4b583e54efd 100644
--- a/gcc/asan.cc
+++ b/gcc/asan.cc
@@ -3457,14 +3457,22 @@ initialize_sanitizer_builtins (void)
 
 #include "sanitizer.def"
 
-  /* -fsanitize=object-size uses __builtin_object_size, but that might
- not be available for e.g. Fortran at this point.  We use
- DEF_SANITIZER_BUILTIN here only as a convenience macro.  */
-  if ((flag_sanitize & SANITIZE_OBJECT_SIZE)
-  && !builtin_decl_implicit_p (BUILT_IN_OBJECT_SIZE))
-DEF_SANITIZER_BUILTIN_1 (BUILT_IN_OBJECT_SIZE, "object_size",
-BT_FN_SIZE_CONST_PTR_INT,
-ATTR_PURE_NOTHROW_LEAF_LIST);
+  /* -fsanitize=object-size uses __builtin_dynamic_object_size and
+ __builtin_object_size, but they might not be available for e.g. Fortran at
+ this point.  We use DEF_SANITIZER_BUILTIN here only as a convenience
+ macro.  */
+  if (flag_sanitize & SANITIZE_OBJECT_SIZE)
+{
+  if (!builtin_decl_implicit_p (BUILT_IN_OBJECT_SIZE))
+   DEF_SANITIZER_BUILTIN_1 (BUILT_IN_OBJECT_SIZE, "object_size",
+BT_FN_SIZE_CONST_PTR_INT,
+ATTR_PURE_NOTHROW_LEAF_LIST);
+  if (!builtin_decl_implicit_p (BUILT_IN_DYNAMIC_OBJECT_SIZE))
+   DEF_SANITIZER_BUILTIN_1 (BUILT_IN_DYNAMIC_OBJECT_SIZE,
+"dynamic_object_size",
+BT_FN_SIZE_CONST_PTR_INT,
+ATTR_PURE_NOTHROW_LEAF_LIST);
+}
 
 #undef DEF_SANITIZER_BUILTIN_1
 #undef DEF_SANITIZER_BUILTIN
-- 
2.35.1



Re: [patch gcc13] middle-end/70090: Dynamic sizes for -fsanitize=object-size

2022-05-10 Thread Siddhesh Poyarekar

On 10/05/2022 16:16, Martin Liška wrote:

The revision caused:

$ ./xgcc -B. 
/home/marxin/Programming/gcc/gcc/testsuite/gfortran.dg/ubsan/bind-c-intent-out-2.f90
 -fsanitize=undefined -c -O
during GIMPLE pass: ubsan
/home/marxin/Programming/gcc/gcc/testsuite/gfortran.dg/ubsan/bind-c-intent-out-2.f90:39:19:

39 | end program alloc_p
   |   ^
internal compiler error: Segmentation fault
0x14b45c7 crash_signal
/home/marxin/Programming/gcc/gcc/toplev.cc:322
0x778b83cf ???

/usr/src/debug/glibc-2.35-2.1.x86_64/signal/../sysdeps/unix/sysv/linux/x86_64/libc_sigaction.c:0
0xc2cf10 contains_struct_check(tree_node*, tree_node_structure_enum, char 
const*, int, char const*)
/home/marxin/Programming/gcc/gcc/tree.h:3570
0x19100d1 build_call_expr_loc_array(unsigned int, tree_node*, int, tree_node**)
/home/marxin/Programming/gcc/gcc/tree.cc:10629
0x19102ff build_call_expr_loc(unsigned int, tree_node*, int, ...)
/home/marxin/Programming/gcc/gcc/tree.cc:10662
0x14f59a3 instrument_object_size
/home/marxin/Programming/gcc/gcc/ubsan.cc:2173
0x14f6770 execute
/home/marxin/Programming/gcc/gcc/ubsan.cc:2428
Please submit a full bug report, with preprocessed source (by using 
-freport-bug).
Please include the complete backtrace with any bug report.
See  for instructions.


Thanks, I just noticed that my non-ubsan bootstrap didn't enable 
sanitizers because of which I didn't see this at all.  I'm testing a fix 
and I'll post it once bootstraps finish.


Siddhesh


Re: [patch gcc13] middle-end/70090: Dynamic sizes for -fsanitize=object-size

2022-05-09 Thread Siddhesh Poyarekar

On 07/02/2022 17:37, Jakub Jelinek wrote:

On Mon, Feb 07, 2022 at 05:31:58PM +0530, Siddhesh Poyarekar wrote:

Use __builtin_dynamic_object_size to get object sizes for ubsan.

gcc/ChangeLog:

middle-end/70090
* ubsan.cc (ubsan_expand_objsize_ifn): Allow non-constant SIZE.
(instrument_object_size): Get dynamic object size expression.

gcc/testsuite/ChangeLog:

middle-end/70090
* gcc.dg/ubsan/object-size-dyn.c: New test.

Signed-off-by: Siddhesh Poyarekar 
---
Proposing for gcc13 since I reckoned this is not feasible for stage 4.


Ok for stage1.

Jakub



Hi Jakub, may I rebase and push this now?

Thanks,
Siddhesh


Re: [PATCH] middle-end/104854: Avoid overread warning for strnlen and strndup

2022-03-25 Thread Siddhesh Poyarekar

On 10/03/2022 06:09, Siddhesh Poyarekar wrote:

The size argument larger than size of SRC for strnlen and strndup is
problematic only if SRC is not NULL terminated, which invokes undefined
behaviour.  In all other cases, as long as SRC is large enough to have a
NULL char (i.e. size 1 or more), a larger N should not invoke a warning
during compilation.

Such a warning may be a suitable check for the static analyzer instead
with slightly different wording suggesting that choice of size argument
makes the function call equivalent to strlen/strdup.


This fix is too aggressive, I need to take another pass at this once 
stage 1 opens.


Siddhesh


Re: [PATCH v2] middle-end/104854: Limit strncmp overread warnings

2022-03-25 Thread Siddhesh Poyarekar

On 25/03/2022 18:56, Jason Merrill via Gcc-patches wrote:
Perhaps a suitable compromise would be to add a separate warning flag 
specifically for the strn* warnings, so users deliberately using the 
bound to express a limit other than the length of the argument string 
(and confident that their strings are always NUL-terminated) can turn 
them off without turning off all the overread warnings.


For strncmp (in cases where NUL termination cannot be proven) that is 
perhaps a reasonable compromise.  However I think I need to take a 
closer look to figure out if there are other ways to work around this, 
especially since discovering that I had misread the previous report.


I take back this patch and will revisit this a bit later, probably once 
stage 1 opens.


Thanks,
Siddhesh


[PATCH] tree-optimization/104970: Limit size computation for access attribute

2022-03-23 Thread Siddhesh Poyarekar
Limit object size computation only to the simple case where access
attribute has been explicitly specified.  The object passed to
__builtin_dynamic_object_size could either be a pointer or a VLA whose
size has been described only using access attribute.

Further, return a valid size only if the object is a void * pointer or
points to (or is a VLA of) a type that has a constant size.

gcc/ChangeLog:

PR tree-optimization/104970
* tree-object-size.cc (parm_object_size): Restrict size
computation scenarios to explicit access attributes.

gcc/testsuite/ChangeLog:

PR tree-optimization/104970
* gcc.dg/builtin-dynamic-object-size-0.c (test_parmsz_simple2,
test_parmsz_simple3, test_parmsz_extern, test_parmsz_internal,
test_parmsz_internal2, test_parmsz_internal3): New tests.
(main): Use them.

Signed-off-by: Siddhesh Poyarekar 
---

Tested:
- x86_64 bootstrap and test
- x86_64 ubsan bootstrap
- i686 test

 .../gcc.dg/builtin-dynamic-object-size-0.c| 71 +++
 gcc/tree-object-size.cc   | 11 ++-
 2 files changed, 79 insertions(+), 3 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
index e5dc23a908d..b5b0b3a677c 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -380,6 +380,22 @@ test_parmsz_simple (void *obj, size_t sz)
   return __builtin_dynamic_object_size (obj, 0);
 }
 
+size_t
+__attribute__ ((access (__read_write__, 2, 1)))
+__attribute__ ((noinline))
+test_parmsz_simple2 (size_t sz, char obj[])
+{
+  return __builtin_dynamic_object_size (obj, 0);
+}
+
+/* Implicitly constructed access attributes not supported yet.  */
+size_t
+__attribute__ ((noinline))
+test_parmsz_simple3 (size_t sz, char obj[sz])
+{
+  return __builtin_dynamic_object_size (obj, 0);
+}
+
 size_t
 __attribute__ ((noinline))
 __attribute__ ((access (__read_write__, 1, 2)))
@@ -412,6 +428,38 @@ test_parmsz_unknown (void *obj, void *unknown, size_t sz, 
int cond)
   return __builtin_dynamic_object_size (cond ? obj : unknown, 0);
 }
 
+struct S;
+size_t
+__attribute__ ((access (__read_write__, 1, 2)))
+__attribute__ ((noinline))
+test_parmsz_extern (struct S *obj, size_t sz)
+{
+  return __builtin_dynamic_object_size (obj, 0);
+}
+
+/* Implicitly constructed access attributes not supported yet.  */
+size_t
+__attribute__ ((noinline))
+test_parmsz_internal (size_t sz, double obj[][sz])
+{
+  return __builtin_dynamic_object_size (obj, 0);
+}
+
+size_t
+__attribute__ ((access (__read_write__, 2, 1)))
+__attribute__ ((noinline))
+test_parmsz_internal2 (size_t sz, double obj[][sz])
+{
+  return __builtin_dynamic_object_size (obj, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_parmsz_internal3 (size_t sz1, size_t sz2, double obj[sz1][sz2])
+{
+  return __builtin_dynamic_object_size (obj, 0);
+}
+
 /* Loops.  */
 
 size_t
@@ -532,9 +580,22 @@ main (int argc, char **argv)
   if (test_parmsz_simple (argv[0], __builtin_strlen (argv[0]) + 1)
   != __builtin_strlen (argv[0]) + 1)
 FAIL ();
+  if (test_parmsz_simple2 (__builtin_strlen (argv[0]) + 1, argv[0])
+  != __builtin_strlen (argv[0]) + 1)
+FAIL ();
+  /* Only explicitly added access attributes are supported for now.  */
+  if (test_parmsz_simple3 (__builtin_strlen (argv[0]) + 1, argv[0]) != -1)
+FAIL ();
   int arr[42];
   if (test_parmsz_scaled (arr, 42) != sizeof (arr))
 FAIL ();
+  if (test_parmsz_scaled (arr, 40) != 40 * sizeof (int))
+FAIL ();
+  /* __bdos cannot see the actual size of ARR, so it will return what it was
+ passed.  Fortunately though the overflow warnings see this caller side and
+ warns of the problematic size.  */
+  if (test_parmsz_scaled (arr, 44) != 44 * sizeof (int)) /* { dg-warning 
"-Wstringop-overflow=" } */
+FAIL ();
   if (test_parmsz_unknown (argv[0], argv[0], __builtin_strlen (argv[0]) + 1, 0)
   != -1)
   if (test_parmsz (argv[0], __builtin_strlen (argv[0]) + 1, -1) != 0)
@@ -550,6 +611,16 @@ main (int argc, char **argv)
 FAIL ();
   if (test_parmsz_scaled_off (arr, 42, 2) != 40 * sizeof (int))
 FAIL ();
+  struct S *s;
+  if (test_parmsz_extern (s, 42) != -1)
+FAIL ();
+  double obj[4][4];
+  if (test_parmsz_internal (4, obj) != -1)
+FAIL ();
+  if (test_parmsz_internal2 (4, obj) != -1)
+FAIL ();
+  if (test_parmsz_internal3 (4, 4, obj) != -1)
+FAIL ();
   if (test_loop (arr, 42, 0, 32, 1) != 10 * sizeof (int))
 FAIL ();
   if (test_loop (arr, 42, 32, -1, -1) != 0)
diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
index b0b50774936..fc062b94d76 100644
--- a/gcc/tree-object-size.cc
+++ b/gcc/tree-object-size.cc
@@ -1477,14 +1477,19 @@ parm_object_size (struct object_size_info *osi, tree 
var)
   tree typesize = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (parm)));
   tree sz = NULL_TREE;
 
-  if (access &&a

Re: [PATCH v2] middle-end/104854: Limit strncmp overread warnings

2022-03-17 Thread Siddhesh Poyarekar

On 17/03/2022 23:21, Martin Sebor wrote:

On 3/17/22 11:22, Siddhesh Poyarekar wrote:

On 17/03/2022 22:16, Jeff Law wrote:

    #include 
    char a[] = "abc";
    char b[] = "abcd";

    int f (void)
    {
   return strncmp (a, b, 8);
    }

    where I get

    t.c:7:10: warning: ‘strncmp’ specified bound 8 exceeds source size 5
    [-Wstringop-overread]
     7 |   return strncmp (a, b, 8);   // -Wstringop-overread
       |          ^

    even without -Wall.  strncmp sees that a[3] is '\0' so it stops
    comparing
    and there's no UB.

This one is a clear case where warning is bad.   Both arguments are 
constant and we can determine they are NUL terminated and an overread 
will never occur.  No deep analysis really needed here.


THe far more interesting case in my mind is when one or both 
arguments have an unknown NUL termination state.  I could argue 
either side of that case.  I lean towards warning but I understand 
that opinions differ and my priorities have moved away from 
distro-level issues, so identifying code that needs a careful review 
for correctness, particularly old or security sensitive code, has 
become a much lower priority for me.   Combine that with the fact 
that we're really just dealing with over-reads here, I can support 
whatever the broadest consensus is.


Actually in the above reproducer a and b are not const, so this is in 
fact the case where the NUL termination state of the strings is in 
theory unknown.  From the distro level (and in general for 
applications) the question is how common this is and I gathered from a 
Red Hat internal conversation that it's not uncommon.  However David 
pointed out that I need to share more specific examples to quantify 
this, so I need to work on that.  I'll share an update once I have it.


One case I am aware of is the pmix package in Fedora/RHEL, which has 
the following warning:


pmix-3.2.3/examples/alloc.c: scope_hint: In function 'main'
pmix-3.2.3/examples/alloc.c:179:31: warning[-Wstringop-overread]: 
'PMIx_Get' reading 512 bytes from a region of size 15
   179 | if (PMIX_SUCCESS != (rc = PMIx_Get(, PMIX_UNIV_SIZE, 
NULL, 0, ))) {

   | ^~
pmix-3.2.3/examples/alloc.c:179:31: note: referencing argument 2 of 
type 'const char *'

pmix-3.2.3/examples/alloc.c:33: included_from: Included from here.
pmix-3.2.3/include/pmix.h:203:27: note: in a call to function 'PMIx_Get'
   203 | PMIX_EXPORT pmix_status_t PMIx_Get(const pmix_proc_t *proc, 
const pmix_key_t key,

   |   ^~~~
   177|   PMIX_PROC_CONSTRUCT();
   178|   PMIX_LOAD_PROCID(, myproc.nspace, PMIX_RANK_WILDCARD);
   179|-> if (PMIX_SUCCESS != (rc = PMIx_Get(, 
PMIX_UNIV_SIZE, NULL, 0, ))) {
   180|   fprintf(stderr, "Client ns %s rank %d: PMIx_Get 
universe size failed: %d\n", myproc.nspace, myproc.rank, rc);

   181|   goto done;

which is due to PMIx_Get calling strncmp a few levels within with 
non-const strings and a max size of 512 (the maximum size that a key 
could be; AFAICT it's the size of the buffer into which the key gets 
written out), where the strings are always NULL terminated.


This warning has nothing to do with strncmp.

It's issued for the call to PMIx_Get(), where the caller passes as
the second argument PMIX_UNIV_SIZE, a macro that expands to
the string "pmix.univ.size".

The function is declared like so:

   PMIX_EXPORT pmix_status_t
   PMIx_Get(const pmix_proc_t *proc, const pmix_key_t key,
    const pmix_info_t info[], size_t ninfo,
    pmix_value_t **val);

The type of the second function argument, pmix_key_t, defined as

   typedef char pmix_key_t[PMIX_MAX_KEYLEN+1];

an array of 512 elements (PMIX_MAX_KEYLEN is defined to 511), but
PMIX_UNIV_SIZE is much smaller (just 15 bytes).

The warning detects passing smaller arrays to parameters of larger
types declared using the array syntax.  It's controlled by
-Warray-parameter.


That's odd, shouldn't it show up as -Warray-parameter then and not 
-Wstringop-overread?


Siddhesh


Re: [PATCH v2] middle-end/104854: Limit strncmp overread warnings

2022-03-17 Thread Siddhesh Poyarekar

On 17/03/2022 22:16, Jeff Law wrote:

#include 
char a[] = "abc";
char b[] = "abcd";

int f (void)
{
   return strncmp (a, b, 8);
}

where I get

t.c:7:10: warning: ‘strncmp’ specified bound 8 exceeds source size 5
[-Wstringop-overread]
     7 |   return strncmp (a, b, 8);   // -Wstringop-overread
       |          ^

even without -Wall.  strncmp sees that a[3] is '\0' so it stops
comparing
and there's no UB.

This one is a clear case where warning is bad.   Both arguments are 
constant and we can determine they are NUL terminated and an overread 
will never occur.  No deep analysis really needed here.


THe far more interesting case in my mind is when one or both arguments 
have an unknown NUL termination state.  I could argue either side of 
that case.  I lean towards warning but I understand that opinions differ 
and my priorities have moved away from distro-level issues, so 
identifying code that needs a careful review for correctness, 
particularly old or security sensitive code, has become a much lower 
priority for me.   Combine that with the fact that we're really just 
dealing with over-reads here, I can support whatever the broadest 
consensus is.


Actually in the above reproducer a and b are not const, so this is in 
fact the case where the NUL termination state of the strings is in 
theory unknown.  From the distro level (and in general for applications) 
the question is how common this is and I gathered from a Red Hat 
internal conversation that it's not uncommon.  However David pointed out 
that I need to share more specific examples to quantify this, so I need 
to work on that.  I'll share an update once I have it.


One case I am aware of is the pmix package in Fedora/RHEL, which has the 
following warning:


pmix-3.2.3/examples/alloc.c: scope_hint: In function 'main'
pmix-3.2.3/examples/alloc.c:179:31: warning[-Wstringop-overread]: 
'PMIx_Get' reading 512 bytes from a region of size 15
  179 | if (PMIX_SUCCESS != (rc = PMIx_Get(, PMIX_UNIV_SIZE, 
NULL, 0, ))) {
  | 
^~
pmix-3.2.3/examples/alloc.c:179:31: note: referencing argument 2 of type 
'const char *'

pmix-3.2.3/examples/alloc.c:33: included_from: Included from here.
pmix-3.2.3/include/pmix.h:203:27: note: in a call to function 'PMIx_Get'
  203 | PMIX_EXPORT pmix_status_t PMIx_Get(const pmix_proc_t *proc, 
const pmix_key_t key,

  |   ^~~~
  177|   PMIX_PROC_CONSTRUCT();
  178|   PMIX_LOAD_PROCID(, myproc.nspace, PMIX_RANK_WILDCARD);
  179|-> if (PMIX_SUCCESS != (rc = PMIx_Get(, PMIX_UNIV_SIZE, 
NULL, 0, ))) {
  180|   fprintf(stderr, "Client ns %s rank %d: PMIx_Get 
universe size failed: %d\n", myproc.nspace, myproc.rank, rc);

  181|   goto done;

which is due to PMIx_Get calling strncmp a few levels within with 
non-const strings and a max size of 512 (the maximum size that a key 
could be; AFAICT it's the size of the buffer into which the key gets 
written out), where the strings are always NULL terminated.


Thanks,
Siddhesh


Re: [PATCH v2] middle-end/104854: Limit strncmp overread warnings

2022-03-16 Thread Siddhesh Poyarekar

On 17/03/2022 05:11, Martin Sebor wrote:

As the GCC manual prominently states (and as I already pointed out)
warnings are:


We are indeed going around in circles.  Hopefully someone else will 
pitch in and break the deadlock.


Siddhesh


[PATCH] tree-optimization/104941: Actually assign the conversion result

2022-03-16 Thread Siddhesh Poyarekar
Assign the result of fold_convert to offset.

gcc/ChangeLog:

PR tree-optimization/104941
* tree-object-size.cc (size_for_offset): Assign result of
fold_convert to OFFSET.

gcc/testsuite/ChangeLog:

PR tree-optimization/104941
* gcc.dg/builtin-dynamic-object-size-0.c (S1, S2): New structs.
(test_alloc_nested_structs, g): New functions.
(main): Call test_alloc_nested_structs.

Signed-off-by: Siddhesh Poyarekar 
---

Testing:
- x86_64 bootstrap build and check
- i686 build and check

 .../gcc.dg/builtin-dynamic-object-size-0.c| 34 +++
 gcc/tree-object-size.cc   |  2 +-
 2 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
index 2fca0a9c5b4..e5dc23a908d 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -323,6 +323,34 @@ test_substring (size_t sz, size_t off)
   return __builtin_dynamic_object_size ([off], 0);
 }
 
+struct S2
+{
+  char arr[7];
+};
+
+struct S1
+{
+  int pad;
+  struct S2 s2;
+};
+
+static long
+g (struct S1 *s1)
+{
+  struct S2 *s2 = >s2;
+  return __builtin_dynamic_object_size (s2->arr, 0);
+}
+
+long
+__attribute__ ((noinline))
+test_alloc_nested_structs (int x)
+{
+  struct S1 *s1 = __builtin_malloc (x);
+  return g (s1);
+}
+
+/* POINTER_PLUS expressions.  */
+
 size_t
 __attribute__ ((noinline))
 test_substring_ptrplus (size_t sz, size_t off)
@@ -342,6 +370,8 @@ test_substring_ptrplus2 (size_t sz, size_t off, size_t off2)
   return __builtin_dynamic_object_size (ptr + off2, 0);
 }
 
+/* Function parameters.  */
+
 size_t
 __attribute__ ((access (__read_write__, 1, 2)))
 __attribute__ ((noinline))
@@ -382,6 +412,8 @@ test_parmsz_unknown (void *obj, void *unknown, size_t sz, 
int cond)
   return __builtin_dynamic_object_size (cond ? obj : unknown, 0);
 }
 
+/* Loops.  */
+
 size_t
 __attribute__ ((noinline))
 __attribute__ ((access (__read_write__, 1, 2)))
@@ -491,6 +523,8 @@ main (int argc, char **argv)
 FAIL ();
   if (test_dynarray_cond (1) != 8)
 FAIL ();
+  if (test_alloc_nested_structs (42) != 42 - sizeof (int))
+FAIL ();
   if (test_deploop (128, 4) != 128)
 FAIL ();
   if (test_deploop (128, 129) != 32)
diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
index 9728f79da75..e23e80cb726 100644
--- a/gcc/tree-object-size.cc
+++ b/gcc/tree-object-size.cc
@@ -372,7 +372,7 @@ size_for_offset (tree sz, tree offset, tree wholesize = 
NULL_TREE)
 
   /* Safe to convert now, since a valid net offset should be non-negative.  */
   if (!types_compatible_p (TREE_TYPE (offset), sizetype))
-fold_convert (sizetype, offset);
+offset = fold_convert (sizetype, offset);
 
   if (TREE_CODE (offset) == INTEGER_CST)
 {
-- 
2.35.1



[PATCH] tree-optimization/104942: Retain sizetype conversions till the end

2022-03-16 Thread Siddhesh Poyarekar
Retain the sizetype alloc_object_size to guarantee the assertion in
size_for_offset and to avoid adding a conversion there.  nop conversions
are eliminated at the end anyway in dynamic object size computation.

gcc/ChangeLog:

tree-optimization/104942
* tree-object-size.cc (alloc_object_size): Remove STRIP_NOPS.

gcc/testsuite/ChangeLog:

tree-optimization/104942
* gcc.dg/builtin-dynamic-object-size-0.c (alloc_func_long,
test_builtin_malloc_long): New functions.
(main): Use it.

Signed-off-by: Siddhesh Poyarekar 
---

Testing:

- i686 build and check
- x86_64 bootstrap build and check
- --with-build-config=bootstrap-ubsan

 .../gcc.dg/builtin-dynamic-object-size-0.c| 22 +++
 gcc/tree-object-size.cc   |  5 +
 2 files changed, 23 insertions(+), 4 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
index dd8dc99a580..2fca0a9c5b4 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -4,6 +4,15 @@
 typedef __SIZE_TYPE__ size_t;
 #define abort __builtin_abort
 
+void *
+__attribute__ ((alloc_size (1)))
+__attribute__ ((__nothrow__ , __leaf__))
+__attribute__ ((noinline))
+alloc_func_long (long sz)
+{
+  return __builtin_malloc (sz);
+}
+
 void *
 __attribute__ ((alloc_size (1)))
 __attribute__ ((__nothrow__ , __leaf__))
@@ -145,6 +154,16 @@ test_builtin_malloc_condphi5 (size_t sz, int cond, char *c)
   return ret;
 }
 
+long
+__attribute__ ((noinline))
+test_builtin_malloc_long (long sz, long off)
+{
+  char *a = alloc_func_long (sz);
+  char *dest = a + off;
+  long ret = __builtin_dynamic_object_size (dest, 0);
+  return ret;
+}
+
 /* Calloc-like allocator.  */
 
 size_t
@@ -419,6 +438,9 @@ main (int argc, char **argv)
 FAIL ();
   if (test_builtin_malloc_condphi5 (128, 0, argv[0]) != -1)
 FAIL ();
+  long x = 42;
+  if (test_builtin_malloc_long (x, 0) != x)
+FAIL ();
   if (test_calloc (2048, 4) != 2048 * 4)
 FAIL ();
   if (test_builtin_calloc (2048, 8) != 2048 * 8)
diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
index 8be0df6ba40..9728f79da75 100644
--- a/gcc/tree-object-size.cc
+++ b/gcc/tree-object-size.cc
@@ -784,10 +784,7 @@ alloc_object_size (const gcall *call, int object_size_type)
   else if (arg1 >= 0)
 bytes = fold_convert (sizetype, gimple_call_arg (call, arg1));
 
-  if (bytes)
-return STRIP_NOPS (bytes);
-
-  return size_unknown (object_size_type);
+  return bytes ? bytes : size_unknown (object_size_type);
 }
 
 
-- 
2.35.1



Re: [PATCH v2] middle-end/104854: Limit strncmp overread warnings

2022-03-15 Thread Siddhesh Poyarekar

On 16/03/2022 02:06, Martin Sebor wrote:

The intended use of the strncmp bound is to limit the comparison to
at most the size of the arrays or (in a subset of cases) the length
of an initial substring. Providing an arbitrary bound that's not
related to the sizes as you describe sounds very much like a misuse.


Nothing in the standard says that the bound is related to the sizes of 
input buffers.  I don't think deducing that intent makes sense either, 
nor concluding that any other use case is misuse.



As a historical note, strncmp was first introduced in UNIX v7 where
its purpose, alongside strncpy, was to manipulate (potentially)
unterminated character arrays like file names stored in fixed size
arrays (typically 14 bytes).  Strncpy would fill the buffers with
ASCII data up to their size and pad the rest with nuls only if there
was room.

Strncmp was then used to compare these potentially unterminated
character arrays (e.g., archive headers in ld and ranlib).  The bound
was the size of the fixed size array.  Its other use case was to compare
leading portions of strings (e.g, when looking for an environment
variable or when stripping "./" from path names).


Thanks for sharing the historical perspective.


Since the early UNIX days, both strncpy and to a lesser extent strncmp
have been widely misused and, along with many other functions in
, a frequent source of bugs due to common misunderstanding
of their intended purpose.  The aim of these warnings is to detect
the common (and sometimes less common) misuses and bugs.


They're all valid uses however since they do not violate the standard. 
If we find at compile time that the strings don't terminate at the 
bounds, emitting the warning is OK but the more pessimistic check seems 
like overkill.



I haven't seen these so I can't very well comment on them.  But I can
assure you that warning for the code above is intentional.  Whether
or not the arrays are nul-terminated, the expected way to call
the function is with a bound no greater than their size (some coding
guidelines are explicit about this; see for example the CERT C Secure
Coding standard rule ARR38-C).

(Granted, the manual makes it sound like -Wstringop-overread only
detects provable past-the-end reads.  That's a mistake in
the documentation that should be fixed.  The warning was never quite
so limited, nor was it intended to be.)


The contention is not that it's not provable, it's more that it's 
doesn't even pass the "based on available information this is definitely 
buggy" assertion, making it more a strong suggestion than a warning that 
something is definitely amiss.  Which is why IMO it is more suitable as 
an analyzer check than a warning.


Thanks,
Siddhesh


Re: [PATCH v2] middle-end/104854: Limit strncmp overread warnings

2022-03-15 Thread Siddhesh Poyarekar

On 15/03/2022 21:09, Martin Sebor wrote:

The strncmp function takes arrays as arguments (not necessarily
strings).  The main purpose of the -Wstringop-overread warning
for calls to it is to detect calls where one of the arrays is
not a nul-terminated string and the bound is larger than the size
of the array.  For example:

   char a[4], b[4];

   int f (void)
   {
     return strncmp (a, b, 8);   // -Wstringop-overread
   }

Such a call is suspect: if one of the arrays isn't nul-terminated
the call is undefined.  Otherwise, if both are nul-terminated there


Isn't "suspect" too harsh a description though?  The bound does not 
specify the size of a or b, it specifies the maximum extent to which to 
compare a and b, the extent being any application-specific limit.  In 
fact the limit could be the size of some arbitrary third buffer that the 
contents of a or b must be copied to, truncating to the bound.


I agree the call is undefined if one of the arrays is not nul-terminated 
and that's the thing; nothing about the bound is undefined in this 
context, it's the NUL termination that is key.



is no point in calling strncmp with a bound greater than their sizes.


There is, when the bound describes something else, e.g. the size of a 
third destination buffer into which one of the input buffers may get 
copied into.  Or when the bound describes the maximum length of a set of 
strings where only a subset of the strings are reachable in the current 
function and ranger sees it, allowing us to reduce our input string size 
estimate.  The bounds being the maximum of the lengths of two input 
strings is just one of many possibilities.



With no evidence that this warning is ever harmful I'd consider


There is, the false positives were seen in Fedora/RHEL builds.


suppressing it a regression.  Since the warning is a deliberate
feature in a released compiler and GCC is now in a regression
fixing stage, this patch is out of scope even if a case where
the warning wasn't helpful did turn up (none has been reported
so far).


Wait, I just reported an issue and it's across multiple packages in 
Fedora/RHEL :)


I think this is a regression since gcc 11 due to misunderstanding the 
specification and assuming too strong a relationship between the size 
argument of strncmp (and indeed strnlen and strndup) and the size of 
objects being passed to it.  Compliant code relies on the compiler to do 
the right thing here, i.e. optimize the strncmp call to strcmp and not 
panic about the size argument being larger than the input buffer size. 
If at all such a diagnostic needs to stay, it ought to go into the 
analyzer, where such looser heuristic suggestions are more acceptable 
and sometimes even appreciated.


FWIW, I'm open to splitting the warning levels as you suggested if 
that's the consensus since it at least provides a way to make these 
warnings saner. However I still haven't found the rationale presented so 
far compelling enough to justify these false positives; I just don't see 
a proportional enough reward.  Hopefully more people can chime in with 
their perspective on this.


Thanks,
Siddhesh


[PATCH v2] middle-end/104854: Limit strncmp overread warnings

2022-03-14 Thread Siddhesh Poyarekar
The size argument in strncmp only describe the maximum length to which
to compare two strings and is not an indication of sizes of the two
source strings.  Do not warn if it is larger than the two input strings
because it is entirely likely that the size argument is a conservative
maximum to accommodate inputs of different lengths and only a subset is
reachable through the current code path or that it is some other
application-specific property completely unrelated to the sizes of the
input strings.

gcc/ChangeLog:

middle-end/104854
* gimple-ssa-warn-access.cc
(pass_waccess::warn_zero_sized_strncmp_inputs): New function.
(pass_waccess::check_strncmp): Use it.

gcc/testsuite/ChangeLog:

middle-end/104854
* gcc.dg/Wstringop-overread.c (test_strncmp_array): Don't expect
failures for non-zero sizes.

Signed-off-by: Siddhesh Poyarekar 
---

Changes from v1:

A little better approach, ensuring that it tries to warn on zero length
inputs if the size of at least one of the two sources is known.

Also cc'ing Martin so that we can discuss approach on the list instead
of on the bug.  To summarize the discussion so far, Martin suggests that
the warning be split into levels but I'm contesting the utility of the
heuristics as a compiler warning given the looseness of the relationship
between the size argument and the inputs in the case of these functions.


 gcc/gimple-ssa-warn-access.cc | 69 +--
 gcc/testsuite/gcc.dg/Wstringop-overread.c |  2 +-
 2 files changed, 28 insertions(+), 43 deletions(-)

diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index 75297ed7c9e..15299770e29 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -2137,6 +2137,9 @@ private:
   /* Return true if use follows an invalidating statement.  */
   bool use_after_inval_p (gimple *, gimple *, bool = false);
 
+  /* Emit an overread warning for zero sized inputs to strncmp.  */
+  void warn_zero_sized_strncmp_inputs (gimple *, tree *, access_data *);
+
   /* A pointer_query object to store information about pointers and
  their targets in.  */
   pointer_query m_ptr_qry;
@@ -2619,8 +2622,20 @@ pass_waccess::check_stxncpy (gcall *stmt)
data.mode, , m_ptr_qry.rvals);
 }
 
-/* Check a call STMT to stpncpy() or strncpy() for overflow and warn
-   if it does.  */
+/* Warn for strncmp on a zero sized source or when an argument isn't
+   nul-terminated.  */
+void
+pass_waccess::warn_zero_sized_strncmp_inputs (gimple *stmt, tree *bndrng,
+ access_data *pad)
+{
+  tree func = get_callee_fndecl (stmt);
+  location_t loc = gimple_location (stmt);
+  maybe_warn_for_bound (OPT_Wstringop_overread, loc, stmt, func, bndrng,
+   size_zero_node, pad);
+}
+
+/* Check a call STMT to strncmp () for overflow and warn if it does.  This is
+   limited to checking for NUL terminated arrays for now.  */
 
 void
 pass_waccess::check_strncmp (gcall *stmt)
@@ -2678,46 +2693,16 @@ pass_waccess::check_strncmp (gcall *stmt)
   if (!bndrng[0] || integer_zerop (bndrng[0]))
 return;
 
-  if (len1 && tree_int_cst_lt (len1, bndrng[0]))
-bndrng[0] = len1;
-  if (len2 && tree_int_cst_lt (len2, bndrng[0]))
-bndrng[0] = len2;
-
-  /* compute_objsize almost never fails (and ultimately should never
- fail).  Don't bother to handle the rare case when it does.  */
-  if (!compute_objsize (arg1, stmt, 1, , _ptr_qry)
-  || !compute_objsize (arg2, stmt, 1, , _ptr_qry))
-return;
-
-  /* Compute the size of the remaining space in each array after
- subtracting any offset into it.  */
-  offset_int rem1 = adata1.src.size_remaining ();
-  offset_int rem2 = adata2.src.size_remaining ();
-
-  /* Cap REM1 and REM2 at the other if the other's argument is known
- to be an unterminated array, either because there's no space
- left in it after adding its offset or because it's constant and
- has no nul.  */
-  if (rem1 == 0 || (rem1 < rem2 && lendata1.decl))
-rem2 = rem1;
-  else if (rem2 == 0 || (rem2 < rem1 && lendata2.decl))
-rem1 = rem2;
-
-  /* Point PAD at the array to reference in the note if a warning
- is issued.  */
-  access_data *pad = len1 ?  : 
-  offset_int maxrem = wi::max (rem1, rem2, UNSIGNED);
-  if (lendata1.decl || lendata2.decl
-  || maxrem < wi::to_offset (bndrng[0]))
-{
-  /* Warn when either argument isn't nul-terminated or the maximum
-remaining space in the two arrays is less than the bound.  */
-  tree func = get_callee_fndecl (stmt);
-  location_t loc = gimple_location (stmt);
-  maybe_warn_for_bound (OPT_Wstringop_overread, loc, stmt, func,
-   bndrng, wide_int_to_tree (sizetype, maxrem),
-   pad);
-}
+  /* compute_objsize almost never fails (and ultimately should never fail).
+

[PATCH] middle-end/104854: Limit strncmp overread warnings

2022-03-10 Thread Siddhesh Poyarekar
The size argument in strncmp only describe the maximum length to which
to compare two strings and is not an indication of sizes of the two
source strings.  Do not warn if it is larger than the two input strings
because it is entirely likely that the size argument is a conservative
maximum to accommodate inputs of different lengths and only a subset is
reachable through the current code path.

gcc/ChangeLog:

middle-end/104854
* gimple-ssa-warn-access.cc
(pass_waccess::warn_zero_sized_strncmp_inputs): New function.
(pass_waccess::check_strncmp): Use it.

gcc/testsuite/ChangeLog:

middle-end/104854
* gcc.dg/Wstringop-overread.c (test_strncmp_array): Don't expect
failures for non-zero sizes.

Signed-off-by: Siddhesh Poyarekar 
---

x86_64 bootstrap in progress.

 gcc/gimple-ssa-warn-access.cc | 39 +--
 gcc/testsuite/gcc.dg/Wstringop-overread.c |  2 +-
 2 files changed, 23 insertions(+), 18 deletions(-)

diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index 75297ed7c9e..970f4b9b69f 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -2137,6 +2137,9 @@ private:
   /* Return true if use follows an invalidating statement.  */
   bool use_after_inval_p (gimple *, gimple *, bool = false);
 
+  /* Emit an overread warning for zero sized inputs to strncmp.  */
+  void warn_zero_sized_strncmp_inputs (gimple *, tree *, access_data *);
+
   /* A pointer_query object to store information about pointers and
  their targets in.  */
   pointer_query m_ptr_qry;
@@ -2619,8 +2622,20 @@ pass_waccess::check_stxncpy (gcall *stmt)
data.mode, , m_ptr_qry.rvals);
 }
 
-/* Check a call STMT to stpncpy() or strncpy() for overflow and warn
-   if it does.  */
+/* Warn for strncmp on a zero sized source or when an argument isn't
+   nul-terminated.  */
+void
+pass_waccess::warn_zero_sized_strncmp_inputs (gimple *stmt, tree *bndrng,
+ access_data *pad)
+{
+  tree func = get_callee_fndecl (stmt);
+  location_t loc = gimple_location (stmt);
+  maybe_warn_for_bound (OPT_Wstringop_overread, loc, stmt, func, bndrng,
+   size_zero_node, pad);
+}
+
+/* Check a call STMT to strncmp () for overflow and warn if it does.  This is
+   limited to checking for NUL terminated arrays for now.  */
 
 void
 pass_waccess::check_strncmp (gcall *stmt)
@@ -2703,21 +2718,11 @@ pass_waccess::check_strncmp (gcall *stmt)
   else if (rem2 == 0 || (rem2 < rem1 && lendata2.decl))
 rem1 = rem2;
 
-  /* Point PAD at the array to reference in the note if a warning
- is issued.  */
-  access_data *pad = len1 ?  : 
-  offset_int maxrem = wi::max (rem1, rem2, UNSIGNED);
-  if (lendata1.decl || lendata2.decl
-  || maxrem < wi::to_offset (bndrng[0]))
-{
-  /* Warn when either argument isn't nul-terminated or the maximum
-remaining space in the two arrays is less than the bound.  */
-  tree func = get_callee_fndecl (stmt);
-  location_t loc = gimple_location (stmt);
-  maybe_warn_for_bound (OPT_Wstringop_overread, loc, stmt, func,
-   bndrng, wide_int_to_tree (sizetype, maxrem),
-   pad);
-}
+  if (rem1 == 0)
+warn_zero_sized_strncmp_inputs (stmt, bndrng, );
+  if (rem2 == 0)
+warn_zero_sized_strncmp_inputs (stmt, bndrng, );
+
 }
 
 /* Determine and check the sizes of the source and the destination
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overread.c 
b/gcc/testsuite/gcc.dg/Wstringop-overread.c
index 7db74029819..fb8e626439d 100644
--- a/gcc/testsuite/gcc.dg/Wstringop-overread.c
+++ b/gcc/testsuite/gcc.dg/Wstringop-overread.c
@@ -431,7 +431,7 @@ void test_strncmp_array (const char *s, int i)
 
   T (strncmp (a1, b1, 0));
   T (strncmp (a1, b1, 1));
-  T (strncmp (a1, b1, 2));  // { dg-warning "'strncmp' specified bound 2 
exceeds source size 1" }
+  T (strncmp (a1, b1, 2));
 }
 
 
-- 
2.35.1



[PATCH] middle-end/104854: Avoid overread warning for strnlen and strndup

2022-03-09 Thread Siddhesh Poyarekar
The size argument larger than size of SRC for strnlen and strndup is
problematic only if SRC is not NULL terminated, which invokes undefined
behaviour.  In all other cases, as long as SRC is large enough to have a
NULL char (i.e. size 1 or more), a larger N should not invoke a warning
during compilation.

Such a warning may be a suitable check for the static analyzer instead
with slightly different wording suggesting that choice of size argument
makes the function call equivalent to strlen/strdup.

This change results in the following code going through without a
warning:

--
char *buf;

char *
foo (void)
{
  buf = __builtin_malloc (4);
  __builtin_memset (buf, 'A', 4);

  return __builtin_strndup (buf,  5);
}

int
main ()
{
  __builtin_printf ("%s\n", foo ());
}
--

but the problem above is a missing NULL, not N being larger than the
size of SRC and the overread warning in this context is confusing at
best and misleading (and hinting at the wrong solution) in the worst
case.

gcc/ChangeLog:

middle-end/104854
* gimple-ssa-warn-access.cc (check_access):
New parameter.  Skip warning if in read-only mode, source string
is NULL terminated and has non-zero object size.
(check_access): New parameter.
(check_access): Adjust.
(check_read_access): New parameter.  Adjust for check_access
change.
(pass_waccess::check_builtin): Adjust check_read_access call for
memcmp, memchr.
(pass_waccess::maybe_check_access_sizes): Likewise.

gcc/testsuite/ChangeLog:

middle-end/104854
* gcc.dg/Wstringop-overread.c
(test_strnlen_array, test_strndup_array): Don't expect warning
for non-zero source sizes.
* gcc.dg/attr-nonstring-4.c (strnlen_range): Likewise.
* gcc.dg/pr78902.c: Likewise.
* gcc.dg/warn-strnlen-no-nul.c: Likewise.

Signed-off-by: Siddhesh Poyarekar 
---
Tested with an x86_64 bootstrap.  strncmp has a similar issue, I'll post a
separate patch for it.

 gcc/gimple-ssa-warn-access.cc  | 35 ++
 gcc/testsuite/gcc.dg/Wstringop-overread.c  | 26 
 gcc/testsuite/gcc.dg/attr-nonstring-4.c|  2 +-
 gcc/testsuite/gcc.dg/pr78902.c |  1 -
 gcc/testsuite/gcc.dg/warn-strnlen-no-nul.c | 16 +-
 5 files changed, 45 insertions(+), 35 deletions(-)

diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index c36cd5d45d4..972e80e4b62 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -1256,7 +1256,7 @@ static bool
 check_access (GimpleOrTree exp, tree dstwrite,
  tree maxread, tree srcstr, tree dstsize,
  access_mode mode, const access_data *pad,
- range_query *rvals)
+ range_query *rvals, bool null_terminated)
 {
   /* The size of the largest object is half the address space, or
  PTRDIFF_MAX.  (This is way too permissive.)  */
@@ -1431,6 +1431,15 @@ check_access (GimpleOrTree exp, tree dstwrite,
}
 }
 
+  /* For functions that take string inputs and stop reading on encountering a
+ NULL, if remaining size in the source is non-zero, it is legitimate for
+ such functions to pass a larger size (that perhaps is the maximum object
+ size of all possible inputs), making the MAXREAD comparison noisy.  */
+  if (null_terminated
+  && pad && pad->mode == access_read_only
+  && pad->src.size_remaining () != 0)
+return true;
+
   /* Check the maximum length of the source sequence against the size
  of the destination object if known, or against the maximum size
  of an object.  */
@@ -1522,10 +1531,10 @@ static bool
 check_access (gimple *stmt, tree dstwrite,
  tree maxread, tree srcstr, tree dstsize,
  access_mode mode, const access_data *pad,
- range_query *rvals)
+ range_query *rvals, bool null_terminated = true)
 {
   return check_access (stmt, dstwrite, maxread, srcstr, dstsize,
-mode, pad, rvals);
+mode, pad, rvals, null_terminated);
 }
 
 bool
@@ -1534,7 +1543,7 @@ check_access (tree expr, tree dstwrite,
  access_mode mode, const access_data *pad /* = NULL */)
 {
   return check_access (expr, dstwrite, maxread, srcstr, dstsize,
-mode, pad, nullptr);
+mode, pad, nullptr, true);
 }
 
 /* Return true if STMT is a call to an allocation function.  Unless
@@ -2109,7 +2118,8 @@ private:
   void check_stxncpy (gcall *);
   void check_strncmp (gcall *);
   void check_memop_access (gimple *, tree, tree, tree);
-  void check_read_access (gimple *, tree, tree = NULL_TREE, int = 1);
+  void check_read_access (gimple *, tree, tree = NULL_TREE, int = 1,
+ bool = true);
 
   void maybe_check_dealloc_call (gcall *);
   void ma

[patch gcc13] middle-end/70090: Dynamic sizes for -fsanitize=object-size

2022-02-07 Thread Siddhesh Poyarekar
Use __builtin_dynamic_object_size to get object sizes for ubsan.

gcc/ChangeLog:

middle-end/70090
* ubsan.cc (ubsan_expand_objsize_ifn): Allow non-constant SIZE.
(instrument_object_size): Get dynamic object size expression.

gcc/testsuite/ChangeLog:

middle-end/70090
* gcc.dg/ubsan/object-size-dyn.c: New test.

Signed-off-by: Siddhesh Poyarekar 
---
Proposing for gcc13 since I reckoned this is not feasible for stage 4.

Tested with:
- ubsan bootstrap config on x86_64
- bootstrap build and test on x86_64
- non-bootstrap build and test with i686

 gcc/testsuite/gcc.dg/ubsan/object-size-dyn.c | 45 
 gcc/ubsan.cc | 13 +++---
 2 files changed, 52 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/ubsan/object-size-dyn.c

diff --git a/gcc/testsuite/gcc.dg/ubsan/object-size-dyn.c 
b/gcc/testsuite/gcc.dg/ubsan/object-size-dyn.c
new file mode 100644
index 000..0159f5b9820
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ubsan/object-size-dyn.c
@@ -0,0 +1,45 @@
+/* { dg-do run } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-O2" } } */
+/* { dg-options "-fsanitize=undefined" } */
+#include 
+
+int
+__attribute__ ((noinline))
+dyn (int size, int i)
+{
+  __builtin_printf ("dyn\n");
+  fflush (stdout);
+  int *alloc = __builtin_calloc (size, sizeof (int));
+  int ret = alloc[i];
+  __builtin_free (alloc);
+  return ret;
+}
+
+int
+__attribute__ ((noinline))
+off (int size, int i, int ret)
+{
+  char *mem = __builtin_alloca (size);
+  mem += size - 1;
+
+  return (int) mem[i] & ret;
+}
+
+int
+main (void)
+{
+  int ret = dyn (2, 2);
+
+  ret |= off (4, 4, 0);
+
+  return ret;
+}
+
+/* { dg-output "load of address \[^\n\r]* with insufficient space for an 
object of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\\^\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*load of address \[^\n\r]* with insufficient space for 
an object of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*note: pointer points here\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*\\^" } */
diff --git a/gcc/ubsan.cc b/gcc/ubsan.cc
index 5641d3cc3be..11dad4f1095 100644
--- a/gcc/ubsan.cc
+++ b/gcc/ubsan.cc
@@ -942,8 +942,8 @@ ubsan_expand_objsize_ifn (gimple_stmt_iterator *gsi)
   gimple *g;
 
   /* See if we can discard the check.  */
-  if (TREE_CODE (size) != INTEGER_CST
-  || integer_all_onesp (size))
+  if (TREE_CODE (size) == INTEGER_CST
+  && integer_all_onesp (size))
 /* Yes, __builtin_object_size couldn't determine the
object size.  */;
   else if (TREE_CODE (offset) == INTEGER_CST
@@ -2160,14 +2160,14 @@ instrument_object_size (gimple_stmt_iterator *gsi, tree 
t, bool is_lhs)
   if (decl_p)
 base_addr = build1 (ADDR_EXPR,
build_pointer_type (TREE_TYPE (base)), base);
-  if (compute_builtin_object_size (base_addr, 0, ))
+  if (compute_builtin_object_size (base_addr, OST_DYNAMIC, ))
 ;
   else if (optimize)
 {
   if (LOCATION_LOCUS (loc) == UNKNOWN_LOCATION)
loc = input_location;
-  /* Generate __builtin_object_size call.  */
-  sizet = builtin_decl_explicit (BUILT_IN_OBJECT_SIZE);
+  /* Generate __builtin_dynamic_object_size call.  */
+  sizet = builtin_decl_explicit (BUILT_IN_DYNAMIC_OBJECT_SIZE);
   sizet = build_call_expr_loc (loc, sizet, 2, base_addr,
   integer_zero_node);
   sizet = force_gimple_operand_gsi (gsi, sizet, false, NULL_TREE, true,
@@ -2219,7 +2219,8 @@ instrument_object_size (gimple_stmt_iterator *gsi, tree 
t, bool is_lhs)
}
 }
 
-  if (bos_stmt && gimple_call_builtin_p (bos_stmt, BUILT_IN_OBJECT_SIZE))
+  if (bos_stmt
+  && gimple_call_builtin_p (bos_stmt, BUILT_IN_DYNAMIC_OBJECT_SIZE))
 ubsan_create_edge (bos_stmt);
 
   /* We have to emit the check.  */
-- 
2.34.1



[wwwdocs] Document __builtin_dynamic_object_size addition for GCC 12

2022-01-27 Thread Siddhesh Poyarekar
Signed-off-by: Siddhesh Poyarekar 
---
 htdocs/gcc-12/changes.html | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/htdocs/gcc-12/changes.html b/htdocs/gcc-12/changes.html
index c69b301e..c6baee75 100644
--- a/htdocs/gcc-12/changes.html
+++ b/htdocs/gcc-12/changes.html
@@ -157,6 +157,8 @@ a work-in-progress.
   A new built-in function, __builtin_assoc_barrier, was added.
   It can be used to inhibit re-association of floating-point
   expressions.
+  Support for __builtin_dynamic_object_size compatible with
+  the clang language extension was added.
   New warnings:
 
   -Wbidi-chars warns about potentially misleading UTF-8
-- 
2.34.1



[PATCH] tree-optimization/104009: Conservative underflow estimate in object size

2022-01-13 Thread Siddhesh Poyarekar
Restrict negative offset computation only to dynamic object sizes, where
size expressions are accurate and not a maximum/minimum estimate and in
cases where negative offsets definitely mean an underflow, e.g. in
MEM_REF of the whole object with negative ofset in addr_object_size.

This ends up missing some cases where __builtin_object_size could have
come up with more precise results, so tests have been adjusted to
reflect that.

gcc/ChangeLog:

PR tree-optimization/104009
* tree-object-size.c (compute_builtin_object_size): Bail out on
negative offset.
(plus_stmt_object_size): Return maximum of wholesize and minimum
of 0 for negative offset.

gcc/testsuite/ChangeLog:

PR tree-optimization/104009
* gcc.dg/builtin-object-size-1.c (test10): New test.
* gcc.dg/builtin-object-size-3.c (test10): Likewise.
(test9): Expect zero size for negative offsets.
* gcc.dg/builtin-object-size-4.c (test8): Likewise.
* gcc.dg/builtin-object-size-5.c (test7): Drop test for
__builtin_object_size.

Signed-off-by: Siddhesh Poyarekar 
---
Testing:
- bootstrap build+test for x86_64
- build+test for i686
- bootstrap build --with-build-config=bootstrap-ubsan

 gcc/testsuite/gcc.dg/builtin-object-size-1.c | 27 
 gcc/testsuite/gcc.dg/builtin-object-size-3.c | 34 +---
 gcc/testsuite/gcc.dg/builtin-object-size-4.c |  6 ++--
 gcc/testsuite/gcc.dg/builtin-object-size-5.c |  2 ++
 gcc/tree-object-size.c   | 15 +++--
 5 files changed, 75 insertions(+), 9 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-1.c 
b/gcc/testsuite/gcc.dg/builtin-object-size-1.c
index 161f426ec0b..b772e2da9b9 100644
--- a/gcc/testsuite/gcc.dg/builtin-object-size-1.c
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-1.c
@@ -603,6 +603,32 @@ test9 (unsigned cond)
 #endif
 }
 
+void
+__attribute__ ((noinline))
+test10 (void)
+{
+  static char buf[255];
+  unsigned int i, len = sizeof (buf);
+  char *p = buf;
+
+  for (i = 0 ; i < sizeof (buf) ; i++)
+{
+  if (len < 2)
+   {
+#ifdef __builtin_object_size
+ if (__builtin_object_size (p - 3, 0) != sizeof (buf) - i + 3)
+   abort ();
+#else
+ if (__builtin_object_size (p - 3, 0) != sizeof (buf))
+   abort ();
+#endif
+ break;
+   }
+  p++;
+  len--;
+}
+}
+
 int
 main (void)
 {
@@ -617,5 +643,6 @@ main (void)
   test7 ();
   test8 ();
   test9 (1);
+  test10 ();
   exit (0);
 }
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-3.c 
b/gcc/testsuite/gcc.dg/builtin-object-size-3.c
index db31171a8bd..44a99189776 100644
--- a/gcc/testsuite/gcc.dg/builtin-object-size-3.c
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-3.c
@@ -581,7 +581,7 @@ test9 (unsigned cond)
   if (__builtin_object_size ([-4], 2) != (cond ? 6 : 10))
 abort ();
 #else
-  if (__builtin_object_size ([-4], 2) != 6)
+  if (__builtin_object_size ([-4], 2) != 0)
 abort ();
 #endif
 
@@ -592,7 +592,7 @@ test9 (unsigned cond)
   if (__builtin_object_size (p, 2) != ((cond ? 2 : 6) + cond))
 abort ();
 #else
-  if (__builtin_object_size (p, 2) != 2)
+  if (__builtin_object_size (p, 2) != 0)
 abort ();
 #endif
 
@@ -605,12 +605,37 @@ test9 (unsigned cond)
   != sizeof (y) - __builtin_offsetof (struct A, c) - 8 + cond)
 abort ();
 #else
-  if (__builtin_object_size (p, 2)
-  != sizeof (y) - __builtin_offsetof (struct A, c) - 8)
+  if (__builtin_object_size (p, 2) != 0)
 abort ();
 #endif
 }
 
+void
+__attribute__ ((noinline))
+test10 (void)
+{
+  static char buf[255];
+  unsigned int i, len = sizeof (buf);
+  char *p = buf;
+
+  for (i = 0 ; i < sizeof (buf) ; i++)
+{
+  if (len < 2)
+   {
+#ifdef __builtin_object_size
+ if (__builtin_object_size (p - 3, 2) != sizeof (buf) - i + 3)
+   abort ();
+#else
+ if (__builtin_object_size (p - 3, 2) != 0)
+   abort ();
+#endif
+ break;
+   }
+  p++;
+  len--;
+}
+}
+
 int
 main (void)
 {
@@ -625,5 +650,6 @@ main (void)
   test7 ();
   test8 ();
   test9 (1);
+  test10 ();
   exit (0);
 }
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-4.c 
b/gcc/testsuite/gcc.dg/builtin-object-size-4.c
index f644890dd14..b9fddfed036 100644
--- a/gcc/testsuite/gcc.dg/builtin-object-size-4.c
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-4.c
@@ -489,7 +489,7 @@ test8 (unsigned cond)
   if (__builtin_object_size ([-4], 3) != (cond ? 6 : 10))
 abort ();
 #else
-  if (__builtin_object_size ([-4], 3) != 6)
+  if (__builtin_object_size ([-4], 3) != 0)
 abort ();
 #endif
 
@@ -500,7 +500,7 @@ test8 (unsigned cond)
   if (__builtin_object_size (p, 3) != ((cond ? 2 : 6) + cond))
 abort ();
 #else
-  if (__builtin_object_size (p, 3) != 2)
+  if (__builtin_object_size (p, 3) != 0)
 abort ();
 #endif
 
@@ -512,7 +512,7 @@ test8 (unsigned cond)
   if (__builtin_object_size (p, 3) != size

Re: [PATCH] tree-optimization/pr103961: Never compute offset for -1 size

2022-01-11 Thread Siddhesh Poyarekar

On 11/01/2022 19:04, Jakub Jelinek wrote:

On Tue, Jan 11, 2022 at 06:40:44PM +0530, Siddhesh Poyarekar wrote:

Never try to compute size for offset when the object size is -1, which
is either unknown maximum or uninitialized minimum irrespective of the
osi->pass number.

gcc/ChangeLog:

PR tree-optimization/pr103961
* tree-object-size.c (plus_stmt_object_size): Always avoid
computing offset for -1 size.

gcc/testsuite/ChangeLog:

PR tree-optimization/pr103961
* gcc.dg/pr103961.c: New test case.


Ok.  Martin's executable testcase would work too but only if
it would be limited to targets with glibc with __sprintf_chk in or
it would need to be linked against -lssp, so I think it is fine as is.


Thanks I'll push this then.


+void
+cap_to_text (int c)
+{
+  char buf[1572];
+  char *p;
+  int n, t;
+  p = 20 + buf;
+  for (t = 8; t--; )
+{
+  for (n = 0; n < c; n++)
+   p += sprintf (p, "a,");
+  p--;
+  if (__builtin_object_size (p, 1) == 0)
+   abort ();
+}


Just curious, does your PR77608 patch change this such that __bos (p, 1)
is not ~(size_t)0 but 1572?
We don't know if c isn't 0, so can't count on p += sprintf (p, "a,");
actually incrementing the pointer (and unless we try to understand more
what exactly it is doing we'd need to also assume it could e.g. return -1,
and we aren't too smart about loops anyway, but if the PR77608 patch assumes
that variable bounds aren't out of bounds, then a pointer that started
as 20 + buf can be minimum buf + 0 and maximum buf + 1572.
Note, as __bos is trying to prevent exploiting UB, perhaps assuming the
pointer arithmetics or array refs aren't out of bounds isn't perfect, but
then I'd say a __bos (p, 1) == 1572 means bigger security than __bos (p, 1)
== -1 where we punt and don't check anything.


That's a good catch; the 77608 patch actually breaks this again, but for 
a different reason that the patch itself introduces.  The "safe" 
assumption of wholesize for p_4 is not safe enough because p_17 (which 
is p_4 - 1) is assumed to have an underflow, resulting in a zero size again.


I need to rethink the 77608 fix; it won't always be as simple as 
returning the wholesize.


Thanks,
Siddhesh


[PATCH] tree-optimization/pr103961: Never compute offset for -1 size

2022-01-11 Thread Siddhesh Poyarekar
Never try to compute size for offset when the object size is -1, which
is either unknown maximum or uninitialized minimum irrespective of the
osi->pass number.

gcc/ChangeLog:

PR tree-optimization/pr103961
* tree-object-size.c (plus_stmt_object_size): Always avoid
computing offset for -1 size.

gcc/testsuite/ChangeLog:

PR tree-optimization/pr103961
* gcc.dg/pr103961.c: New test case.

Co-authored-by: Jakub Jelinek 
Signed-off-by: Siddhesh Poyarekar 
---
Tested with i686 build+test, x86_64 bootstrap build+test and ubsan
bootstrap.

 gcc/testsuite/gcc.dg/pr103961.c | 30 ++
 gcc/tree-object-size.c  | 11 ---
 2 files changed, 34 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr103961.c

diff --git a/gcc/testsuite/gcc.dg/pr103961.c b/gcc/testsuite/gcc.dg/pr103961.c
new file mode 100644
index 000..2cd52884e3b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr103961.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+extern void abort ();
+
+extern inline __attribute__ ((__gnu_inline__)) int
+sprintf (char *restrict s, const char *restrict fmt, ...)
+{
+  return __builtin___sprintf_chk (s, 1, __builtin_object_size (s, 1),
+ fmt, __builtin_va_arg_pack ());
+}
+
+void
+cap_to_text (int c)
+{
+  char buf[1572];
+  char *p;
+  int n, t;
+  p = 20 + buf;
+  for (t = 8; t--; )
+{
+  for (n = 0; n < c; n++)
+   p += sprintf (p, "a,");
+  p--;
+  if (__builtin_object_size (p, 1) == 0)
+   abort ();
+}
+}
+
+/* { dg-final { scan-assembler-not "abort" } } */
diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c
index fbaf57a20f8..f7cc323591c 100644
--- a/gcc/tree-object-size.c
+++ b/gcc/tree-object-size.c
@@ -990,13 +990,10 @@ plus_stmt_object_size (struct object_size_info *osi, tree 
var, gimple *stmt)
  addr_object_size (osi, op0, object_size_type, , );
}
 
-  /* In the first pass, do not compute size for offset if either the
-maximum size is unknown or the minimum size is not initialized yet;
-the latter indicates a dependency loop and will be resolved in
-subsequent passes.  We attempt to compute offset for 0 minimum size
-too because a negative offset could be within bounds of WHOLESIZE,
-giving a non-zero result for VAR.  */
-  if (osi->pass != 0 || !size_unknown_p (bytes, 0))
+  /* size_for_offset doesn't make sense for -1 size, but it does for size 0
+since the wholesize could be non-zero and a negative offset could give
+a non-zero size.  */
+  if (!size_unknown_p (bytes, 0))
bytes = size_for_offset (bytes, op1, wholesize);
 }
   else
-- 
2.33.1



Re: [PATCH v6 1/4] tree-object-size: Support dynamic sizes in conditions

2022-01-11 Thread Siddhesh Poyarekar

On 11/01/2022 15:13, Jakub Jelinek wrote:

On Tue, Jan 11, 2022 at 02:27:47PM +0530, Siddhesh Poyarekar wrote:

Handle GIMPLE_PHI and conditionals specially for dynamic objects,
returning PHI/conditional expressions instead of just a MIN/MAX
estimate.

This makes the returned object size variable for loops and conditionals,
so tests need to be adjusted to look for precise size in some cases.
builtin-dynamic-object-size-5.c had to be modified to only look for
success in maximum object size case and skip over the minimum object
size tests because the result is no longer a compile time constant.

I also added some simple tests to exercise conditionals with dynamic
object sizes.


Ok, but IMO please fix PR103961 first before committing this patchset.



+1, I'm on it right now.

Thanks,
Siddhesh


[PATCH v6 3/4] tree-object-size: Handle GIMPLE_CALL

2022-01-11 Thread Siddhesh Poyarekar
Handle non-constant expressions in GIMPLE_CALL arguments.  Also handle
alloca.

gcc/ChangeLog:

* tree-object-size.c (alloc_object_size): Make and return
non-constant size expression.
(call_object_size): Return expression or unknown based on
whether dynamic object size is requested.

gcc/testsuite/ChangeLog:

* gcc.dg/builtin-dynamic-object-size-0.c: Add new tests.
* gcc.dg/builtin-object-size-1.c (test1)
[__builtin_object_size]: Alter expected result for dynamic
object size.
* gcc.dg/builtin-object-size-2.c (test1)
[__builtin_object_size]: Likewise.
* gcc.dg/builtin-object-size-3.c (test1)
[__builtin_object_size]: Likewise.
* gcc.dg/builtin-object-size-4.c (test1)
[__builtin_object_size]: Likewise.

Signed-off-by: Siddhesh Poyarekar 
---
 .../gcc.dg/builtin-dynamic-object-size-0.c| 269 +-
 gcc/testsuite/gcc.dg/builtin-object-size-1.c  |   7 +
 gcc/testsuite/gcc.dg/builtin-object-size-2.c  |  14 +
 gcc/testsuite/gcc.dg/builtin-object-size-3.c  |   7 +
 gcc/testsuite/gcc.dg/builtin-object-size-4.c  |  14 +
 gcc/tree-object-size.c|  22 +-
 6 files changed, 325 insertions(+), 8 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
index c89e2268943..930fd49cd16 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -4,6 +4,73 @@
 typedef __SIZE_TYPE__ size_t;
 #define abort __builtin_abort
 
+void *
+__attribute__ ((alloc_size (1)))
+__attribute__ ((__nothrow__ , __leaf__))
+__attribute__ ((noinline))
+alloc_func (size_t sz)
+{
+  return __builtin_malloc (sz);
+}
+
+void *
+__attribute__ ((alloc_size (1, 2)))
+__attribute__ ((__nothrow__ , __leaf__))
+__attribute__ ((noinline))
+calloc_func (size_t cnt, size_t sz)
+{
+  return __builtin_calloc (cnt, sz);
+}
+
+void *
+__attribute__ ((noinline))
+unknown_allocator (size_t cnt, size_t sz)
+{
+  return __builtin_calloc (cnt, sz);
+}
+
+size_t
+__attribute__ ((noinline))
+test_unknown (size_t cnt, size_t sz)
+{
+  void *ch = unknown_allocator (cnt, sz);
+  size_t ret = __builtin_dynamic_object_size (ch, 0);
+  __builtin_free (ch);
+  return ret;
+}
+
+/* Malloc-like allocator.  */
+
+size_t
+__attribute__ ((noinline))
+test_malloc (size_t sz)
+{
+  void *ch = alloc_func (sz);
+  size_t ret = __builtin_dynamic_object_size (ch, 0);
+  __builtin_free (ch);
+  return ret;
+}
+
+size_t
+__attribute__ ((noinline))
+test_builtin_malloc (size_t sz)
+{
+  void *ch = __builtin_malloc (sz);
+  size_t ret = __builtin_dynamic_object_size (ch, 0);
+  __builtin_free (ch);
+  return ret;
+}
+
+size_t
+__attribute__ ((noinline))
+test_builtin_malloc_cond (int cond)
+{
+  void *ch = __builtin_malloc (cond ? 32 : 64);
+  size_t ret = __builtin_dynamic_object_size (ch, 0);
+  __builtin_free (ch);
+  return ret;
+}
+
 size_t
 __attribute__ ((noinline))
 test_builtin_malloc_condphi (int cond)
@@ -21,6 +88,155 @@ test_builtin_malloc_condphi (int cond)
   return ret;
 }
 
+size_t
+__attribute__ ((noinline))
+test_builtin_malloc_condphi2 (int cond, size_t in)
+{
+  void *ch;
+
+  if (cond)
+ch = __builtin_malloc (in);
+  else
+ch = __builtin_malloc (64);
+
+  size_t ret = __builtin_dynamic_object_size (ch, 0);
+
+  __builtin_free (ch);
+  return ret;
+}
+
+size_t
+__attribute__ ((noinline))
+test_builtin_malloc_condphi3 (int cond, size_t in, size_t in2)
+{
+  void *ch;
+
+  if (cond)
+ch = __builtin_malloc (in);
+  else
+ch = __builtin_malloc (in2);
+
+  size_t ret = __builtin_dynamic_object_size (ch, 0);
+
+  __builtin_free (ch);
+  return ret;
+}
+
+size_t
+__attribute__ ((noinline))
+test_builtin_malloc_condphi4 (size_t sz, int cond)
+{
+  char *a = __builtin_malloc (sz);
+  char b[sz / 2];
+
+  size_t ret = __builtin_dynamic_object_size (cond ? b : (void *) , 0);
+  __builtin_free (a);
+  return ret;
+}
+
+size_t
+__attribute__ ((noinline))
+test_builtin_malloc_condphi5 (size_t sz, int cond, char *c)
+{
+  char *a = __builtin_malloc (sz);
+
+  size_t ret = __builtin_dynamic_object_size (cond ? c : (void *) , 0);
+  __builtin_free (a);
+  return ret;
+}
+
+/* Calloc-like allocator.  */
+
+size_t
+__attribute__ ((noinline))
+test_calloc (size_t cnt, size_t sz)
+{
+  void *ch = calloc_func (cnt, sz);
+  size_t ret = __builtin_dynamic_object_size (ch, 0);
+  __builtin_free (ch);
+  return ret;
+}
+
+size_t
+__attribute__ ((noinline))
+test_builtin_calloc (size_t cnt, size_t sz)
+{
+  void *ch = __builtin_calloc (cnt, sz);
+  size_t ret = __builtin_dynamic_object_size (ch, 0);
+  __builtin_free (ch);
+  return ret;
+}
+
+size_t
+__attribute__ ((noinline))
+test_builtin_calloc_cond (int cond1, int cond2)
+{
+  void *ch = __builtin_calloc (cond1 ? 32 : 64, cond2 ? 1024 : 16);
+  size_t ret = __builtin_dynamic_object_size (ch, 0);
+  __builtin_free (ch);
+  return ret

[PATCH v6 4/4] tree-object-size: Dynamic sizes for ADDR_EXPR

2022-01-11 Thread Siddhesh Poyarekar
Allow returning dynamic expressions from ADDR_EXPR for
__builtin_dynamic_object_size and also allow offsets to be dynamic.

gcc/ChangeLog:

* tree-object-size.c (size_valid_p): New function.
(size_for_offset): Remove OFFSET constness assertion.
(addr_object_size): Build dynamic expressions for object
sizes and use size_valid_p to decide if it is valid for the
given OBJECT_SIZE_TYPE.
(compute_builtin_object_size): Allow dynamic offsets when
computing size at O0.
(call_object_size): Call size_valid_p.
(plus_stmt_object_size): Allow non-constant offset and use
size_valid_p to decide if it is valid for the given
OBJECT_SIZE_TYPE.

gcc/testsuite/ChangeLog:

* gcc.dg/builtin-dynamic-object-size-0.c: Add new tests.
* gcc.dg/builtin-object-size-1.c (test1)
[__builtin_object_size]: Adjust expected output for dynamic
object sizes.
* gcc.dg/builtin-object-size-2.c (test1)
[__builtin_object_size]: Likewise.
* gcc.dg/builtin-object-size-3.c (test1)
[__builtin_object_size]: Likewise.
* gcc.dg/builtin-object-size-4.c (test1)
[__builtin_object_size]: Likewise.

Signed-off-by: Siddhesh Poyarekar 
---
 .../gcc.dg/builtin-dynamic-object-size-0.c| 156 ++
 gcc/testsuite/gcc.dg/builtin-object-size-1.c  |  30 +++-
 gcc/testsuite/gcc.dg/builtin-object-size-2.c  |  43 -
 gcc/testsuite/gcc.dg/builtin-object-size-3.c  |  25 ++-
 gcc/testsuite/gcc.dg/builtin-object-size-4.c  |  17 +-
 gcc/tree-object-size.c|  94 ++-
 6 files changed, 299 insertions(+), 66 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
index 930fd49cd16..dd8dc99a580 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -250,6 +250,79 @@ test_deploop (size_t sz, size_t cond)
   return __builtin_dynamic_object_size (bin, 0);
 }
 
+/* Address expressions.  */
+
+struct dynarray_struct
+{
+  long a;
+  char c[16];
+  int b;
+};
+
+size_t
+__attribute__ ((noinline))
+test_dynarray_struct (size_t sz, size_t off)
+{
+  struct dynarray_struct bin[sz];
+
+  return __builtin_dynamic_object_size ([off].c, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_dynarray_struct_subobj (size_t sz, size_t off)
+{
+  struct dynarray_struct bin[sz];
+
+  return __builtin_dynamic_object_size ([off].c[4], 1);
+}
+
+size_t
+__attribute__ ((noinline))
+test_dynarray_struct_subobj2 (size_t sz, size_t off, size_t *objsz)
+{
+  struct dynarray_struct2
+{
+  long a;
+  int b;
+  char c[sz];
+};
+
+  struct dynarray_struct2 bin;
+
+  *objsz = sizeof (bin);
+
+  return __builtin_dynamic_object_size ([off], 1);
+}
+
+size_t
+__attribute__ ((noinline))
+test_substring (size_t sz, size_t off)
+{
+  char str[sz];
+
+  return __builtin_dynamic_object_size ([off], 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_substring_ptrplus (size_t sz, size_t off)
+{
+  int str[sz];
+
+  return __builtin_dynamic_object_size (str + off, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_substring_ptrplus2 (size_t sz, size_t off, size_t off2)
+{
+  int str[sz];
+  int *ptr = [off];
+
+  return __builtin_dynamic_object_size (ptr + off2, 0);
+}
+
 size_t
 __attribute__ ((access (__read_write__, 1, 2)))
 __attribute__ ((noinline))
@@ -258,6 +331,14 @@ test_parmsz_simple (void *obj, size_t sz)
   return __builtin_dynamic_object_size (obj, 0);
 }
 
+size_t
+__attribute__ ((noinline))
+__attribute__ ((access (__read_write__, 1, 2)))
+test_parmsz (void *obj, size_t sz, size_t off)
+{
+  return __builtin_dynamic_object_size (obj + off, 0);
+}
+
 size_t
 __attribute__ ((access (__read_write__, 1, 2)))
 __attribute__ ((noinline))
@@ -266,6 +347,14 @@ test_parmsz_scaled (int *obj, size_t sz)
   return __builtin_dynamic_object_size (obj, 0);
 }
 
+size_t
+__attribute__ ((noinline))
+__attribute__ ((access (__read_write__, 1, 2)))
+test_parmsz_scaled_off (int *obj, size_t sz, size_t off)
+{
+  return __builtin_dynamic_object_size (obj + off, 0);
+}
+
 size_t
 __attribute__ ((access (__read_write__, 1, 3)))
 __attribute__ ((noinline))
@@ -274,6 +363,23 @@ test_parmsz_unknown (void *obj, void *unknown, size_t sz, 
int cond)
   return __builtin_dynamic_object_size (cond ? obj : unknown, 0);
 }
 
+size_t
+__attribute__ ((noinline))
+__attribute__ ((access (__read_write__, 1, 2)))
+test_loop (int *obj, size_t sz, size_t start, size_t end, int incr)
+{
+  int *ptr = obj + start;
+
+  for (int i = start; i != end; i = i + incr)
+{
+  ptr = ptr + incr;
+  if (__builtin_dynamic_object_size (ptr, 0) == 0)
+   return 0;
+}
+
+  return __builtin_dynamic_object_size (ptr, 0);
+}
+
 unsigned nfails = 0;
 
 #define FAIL() ({ \
@@ -333,6 +439,32 @@ main (int argc, char **argv)
 FAIL ();
   if (test_dynarray

[PATCH v6 1/4] tree-object-size: Support dynamic sizes in conditions

2022-01-11 Thread Siddhesh Poyarekar
Handle GIMPLE_PHI and conditionals specially for dynamic objects,
returning PHI/conditional expressions instead of just a MIN/MAX
estimate.

This makes the returned object size variable for loops and conditionals,
so tests need to be adjusted to look for precise size in some cases.
builtin-dynamic-object-size-5.c had to be modified to only look for
success in maximum object size case and skip over the minimum object
size tests because the result is no longer a compile time constant.

I also added some simple tests to exercise conditionals with dynamic
object sizes.

gcc/ChangeLog:

* builtins.c (fold_builtin_object_size): Adjust for dynamic size
expressions.
* tree-object-size.c: Include gimplify-me.h.
(struct object_size_info): New member UNKNOWNS.
(size_initval_p, size_usable_p, object_sizes_get_raw): New
functions.
(object_sizes_get): Return suitable gimple variable for
object size.
(bundle_sizes): New function.
(object_sizes_set): Use it and handle dynamic object size
expressions.
(object_sizes_set_temp): New function.
(size_for_offset): Adjust for dynamic size expressions.
(emit_phi_nodes, propagate_unknowns, gimplify_size_expressions):
New functions.
(compute_builtin_object_size): Call gimplify_size_expressions
for OST_DYNAMIC.
(dynamic_object_size): New function.
(cond_expr_object_size): Use it.
(phi_dynamic_object_size): New function.
(collect_object_sizes_for): Call it for OST_DYNAMIC.  Adjust to
accommodate dynamic object sizes.

gcc/testsuite/ChangeLog:

* gcc.dg/builtin-dynamic-object-size-0.c: New tests.
* gcc.dg/builtin-dynamic-object-size-10.c: Add comment.
* gcc.dg/builtin-dynamic-object-size-5-main.c: New file.
* gcc.dg/builtin-dynamic-object-size-5.c: Use it and change test
to dg-do run.
* gcc.dg/builtin-object-size-5.c [!N]: Define N.
(test1, test2, test3, test4) [__builtin_object_size]: Expect
exact result for __builtin_dynamic_object_size.
* gcc.dg/builtin-object-size-1.c [__builtin_object_size]: Expect
exact size expressions for __builtin_dynamic_object_size.
* gcc.dg/builtin-object-size-2.c [__builtin_object_size]:
Likewise.
* gcc.dg/builtin-object-size-3.c [__builtin_object_size]:
Likewise.
* gcc.dg/builtin-object-size-4.c [__builtin_object_size]:
Likewise.
* gcc.dg/builtin-object-size-5.c [__builtin_object_size]:
Likewise.

Signed-off-by: Siddhesh Poyarekar 
---
 gcc/builtins.c|   6 +-
 .../gcc.dg/builtin-dynamic-object-size-0.c|  58 ++
 .../gcc.dg/builtin-dynamic-object-size-10.c   |   2 +
 .../builtin-dynamic-object-size-5-main.c  |  32 ++
 .../gcc.dg/builtin-dynamic-object-size-5.c|   7 +-
 gcc/testsuite/gcc.dg/builtin-object-size-1.c  | 119 +++-
 gcc/testsuite/gcc.dg/builtin-object-size-2.c  |  92 
 gcc/testsuite/gcc.dg/builtin-object-size-3.c  | 121 
 gcc/testsuite/gcc.dg/builtin-object-size-4.c  |  78 +++
 gcc/testsuite/gcc.dg/builtin-object-size-5.c  |  22 +-
 gcc/tree-object-size.c| 521 +-
 11 files changed, 1022 insertions(+), 36 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
 create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5-main.c

diff --git a/gcc/builtins.c b/gcc/builtins.c
index 51d3635bd57..c780340ed32 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -10306,7 +10306,8 @@ fold_builtin_object_size (tree ptr, tree ost, enum 
built_in_function fcode)
   if (TREE_CODE (ptr) == ADDR_EXPR)
 {
   compute_builtin_object_size (ptr, object_size_type, );
-  if (int_fits_type_p (bytes, size_type_node))
+  if ((object_size_type & OST_DYNAMIC)
+ || int_fits_type_p (bytes, size_type_node))
return fold_convert (size_type_node, bytes);
 }
   else if (TREE_CODE (ptr) == SSA_NAME)
@@ -10315,7 +10316,8 @@ fold_builtin_object_size (tree ptr, tree ost, enum 
built_in_function fcode)
later.  Maybe subsequent passes will help determining
it.  */
   if (compute_builtin_object_size (ptr, object_size_type, )
- && int_fits_type_p (bytes, size_type_node))
+ && ((object_size_type & OST_DYNAMIC)
+ || int_fits_type_p (bytes, size_type_node)))
return fold_convert (size_type_node, bytes);
 }
 
diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
new file mode 100644
index 000..b1013e19fd0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -0,0 +1,58 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+typedef __SIZE_TYPE__ size_t;
+#define abort __builtin_abort
+
+size_t
+__attribute__ ((noinline))
+tes

[PATCH v6 2/4] tree-object-size: Handle function parameters

2022-01-11 Thread Siddhesh Poyarekar
Handle hints provided by __attribute__ ((access (...))) to compute
dynamic sizes for objects.

gcc/ChangeLog:

* tree-object-size.c: Include tree-dfa.h.
(parm_object_size): New function.
(collect_object_sizes_for): Call it.

gcc/testsuite/ChangeLog:

* gcc.dg/builtin-dynamic-object-size-0.c (test_parmsz_simple,
test_parmsz_scaled, test_parmsz_unknown): New functions.
(main): Call them.  Add new arguments argc and argv.

Signed-off-by: Siddhesh Poyarekar 
---
 .../gcc.dg/builtin-dynamic-object-size-0.c| 35 +++-
 gcc/tree-object-size.c| 54 ++-
 2 files changed, 87 insertions(+), 2 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
index b1013e19fd0..c89e2268943 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -34,6 +34,30 @@ test_deploop (size_t sz, size_t cond)
   return __builtin_dynamic_object_size (bin, 0);
 }
 
+size_t
+__attribute__ ((access (__read_write__, 1, 2)))
+__attribute__ ((noinline))
+test_parmsz_simple (void *obj, size_t sz)
+{
+  return __builtin_dynamic_object_size (obj, 0);
+}
+
+size_t
+__attribute__ ((access (__read_write__, 1, 2)))
+__attribute__ ((noinline))
+test_parmsz_scaled (int *obj, size_t sz)
+{
+  return __builtin_dynamic_object_size (obj, 0);
+}
+
+size_t
+__attribute__ ((access (__read_write__, 1, 3)))
+__attribute__ ((noinline))
+test_parmsz_unknown (void *obj, void *unknown, size_t sz, int cond)
+{
+  return __builtin_dynamic_object_size (cond ? obj : unknown, 0);
+}
+
 unsigned nfails = 0;
 
 #define FAIL() ({ \
@@ -42,7 +66,7 @@ unsigned nfails = 0;
 })
 
 int
-main ()
+main (int argc, char **argv)
 {
   if (test_builtin_malloc_condphi (1) != 32)
 FAIL ();
@@ -50,6 +74,15 @@ main ()
 FAIL ();
   if (test_deploop (128, 129) != 32)
 FAIL ();
+  if (test_parmsz_simple (argv[0], __builtin_strlen (argv[0]) + 1)
+  != __builtin_strlen (argv[0]) + 1)
+FAIL ();
+  int arr[42];
+  if (test_parmsz_scaled (arr, 42) != sizeof (arr))
+FAIL ();
+  if (test_parmsz_unknown (argv[0], argv[0], __builtin_strlen (argv[0]) + 1, 0)
+  != -1)
+FAIL ();
 
   if (nfails > 0)
 __builtin_abort ();
diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c
index 775792b4419..47e1c27bfd3 100644
--- a/gcc/tree-object-size.c
+++ b/gcc/tree-object-size.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-fold.h"
 #include "gimple-iterator.h"
 #include "tree-cfg.h"
+#include "tree-dfa.h"
 #include "stringpool.h"
 #include "attribs.h"
 #include "builtins.h"
@@ -1443,6 +1444,57 @@ cond_expr_object_size (struct object_size_info *osi, 
tree var, gimple *stmt)
   return reexamine;
 }
 
+/* Find size of an object passed as a parameter to the function.  */
+
+static void
+parm_object_size (struct object_size_info *osi, tree var)
+{
+  int object_size_type = osi->object_size_type;
+  tree parm = SSA_NAME_VAR (var);
+
+  if (!(object_size_type & OST_DYNAMIC) || !POINTER_TYPE_P (TREE_TYPE (parm)))
+{
+  expr_object_size (osi, var, parm);
+  return;
+}
+
+  /* Look for access attribute.  */
+  rdwr_map rdwr_idx;
+
+  tree fndecl = cfun->decl;
+  const attr_access *access = get_parm_access (rdwr_idx, parm, fndecl);
+  tree typesize = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (parm)));
+  tree sz = NULL_TREE;
+
+  if (access && access->sizarg != UINT_MAX)
+{
+  tree fnargs = DECL_ARGUMENTS (fndecl);
+  tree arg = NULL_TREE;
+  unsigned argpos = 0;
+
+  /* Walk through the parameters to pick the size parameter and safely
+scale it by the type size.  */
+  for (arg = fnargs; arg; arg = TREE_CHAIN (arg), ++argpos)
+   {
+ if (argpos == access->sizarg && INTEGRAL_TYPE_P (TREE_TYPE (arg)))
+   {
+ sz = get_or_create_ssa_default_def (cfun, arg);
+ if (sz != NULL_TREE)
+   {
+ sz = fold_convert (sizetype, sz);
+ if (typesize)
+   sz = size_binop (MULT_EXPR, sz, typesize);
+   }
+ break;
+   }
+   }
+}
+  if (!sz)
+sz = size_unknown (object_size_type);
+
+  object_sizes_set (osi, SSA_NAME_VERSION (var), sz, sz);
+}
+
 /* Compute an object size expression for VAR, which is the result of a PHI
node.  */
 
@@ -1620,7 +1672,7 @@ collect_object_sizes_for (struct object_size_info *osi, 
tree var)
 case GIMPLE_NOP:
   if (SSA_NAME_VAR (var)
  && TREE_CODE (SSA_NAME_VAR (var)) == PARM_DECL)
-   expr_object_size (osi, var, SSA_NAME_VAR (var));
+   parm_object_size (osi, var);
   else
/* Uninitialized SSA names point nowhere.  */
unknown_object_size (osi, var);
-- 
2.33.1



[PATCH v6 0/4] __builtin_dynamic_object_size

2022-01-11 Thread Siddhesh Poyarekar
This patchset enhances the __builtin_dynamic_object_size builtin to
produce dynamic expressions for object sizes to improve coverage of
_FORTIFY_SOURCE.

Testing:


This series has been tested with build and test for i686, bootstrap with
ubsan and bootstrap+test with x86_64.

Additional testing plans (i.e. I've already started to do some of this):

- Build packages to compare values returned by __builtin_object_size
  with the older pass and this new one.  Also compare with
  __builtin_dynamic_object_size.

- Expand the list of packages to get more coverage metrics.

- Explore performance impact on applications on building with
  _FORTIFY_SOURCE=3.

Changes from v5:
- Address review comments
- Add a couple more tests for object sizes of pointers passed as
  parameters.

Siddhesh Poyarekar (4):
  tree-object-size: Support dynamic sizes in conditions
  tree-object-size: Handle function parameters
  tree-object-size: Handle GIMPLE_CALL
  tree-object-size: Dynamic sizes for ADDR_EXPR

 gcc/builtins.c|   6 +-
 .../gcc.dg/builtin-dynamic-object-size-0.c| 514 +
 .../gcc.dg/builtin-dynamic-object-size-10.c   |   2 +
 .../builtin-dynamic-object-size-5-main.c  |  32 +
 .../gcc.dg/builtin-dynamic-object-size-5.c|   7 +-
 gcc/testsuite/gcc.dg/builtin-object-size-1.c  | 154 +++-
 gcc/testsuite/gcc.dg/builtin-object-size-2.c  | 133 
 gcc/testsuite/gcc.dg/builtin-object-size-3.c  | 151 
 gcc/testsuite/gcc.dg/builtin-object-size-4.c  |  93 +++
 gcc/testsuite/gcc.dg/builtin-object-size-5.c  |  22 +-
 gcc/tree-object-size.c| 689 +++---
 11 files changed, 1712 insertions(+), 91 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
 create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5-main.c

-- 
2.33.1



Re: [PATCH v5 2/4] tree-object-size: Handle function parameters

2022-01-10 Thread Siddhesh Poyarekar

On 10/01/2022 16:20, Jakub Jelinek wrote:

On Sat, Dec 18, 2021 at 06:05:09PM +0530, Siddhesh Poyarekar wrote:

@@ -1440,6 +1441,53 @@ cond_expr_object_size (struct object_size_info *osi, 
tree var, gimple *stmt)
return reexamine;
  }
  
+/* Find size of an object passed as a parameter to the function.  */

+
+static void
+parm_object_size (struct object_size_info *osi, tree var)
+{
+  int object_size_type = osi->object_size_type;
+  tree parm = SSA_NAME_VAR (var);
+
+  if (!(object_size_type & OST_DYNAMIC) || !POINTER_TYPE_P (TREE_TYPE (parm)))
+expr_object_size (osi, var, parm);


This looks very suspicious.  Didn't you mean { expr_object_size (...); return; 
} here?
Because the code below e.g. certainly assumes OST_DYNAMIC and that TREE_TYPE 
(parm)
is a pointer type (otherwise TREE_TYPE (TREE_TYPE (...) wouldn't work.


Indeed, fixed.




+
+  /* Look for access attribute.  */
+  rdwr_map rdwr_idx;
+
+  tree fndecl = cfun->decl;
+  const attr_access *access = get_parm_access (rdwr_idx, parm, fndecl);
+  tree typesize = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (parm)));
+  tree sz = NULL_TREE;
+
+  if (access && access->sizarg != UINT_MAX)


Perhaps && typesize here?  It makes no sense to e.g. create ssa default def
when you aren't going to use it in any way.


The typesize is only for scaling; the result of 
get_or_create_ssa_default_def should get returned unscaled if it is 
non-NULL and typesize is NULL; the latter happens when the type is void *:


  sz = get_or_create_ssa_default_def (cfun, arg);
  if (sz != NULL_TREE)
{
  sz = fold_convert (sizetype, sz);
  if (typesize)
sz = size_binop (MULT_EXPR, sz, typesize);
}
}




+{
+  tree fnargs = DECL_ARGUMENTS (fndecl);
+  tree arg = NULL_TREE;
+  unsigned argpos = 0;
+
+  /* Walk through the parameters to pick the size parameter and safely
+scale it by the type size.  */
+  for (arg = fnargs; argpos != access->sizarg && arg;
+  arg = TREE_CHAIN (arg), ++argpos);


Instead of a loop with empty body wouldn't it be better to
do the work in that for loop?
I.e. take argpos != access->sizarg && from the condition,
replace arg != NULL_TREE with that argpos == access->sizarg
and add a break;?


Fixed.




+
+  if (arg != NULL_TREE && INTEGRAL_TYPE_P (TREE_TYPE (arg)))
+   {
+ sz = get_or_create_ssa_default_def (cfun, arg);


Also, I must say I'm little bit worried about this
get_or_create_ssa_default_def call.  If the SSA_NAME doesn't exist,
so you create it and then attempt to use it but in the end don't
because e.g. some PHI's another argument was unknown etc., will
that SSA_NAME be released through release_ssa_name?
I think GIMPLE is fairly unhappy if there are SSA_NAMEs created and not
released that don't appear in the IL anywhere.


AFAICT, set_ss_default_def ends up creating a definition for the new 
SSA_NAME it creates, so it does end up in the IR and in case of object 
size computation failure, it just ends up being a dead store.  I've 
added a test to verify this:


size_t
__attribute__ ((access (__read_write__, 1, 3)))
__attribute__ ((noinline))
test_parmsz_unknown (void *obj, void *unknown, size_t sz, int cond)
{
  return __builtin_dynamic_object_size (cond ? obj : unknown, 0);
}

which works as expected and returns -1.

Thanks,
Siddhesh


Re: [PATCH v5 1/4] tree-object-size: Support dynamic sizes in conditions

2022-01-10 Thread Siddhesh Poyarekar

On 10/01/2022 16:07, Jakub Jelinek wrote:

You test the above with both possibilities.


+  if (test_builtin_calloc_condphi (128, 1, 0) == 128)
+FAIL ();


But not this one, why?  Also, it would be better to have
a != ... test rather than ==, if it is the VLA, then 128 * sizeof (struct { int 
a; char b; })
?


I think I'll move the test_builtin_calloc_condphi test into the 
GIMPLE_CALL patch since that's where it becomes fully functional.


Thanks,
Siddhesh


[PATCH] middle-end/77608: object size estimate with variable offsets

2022-01-05 Thread Siddhesh Poyarekar
This partially fixes middle-end/77608 by making __builtin_object_size
return the whole object size instead of bailing out in case the offset
in the object is variable and the maximum estimate is requested.

gcc/ChangeLog:

PR middle-end/77608
* tree-object-size.c (size_for_offset): New object_size_type
parameter.  Return known whole size if offset is not constant.
(addr_object_size, compute_builtin_object_size): Adjust.
(plus_stmt_object_size): Defer constness check of offset to
size_for_offset.

gcc/testsuite/ChangeLog:

PR middle-end/77608
* gcc.dg/builtin-object-size-1.c (test1): Add tests.
* gcc.dg/builtin-object-size-2.c (test1): Likewise.

Signed-off-by: Siddhesh Poyarekar 
---

This applies on top of the __builtin_dynamic_object_size patchset.  It
should be possible to process trees with side effects and fully fix
77608, but I'll do that later since it would be a bit more involved.

Tested with a full bootstrap on x86_64 and ubsan bootstrap.

 gcc/testsuite/gcc.dg/builtin-object-size-1.c | 16 
 gcc/testsuite/gcc.dg/builtin-object-size-2.c | 37 ++
 gcc/tree-object-size.c   | 77 +++-
 3 files changed, 97 insertions(+), 33 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-1.c 
b/gcc/testsuite/gcc.dg/builtin-object-size-1.c
index 161f426ec0b..0f92713b141 100644
--- a/gcc/testsuite/gcc.dg/builtin-object-size-1.c
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-1.c
@@ -22,6 +22,8 @@ struct A
 extern char exta[];
 extern char extb[30];
 extern struct A zerol[0];
+int off = 2;
+int off2 = -3;
 
 void
 __attribute__ ((noinline))
@@ -162,6 +164,13 @@ test1 (void *q, int x)
   if (__builtin_object_size ([5], 0) != sizeof (extb) - 5)
 abort ();
 #ifdef __builtin_object_size
+  if (__builtin_object_size ([off], 0) != sizeof (extb) - off)
+abort ();
+  r = [5];
+  if (__builtin_object_size (r + off, 0) != sizeof (extb) - 5 - off)
+abort ();
+  if (__builtin_object_size (r + off2, 0) != sizeof (extb) - 5 - off2)
+abort ();
   if (__builtin_object_size (var, 0) != x + 10)
 abort ();
   if (__builtin_object_size (var + 10, 0) != x)
@@ -169,6 +178,13 @@ test1 (void *q, int x)
   if (__builtin_object_size ([5], 0) != x + 5)
 abort ();
 #else
+  if (__builtin_object_size ([off], 0) != sizeof (extb))
+abort ();
+  r = [5];
+  if (__builtin_object_size (r + off, 0) != sizeof (extb))
+abort ();
+  if (__builtin_object_size (r + off2, 0) != sizeof (extb))
+abort ();
   if (__builtin_object_size (var, 0) != (size_t) -1)
 abort ();
   if (__builtin_object_size (var + 10, 0) != (size_t) -1)
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-2.c 
b/gcc/testsuite/gcc.dg/builtin-object-size-2.c
index 2729538da17..62a5af1384a 100644
--- a/gcc/testsuite/gcc.dg/builtin-object-size-2.c
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-2.c
@@ -24,6 +24,9 @@ extern char extb[30];
 extern struct A extc[];
 struct A zerol[0];
 
+int off = 3;
+int off2 = -3;
+
 void
 __attribute__ ((noinline))
 test1 (void *q, int x)
@@ -151,6 +154,23 @@ test1 (void *q, int x)
 abort ();
   if (__builtin_object_size ([5], 1) != sizeof (extb) - 5)
 abort ();
+#ifdef __builtin_object_size
+  if (__builtin_object_size ([off], 1) != sizeof (extb) - off)
+abort ();
+  r = [5];
+  if (__builtin_object_size (r + off, 1) != sizeof (extb) - 5 - off)
+abort ();
+  if (__builtin_object_size (r + off2, 0) != sizeof (extb) - 5 - off2)
+abort ();
+#else
+  if (__builtin_object_size ([off], 1) != sizeof (extb))
+abort ();
+  r = [5];
+  if (__builtin_object_size (r + off, 1) != sizeof (extb))
+abort ();
+  if (__builtin_object_size (r + off2, 0) != sizeof (extb))
+abort ();
+#endif
   if (__builtin_object_size (extc, 1) != (size_t) -1)
 abort ();
   if (__builtin_object_size (extc + 10, 1) != (size_t) -1)
@@ -200,6 +220,23 @@ test1 (void *q, int x)
 abort ();
   if (__builtin_object_size ([7].c[7], 1) != sizeof (vara[0].c) - 7)
 abort ();
+#ifdef __builtin_object_size
+  if (__builtin_object_size ([5].c[off], 1) != sizeof (vara[0].c) - off)
+abort ();
+  r = [1].c[5];
+  if (__builtin_object_size (r + off, 1) != sizeof (vara[0].c) - 5 - off)
+abort ();
+  if (__builtin_object_size (r + off2, 1) != sizeof (vara[0].c) - 5 - off2)
+abort ();
+#else
+  if (__builtin_object_size ([5].c[off], 1) != sizeof (vara[0].c))
+abort ();
+  r = [1].c[5];
+  if (__builtin_object_size (r + off, 1) != sizeof (vara[0].c))
+abort ();
+  if (__builtin_object_size (r + off2, 1) != sizeof (vara[0].c))
+abort ();
+#endif
   if (__builtin_object_size (zerol, 1) != 0)
 abort ();
   if (__builtin_object_size (, 1) != 0)
diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c
index bf45adc7307..b5cb637f207 100644
--- a/gcc/tree-object-size.c
+++ b/gcc/tree-object-size.c
@@ -347,10 +347,21 @@ init_offset_limit (void)
be positive and hence

[PING][PATCH v5 0/4] __builtin_dynamic_object_size

2022-01-03 Thread Siddhesh Poyarekar

Happy new year, and ping!

On 12/18/21 18:05, Siddhesh Poyarekar wrote:

This patchset enhances the __builtin_dynamic_object_size builtin to
produce dynamic expressions for object sizes to improve coverage of
_FORTIFY_SOURCE.

Testing:


This series has been tested with build and test for i686, bootstrap with
ubsan and full bootstrap and test with x86_64.  I also tested the
toolchain with a glibc build and testsuite run for x86_64 and i686 with
_FORTIFY_SOURCE=3 enabled for gcc12.

Additional testing plans (i.e. I've already started to do some of this):

- Build packages to compare values returned by __builtin_object_size
   with the older pass and this new one.  Also compare with
   __builtin_dynamic_object_size.

- Expand the list of packages to get more coverage metrics.

- Explore performance impact on applications on building with
   _FORTIFY_SOURCE=3.

Siddhesh Poyarekar (4):
   tree-object-size: Support dynamic sizes in conditions
   tree-object-size: Handle function parameters
   tree-object-size: Handle GIMPLE_CALL
   tree-object-size: Dynamic sizes for ADDR_EXPR

  gcc/builtins.c|   6 +-
  .../gcc.dg/builtin-dynamic-object-size-0.c| 495 +
  .../gcc.dg/builtin-dynamic-object-size-10.c   |   2 +
  .../builtin-dynamic-object-size-5-main.c  |  32 +
  .../gcc.dg/builtin-dynamic-object-size-5.c|   7 +-
  gcc/testsuite/gcc.dg/builtin-object-size-1.c  | 154 +++-
  gcc/testsuite/gcc.dg/builtin-object-size-2.c  | 133 
  gcc/testsuite/gcc.dg/builtin-object-size-3.c  | 151 
  gcc/testsuite/gcc.dg/builtin-object-size-4.c  |  93 +++
  gcc/testsuite/gcc.dg/builtin-object-size-5.c  |  22 +-
  gcc/tree-object-size.c| 670 +++---
  11 files changed, 1677 insertions(+), 88 deletions(-)
  create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
  create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5-main.c





[PATCH v5 4/4] tree-object-size: Dynamic sizes for ADDR_EXPR

2021-12-18 Thread Siddhesh Poyarekar
Allow returning dynamic expressions from ADDR_EXPR for
__builtin_dynamic_object_size and also allow offsets to be dynamic.

gcc/ChangeLog:

* tree-object-size.c (size_valid_p): New function.
(size_for_offset): Remove OFFSET constness assertion.
(addr_object_size): Build dynamic expressions for object
sizes and use size_valid_p to decide if it is valid for the
given OBJECT_SIZE_TYPE.
(compute_builtin_object_size): Allow dynamic offsets when
computing size at O0.
(call_object_size): Call size_valid_p.
(plus_stmt_object_size): Allow non-constant offset and use
size_valid_p to decide if it is valid for the given
OBJECT_SIZE_TYPE.

gcc/testsuite/ChangeLog:

* gcc.dg/builtin-dynamic-object-size-0.c: Add new tests.
* gcc.dg/builtin-object-size-1.c (test1)
[__builtin_object_size]: Adjust expected output for dynamic
object sizes.
* gcc.dg/builtin-object-size-2.c (test1)
[__builtin_object_size]: Likewise.
* gcc.dg/builtin-object-size-3.c (test1)
[__builtin_object_size]: Likewise.
* gcc.dg/builtin-object-size-4.c (test1)
[__builtin_object_size]: Likewise.

Signed-off-by: Siddhesh Poyarekar 
---
 .../gcc.dg/builtin-dynamic-object-size-0.c| 158 ++
 gcc/testsuite/gcc.dg/builtin-object-size-1.c  |  30 +++-
 gcc/testsuite/gcc.dg/builtin-object-size-2.c  |  43 -
 gcc/testsuite/gcc.dg/builtin-object-size-3.c  |  25 ++-
 gcc/testsuite/gcc.dg/builtin-object-size-4.c  |  17 +-
 gcc/tree-object-size.c|  91 +-
 6 files changed, 300 insertions(+), 64 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
index d67cf4a3c07..ba710f47f1c 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -250,6 +250,79 @@ test_deploop (size_t sz, size_t cond)
   return __builtin_dynamic_object_size (bin, 0);
 }
 
+/* Address expressions.  */
+
+struct dynarray_struct
+{
+  long a;
+  char c[16];
+  int b;
+};
+
+size_t
+__attribute__ ((noinline))
+test_dynarray_struct (size_t sz, size_t off)
+{
+  struct dynarray_struct bin[sz];
+
+  return __builtin_dynamic_object_size ([off].c, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_dynarray_struct_subobj (size_t sz, size_t off)
+{
+  struct dynarray_struct bin[sz];
+
+  return __builtin_dynamic_object_size ([off].c[4], 1);
+}
+
+size_t
+__attribute__ ((noinline))
+test_dynarray_struct_subobj2 (size_t sz, size_t off, size_t *objsz)
+{
+  struct dynarray_struct2
+{
+  long a;
+  int b;
+  char c[sz];
+};
+
+  struct dynarray_struct2 bin;
+
+  *objsz = sizeof (bin);
+
+  return __builtin_dynamic_object_size ([off], 1);
+}
+
+size_t
+__attribute__ ((noinline))
+test_substring (size_t sz, size_t off)
+{
+  char str[sz];
+
+  return __builtin_dynamic_object_size ([off], 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_substring_ptrplus (size_t sz, size_t off)
+{
+  int str[sz];
+
+  return __builtin_dynamic_object_size (str + off, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_substring_ptrplus2 (size_t sz, size_t off, size_t off2)
+{
+  int str[sz];
+  int *ptr = [off];
+
+  return __builtin_dynamic_object_size (ptr + off2, 0);
+}
+
 size_t
 __attribute__ ((access (__read_write__, 1, 2)))
 __attribute__ ((noinline))
@@ -258,6 +331,40 @@ test_parmsz_simple (void *obj, size_t sz)
   return __builtin_dynamic_object_size (obj, 0);
 }
 
+size_t
+__attribute__ ((noinline))
+__attribute__ ((access (__read_write__, 1, 2)))
+test_parmsz (void *obj, size_t sz, size_t off)
+{
+  return __builtin_dynamic_object_size (obj + off, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+__attribute__ ((access (__read_write__, 1, 2)))
+test_parmsz_scale (int *obj, size_t sz, size_t off)
+{
+  return __builtin_dynamic_object_size (obj + off, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+__attribute__ ((access (__read_write__, 1, 2)))
+test_loop (int *obj, size_t sz, size_t start, size_t end, int incr)
+{
+  int *ptr = obj + start;
+
+  for (int i = start; i != end; i = i + incr)
+{
+  ptr = ptr + incr;
+  if (__builtin_dynamic_object_size (ptr, 0) == 0)
+   return 0;
+}
+
+  return __builtin_dynamic_object_size (ptr, 0);
+}
+
+
 unsigned nfails = 0;
 
 #define FAIL() ({ \
@@ -318,6 +425,31 @@ main (int argc, char **argv)
 FAIL ();
   if (test_dynarray (__builtin_strlen (argv[0])) != __builtin_strlen (argv[0]))
 FAIL ();
+  if (test_dynarray_struct (42, 4) !=
+  ((42 - 4) * sizeof (struct dynarray_struct)
+   - __builtin_offsetof (struct dynarray_struct, c)))
+FAIL ();
+  if (test_dynarray_struct (42, 48) != 0)
+FAIL ();
+  if (test_substring (128, 4) != 128 - 4)
+FAIL ();
+  if (test_substring (128, 142) != 0)
+FAIL ();
+  if (test_dynarray_struct_subobj (42, 4) != 16 - 4

[PATCH v5 3/4] tree-object-size: Handle GIMPLE_CALL

2021-12-18 Thread Siddhesh Poyarekar
Handle non-constant expressions in GIMPLE_CALL arguments.  Also handle
alloca.

gcc/ChangeLog:

* tree-object-size.c (alloc_object_size): Make and return
non-constant size expression.
(call_object_size): Return expression or unknown based on
whether dynamic object size is requested.

gcc/testsuite/ChangeLog:

* gcc.dg/builtin-dynamic-object-size-0.c: Add new tests.
* gcc.dg/builtin-object-size-1.c (test1)
[__builtin_object_size]: Alter expected result for dynamic
object size.
* gcc.dg/builtin-object-size-2.c (test1)
[__builtin_object_size]: Likewise.
* gcc.dg/builtin-object-size-3.c (test1)
[__builtin_object_size]: Likewise.
* gcc.dg/builtin-object-size-4.c (test1)
[__builtin_object_size]: Likewise.

Signed-off-by: Siddhesh Poyarekar 
---
Changes since v4:
- Free allocations in tests.

 .../gcc.dg/builtin-dynamic-object-size-0.c| 251 +-
 gcc/testsuite/gcc.dg/builtin-object-size-1.c  |   7 +
 gcc/testsuite/gcc.dg/builtin-object-size-2.c  |  14 +
 gcc/testsuite/gcc.dg/builtin-object-size-3.c  |   7 +
 gcc/testsuite/gcc.dg/builtin-object-size-4.c  |  14 +
 gcc/tree-object-size.c|  22 +-
 6 files changed, 307 insertions(+), 8 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
index 7616ffa4cf0..d67cf4a3c07 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -4,6 +4,73 @@
 typedef __SIZE_TYPE__ size_t;
 #define abort __builtin_abort
 
+void *
+__attribute__ ((alloc_size (1)))
+__attribute__ ((__nothrow__ , __leaf__))
+__attribute__ ((noinline))
+alloc_func (size_t sz)
+{
+  return __builtin_malloc (sz);
+}
+
+void *
+__attribute__ ((alloc_size (1, 2)))
+__attribute__ ((__nothrow__ , __leaf__))
+__attribute__ ((noinline))
+calloc_func (size_t cnt, size_t sz)
+{
+  return __builtin_calloc (cnt, sz);
+}
+
+void *
+__attribute__ ((noinline))
+unknown_allocator (size_t cnt, size_t sz)
+{
+  return __builtin_calloc (cnt, sz);
+}
+
+size_t
+__attribute__ ((noinline))
+test_unknown (size_t cnt, size_t sz)
+{
+  void *ch = unknown_allocator (cnt, sz);
+  size_t ret = __builtin_dynamic_object_size (ch, 0);
+  __builtin_free (ch);
+  return ret;
+}
+
+/* Malloc-like allocator.  */
+
+size_t
+__attribute__ ((noinline))
+test_malloc (size_t sz)
+{
+  void *ch = alloc_func (sz);
+  size_t ret = __builtin_dynamic_object_size (ch, 0);
+  __builtin_free (ch);
+  return ret;
+}
+
+size_t
+__attribute__ ((noinline))
+test_builtin_malloc (size_t sz)
+{
+  void *ch = __builtin_malloc (sz);
+  size_t ret = __builtin_dynamic_object_size (ch, 0);
+  __builtin_free (ch);
+  return ret;
+}
+
+size_t
+__attribute__ ((noinline))
+test_builtin_malloc_cond (int cond)
+{
+  void *ch = __builtin_malloc (cond ? 32 : 64);
+  size_t ret = __builtin_dynamic_object_size (ch, 0);
+  __builtin_free (ch);
+  return ret;
+}
+
 size_t
 __attribute__ ((noinline))
 test_builtin_malloc_condphi (int cond)
@@ -21,6 +88,95 @@ test_builtin_malloc_condphi (int cond)
   return ret;
 }
 
+size_t
+__attribute__ ((noinline))
+test_builtin_malloc_condphi2 (int cond, size_t in)
+{
+  void *ch;
+
+  if (cond)
+ch = __builtin_malloc (in);
+  else
+ch = __builtin_malloc (64);
+
+  size_t ret = __builtin_dynamic_object_size (ch, 0);
+
+  __builtin_free (ch);
+  return ret;
+}
+
+size_t
+__attribute__ ((noinline))
+test_builtin_malloc_condphi3 (int cond, size_t in, size_t in2)
+{
+  void *ch;
+
+  if (cond)
+ch = __builtin_malloc (in);
+  else
+ch = __builtin_malloc (in2);
+
+  size_t ret = __builtin_dynamic_object_size (ch, 0);
+
+  __builtin_free (ch);
+  return ret;
+}
+
+size_t
+__attribute__ ((noinline))
+test_builtin_malloc_condphi4 (size_t sz, int cond)
+{
+  char *a = __builtin_malloc (sz);
+  char b[sz / 2];
+
+  size_t ret = __builtin_dynamic_object_size (cond ? b : (void *) , 0);
+  __builtin_free (a);
+  return ret;
+}
+
+size_t
+__attribute__ ((noinline))
+test_builtin_malloc_condphi5 (size_t sz, int cond, char *c)
+{
+  char *a = __builtin_malloc (sz);
+
+  size_t ret = __builtin_dynamic_object_size (cond ? c : (void *) , 0);
+  __builtin_free (a);
+  return ret;
+}
+
+/* Calloc-like allocator.  */
+
+size_t
+__attribute__ ((noinline))
+test_calloc (size_t cnt, size_t sz)
+{
+  void *ch = calloc_func (cnt, sz);
+  size_t ret = __builtin_dynamic_object_size (ch, 0);
+  __builtin_free (ch);
+  return ret;
+}
+
+size_t
+__attribute__ ((noinline))
+test_builtin_calloc (size_t cnt, size_t sz)
+{
+  void *ch = __builtin_calloc (cnt, sz);
+  size_t ret = __builtin_dynamic_object_size (ch, 0);
+  __builtin_free (ch);
+  return ret;
+}
+
+size_t
+__attribute__ ((noinline))
+test_builtin_calloc_cond (int cond1, int cond2)
+{
+  void *ch = __builtin_calloc (cond1 ? 32 : 64, cond2 ? 1024 : 16);
+  size_t ret = __builtin_dynamic_object_size

[PATCH v5 1/4] tree-object-size: Support dynamic sizes in conditions

2021-12-18 Thread Siddhesh Poyarekar
Handle GIMPLE_PHI and conditionals specially for dynamic objects,
returning PHI/conditional expressions instead of just a MIN/MAX
estimate.

This makes the returned object size variable for loops and conditionals,
so tests need to be adjusted to look for precise size in some cases.
builtin-dynamic-object-size-5.c had to be modified to only look for
success in maximum object size case and skip over the minimum object
size tests because the result is no longer a compile time constant.

I also added some simple tests to exercise conditionals with dynamic
object sizes.

gcc/ChangeLog:

* builtins.c (fold_builtin_object_size): Adjust for dynamic size
expressions.
* tree-object-size.c: Include gimplify-me.h.
(struct object_size_info): New member UNKNOWNS.
(size_initval_p, size_usable_p, object_sizes_get_raw): New
functions.
(object_sizes_get): Return suitable gimple variable for
object size.
(bundle_sizes): New function.
(object_sizes_set): Use it and handle dynamic object size
expressions.
(object_sizes_set_temp): New function.
(size_for_offset): Adjust for dynamic size expressions.
(emit_phi_nodes, propagate_unknowns, gimplify_size_expressions):
New functions.
(compute_builtin_object_size): Call gimplify_size_expressions
for OST_DYNAMIC.
(dynamic_object_size): New function.
(cond_expr_object_size): Use it.
(phi_dynamic_object_size): New function.
(collect_object_sizes_for): Call it for OST_DYNAMIC.  Adjust to
accommodate dynamic object sizes.

gcc/testsuite/ChangeLog:

* gcc.dg/builtin-dynamic-object-size-0.c: New tests.
* gcc.dg/builtin-dynamic-object-size-10.c: Add comment.
* gcc.dg/builtin-dynamic-object-size-5-main.c: New file.
* gcc.dg/builtin-dynamic-object-size-5.c: Use it and change test
to dg-do run.
* gcc.dg/builtin-object-size-5.c [!N]: Define N.
(test1, test2, test3, test4) [__builtin_object_size]: Expect
exact result for __builtin_dynamic_object_size.
* gcc.dg/builtin-object-size-1.c [__builtin_object_size]: Expect
exact size expressions for __builtin_dynamic_object_size.
* gcc.dg/builtin-object-size-2.c [__builtin_object_size]:
Likewise.
* gcc.dg/builtin-object-size-3.c [__builtin_object_size]:
Likewise.
* gcc.dg/builtin-object-size-4.c [__builtin_object_size]:
Likewise.
* gcc.dg/builtin-object-size-5.c [__builtin_object_size]:
Likewise.

Signed-off-by: Siddhesh Poyarekar 
---
Changes since v4:

- Propagate sameness of size and wholesize through PHI nodes whenever
  possible.  Check and avoid emitting wholesize if it is the same as
  size.
- Bail out and punt to __builtin_object_size if PHI node has any complex
  edges.  Use insert_seq_on_edge to emit size PHI node edge values.
- Free allocations in tests.

 gcc/builtins.c|   6 +-
 .../gcc.dg/builtin-dynamic-object-size-0.c|  77 +++
 .../gcc.dg/builtin-dynamic-object-size-10.c   |   2 +
 .../builtin-dynamic-object-size-5-main.c  |  32 ++
 .../gcc.dg/builtin-dynamic-object-size-5.c|   7 +-
 gcc/testsuite/gcc.dg/builtin-object-size-1.c  | 119 +++-
 gcc/testsuite/gcc.dg/builtin-object-size-2.c  |  92 
 gcc/testsuite/gcc.dg/builtin-object-size-3.c  | 121 +
 gcc/testsuite/gcc.dg/builtin-object-size-4.c  |  78 +++
 gcc/testsuite/gcc.dg/builtin-object-size-5.c  |  22 +-
 gcc/tree-object-size.c| 509 +-
 11 files changed, 1030 insertions(+), 35 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
 create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5-main.c

diff --git a/gcc/builtins.c b/gcc/builtins.c
index 00f6c5552bf..01c24f42540 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -10285,7 +10285,8 @@ fold_builtin_object_size (tree ptr, tree ost, enum 
built_in_function fcode)
   if (TREE_CODE (ptr) == ADDR_EXPR)
 {
   compute_builtin_object_size (ptr, object_size_type, );
-  if (int_fits_type_p (bytes, size_type_node))
+  if ((object_size_type & OST_DYNAMIC)
+ || int_fits_type_p (bytes, size_type_node))
return fold_convert (size_type_node, bytes);
 }
   else if (TREE_CODE (ptr) == SSA_NAME)
@@ -10294,7 +10295,8 @@ fold_builtin_object_size (tree ptr, tree ost, enum 
built_in_function fcode)
later.  Maybe subsequent passes will help determining
it.  */
   if (compute_builtin_object_size (ptr, object_size_type, )
- && int_fits_type_p (bytes, size_type_node))
+ && ((object_size_type & OST_DYNAMIC)
+ || int_fits_type_p (bytes, size_type_node)))
return fold_convert (size_type_node, bytes);
 }
 
diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/bui

[PATCH v5 2/4] tree-object-size: Handle function parameters

2021-12-18 Thread Siddhesh Poyarekar
Handle hints provided by __attribute__ ((access (...))) to compute
dynamic sizes for objects.

gcc/ChangeLog:

* tree-object-size.c: Include tree-dfa.h.
(parm_object_size): New function.
(collect_object_sizes_for): Call it.

gcc/testsuite/ChangeLog:

* gcc.dg/builtin-dynamic-object-size-0.c (test_parmsz_simple):
New function.
(main): Call it.

Signed-off-by: Siddhesh Poyarekar 
---
 .../gcc.dg/builtin-dynamic-object-size-0.c| 11 
 gcc/tree-object-size.c| 50 ++-
 2 files changed, 60 insertions(+), 1 deletion(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
index 81588cb28a6..7616ffa4cf0 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -51,6 +51,14 @@ test_deploop (size_t sz, size_t cond)
   return __builtin_dynamic_object_size (bin, 0);
 }
 
+size_t
+__attribute__ ((access (__read_write__, 1, 2)))
+__attribute__ ((noinline))
+test_parmsz_simple (void *obj, size_t sz)
+{
+  return __builtin_dynamic_object_size (obj, 0);
+}
+
 unsigned nfails = 0;
 
 #define FAIL() ({ \
@@ -69,6 +77,9 @@ main (int argc, char **argv)
 FAIL ();
   if (test_deploop (128, 129) != 32)
 FAIL ();
+  if (test_parmsz_simple (argv[0], __builtin_strlen (argv[0]) + 1)
+  != __builtin_strlen (argv[0]) + 1)
+FAIL ();
 
   if (nfails > 0)
 __builtin_abort ();
diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c
index 95cb44d9c7e..bf33ac93b93 100644
--- a/gcc/tree-object-size.c
+++ b/gcc/tree-object-size.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-fold.h"
 #include "gimple-iterator.h"
 #include "tree-cfg.h"
+#include "tree-dfa.h"
 #include "stringpool.h"
 #include "attribs.h"
 #include "builtins.h"
@@ -1440,6 +1441,53 @@ cond_expr_object_size (struct object_size_info *osi, 
tree var, gimple *stmt)
   return reexamine;
 }
 
+/* Find size of an object passed as a parameter to the function.  */
+
+static void
+parm_object_size (struct object_size_info *osi, tree var)
+{
+  int object_size_type = osi->object_size_type;
+  tree parm = SSA_NAME_VAR (var);
+
+  if (!(object_size_type & OST_DYNAMIC) || !POINTER_TYPE_P (TREE_TYPE (parm)))
+expr_object_size (osi, var, parm);
+
+  /* Look for access attribute.  */
+  rdwr_map rdwr_idx;
+
+  tree fndecl = cfun->decl;
+  const attr_access *access = get_parm_access (rdwr_idx, parm, fndecl);
+  tree typesize = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (parm)));
+  tree sz = NULL_TREE;
+
+  if (access && access->sizarg != UINT_MAX)
+{
+  tree fnargs = DECL_ARGUMENTS (fndecl);
+  tree arg = NULL_TREE;
+  unsigned argpos = 0;
+
+  /* Walk through the parameters to pick the size parameter and safely
+scale it by the type size.  */
+  for (arg = fnargs; argpos != access->sizarg && arg;
+  arg = TREE_CHAIN (arg), ++argpos);
+
+  if (arg != NULL_TREE && INTEGRAL_TYPE_P (TREE_TYPE (arg)))
+   {
+ sz = get_or_create_ssa_default_def (cfun, arg);
+ if (sz != NULL_TREE)
+   {
+ sz = fold_convert (sizetype, sz);
+ if (typesize)
+   sz = size_binop (MULT_EXPR, sz, typesize);
+   }
+   }
+}
+  if (!sz)
+sz = size_unknown (object_size_type);
+
+  object_sizes_set (osi, SSA_NAME_VERSION (var), sz, sz);
+}
+
 /* Compute an object size expression for VAR, which is the result of a PHI
node.  */
 
@@ -1610,7 +1658,7 @@ collect_object_sizes_for (struct object_size_info *osi, 
tree var)
 case GIMPLE_NOP:
   if (SSA_NAME_VAR (var)
  && TREE_CODE (SSA_NAME_VAR (var)) == PARM_DECL)
-   expr_object_size (osi, var, SSA_NAME_VAR (var));
+   parm_object_size (osi, var);
   else
/* Uninitialized SSA names point nowhere.  */
unknown_object_size (osi, var);
-- 
2.31.1



[PATCH v5 0/4] __builtin_dynamic_object_size

2021-12-18 Thread Siddhesh Poyarekar
This patchset enhances the __builtin_dynamic_object_size builtin to
produce dynamic expressions for object sizes to improve coverage of
_FORTIFY_SOURCE.

Testing:


This series has been tested with build and test for i686, bootstrap with
ubsan and full bootstrap and test with x86_64.  I also tested the
toolchain with a glibc build and testsuite run for x86_64 and i686 with
_FORTIFY_SOURCE=3 enabled for gcc12.

Additional testing plans (i.e. I've already started to do some of this):

- Build packages to compare values returned by __builtin_object_size
  with the older pass and this new one.  Also compare with
  __builtin_dynamic_object_size.

- Expand the list of packages to get more coverage metrics.

- Explore performance impact on applications on building with
  _FORTIFY_SOURCE=3.

Siddhesh Poyarekar (4):
  tree-object-size: Support dynamic sizes in conditions
  tree-object-size: Handle function parameters
  tree-object-size: Handle GIMPLE_CALL
  tree-object-size: Dynamic sizes for ADDR_EXPR

 gcc/builtins.c|   6 +-
 .../gcc.dg/builtin-dynamic-object-size-0.c| 495 +
 .../gcc.dg/builtin-dynamic-object-size-10.c   |   2 +
 .../builtin-dynamic-object-size-5-main.c  |  32 +
 .../gcc.dg/builtin-dynamic-object-size-5.c|   7 +-
 gcc/testsuite/gcc.dg/builtin-object-size-1.c  | 154 +++-
 gcc/testsuite/gcc.dg/builtin-object-size-2.c  | 133 
 gcc/testsuite/gcc.dg/builtin-object-size-3.c  | 151 
 gcc/testsuite/gcc.dg/builtin-object-size-4.c  |  93 +++
 gcc/testsuite/gcc.dg/builtin-object-size-5.c  |  22 +-
 gcc/tree-object-size.c| 670 +++---
 11 files changed, 1677 insertions(+), 88 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
 create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5-main.c

-- 
2.31.1



[PATCH v3] tree-optimization/103759: Use sizetype everywhere for object sizes

2021-12-17 Thread Siddhesh Poyarekar
Since all computations in tree-object-size are now done in sizetype and
not HOST_WIDE_INT, comparisons with HOST_WIDE_INT based unknown and
initval would be incorrect.  Instead, use the sizetype trees directly to
generate and evaluate initval and unknown size values.

gcc/ChangeLog:

PR tree-optimization/103759
* tree-object-size (unknown, initval): Remove functions.
(size_unknown, size_initval, size_unknown_p): Operate directly
on trees.

Signed-off-by: Siddhesh Poyarekar 
---
Tested a full bootstrap on x86_64, config=ubsan-bootstrap and i686.

Changes from v2:
- Operate directly on trees as per Jakub's suggestion.

 gcc/tree-object-size.c | 27 ++-
 1 file changed, 6 insertions(+), 21 deletions(-)

diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c
index 71f6b747d05..ee9ea1bfbfd 100644
--- a/gcc/tree-object-size.c
+++ b/gcc/tree-object-size.c
@@ -83,30 +83,13 @@ static bitmap computed[OST_END];
 /* Maximum value of offset we consider to be addition.  */
 static unsigned HOST_WIDE_INT offset_limit;
 
-/* Initial value of object sizes; zero for maximum and SIZE_MAX for minimum
-   object size.  */
-
-static inline unsigned HOST_WIDE_INT
-initval (int object_size_type)
-{
-  return (object_size_type & OST_MINIMUM) ? HOST_WIDE_INT_M1U : 0;
-}
-
-/* Unknown object size value; it's the opposite of initval.  */
-
-static inline unsigned HOST_WIDE_INT
-unknown (int object_size_type)
-{
-  return ~initval (object_size_type);
-}
-
 /* Return true if VAL is represents an unknown size for OBJECT_SIZE_TYPE.  */
 
 static inline bool
 size_unknown_p (tree val, int object_size_type)
 {
-  return (tree_fits_uhwi_p (val)
- && tree_to_uhwi (val) == unknown (object_size_type));
+  return ((object_size_type & OST_MINIMUM)
+ ? integer_zerop (val) : integer_all_onesp (val));
 }
 
 /* Return a tree with initial value for OBJECT_SIZE_TYPE.  */
@@ -114,7 +97,8 @@ size_unknown_p (tree val, int object_size_type)
 static inline tree
 size_initval (int object_size_type)
 {
-  return size_int (initval (object_size_type));
+  return ((object_size_type & OST_MINIMUM)
+ ? TYPE_MAX_VALUE (sizetype) : size_zero_node);
 }
 
 /* Return a tree with unknown value for OBJECT_SIZE_TYPE.  */
@@ -122,7 +106,8 @@ size_initval (int object_size_type)
 static inline tree
 size_unknown (int object_size_type)
 {
-  return size_int (unknown (object_size_type));
+  return ((object_size_type & OST_MINIMUM)
+ ? size_zero_node : TYPE_MAX_VALUE (sizetype));
 }
 
 /* Grow object_sizes[OBJECT_SIZE_TYPE] to num_ssa_names.  */
-- 
2.31.1



[PATCH v2] tree-optimization/103759: Truncate unknown to sizetype on compare

2021-12-17 Thread Siddhesh Poyarekar
Since all computations in tree-object-size are now done in sizetype and
not HOST_WIDE_INT, comparisons after conversion to HOST_WIDE_INT would
be incorrect.  Instead, truncate unknown (object_size_type) to sizetype
to compare with the computed size to evaluate if it is unknown.

gcc/ChangeLog:

PR tree-optimization/103759
* tree-object-size (unknown, initval): Change to arrays.  Adjust
all uses.
(init_limits): Rename from init_offset_limit.  Initialize
UNKNOWN and INITVAL.  Adjust all uses.

Signed-off-by: Siddhesh Poyarekar 
---
Changes from v1:
Alternative approach that doesn't result in unnecessary construction of
trees.

 gcc/tree-object-size.c | 36 +---
 1 file changed, 17 insertions(+), 19 deletions(-)

diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c
index 71f6b747d05..fc5f82e7c36 100644
--- a/gcc/tree-object-size.c
+++ b/gcc/tree-object-size.c
@@ -64,7 +64,7 @@ static void expr_object_size (struct object_size_info *, 
tree, tree);
 static bool merge_object_sizes (struct object_size_info *, tree, tree);
 static bool plus_stmt_object_size (struct object_size_info *, tree, gimple *);
 static bool cond_expr_object_size (struct object_size_info *, tree, gimple *);
-static void init_offset_limit (void);
+static void init_limits (void);
 static void check_for_plus_in_loops (struct object_size_info *, tree);
 static void check_for_plus_in_loops_1 (struct object_size_info *, tree,
   unsigned int);
@@ -85,20 +85,10 @@ static unsigned HOST_WIDE_INT offset_limit;
 
 /* Initial value of object sizes; zero for maximum and SIZE_MAX for minimum
object size.  */
-
-static inline unsigned HOST_WIDE_INT
-initval (int object_size_type)
-{
-  return (object_size_type & OST_MINIMUM) ? HOST_WIDE_INT_M1U : 0;
-}
+static unsigned HOST_WIDE_INT initval[OST_END];
 
 /* Unknown object size value; it's the opposite of initval.  */
-
-static inline unsigned HOST_WIDE_INT
-unknown (int object_size_type)
-{
-  return ~initval (object_size_type);
-}
+static unsigned HOST_WIDE_INT unknown[OST_END];
 
 /* Return true if VAL is represents an unknown size for OBJECT_SIZE_TYPE.  */
 
@@ -106,7 +96,7 @@ static inline bool
 size_unknown_p (tree val, int object_size_type)
 {
   return (tree_fits_uhwi_p (val)
- && tree_to_uhwi (val) == unknown (object_size_type));
+ && tree_to_uhwi (val) == unknown[object_size_type]);
 }
 
 /* Return a tree with initial value for OBJECT_SIZE_TYPE.  */
@@ -114,7 +104,7 @@ size_unknown_p (tree val, int object_size_type)
 static inline tree
 size_initval (int object_size_type)
 {
-  return size_int (initval (object_size_type));
+  return size_int (initval[object_size_type]);
 }
 
 /* Return a tree with unknown value for OBJECT_SIZE_TYPE.  */
@@ -122,7 +112,7 @@ size_initval (int object_size_type)
 static inline tree
 size_unknown (int object_size_type)
 {
-  return size_int (unknown (object_size_type));
+  return size_int (unknown[object_size_type]);
 }
 
 /* Grow object_sizes[OBJECT_SIZE_TYPE] to num_ssa_names.  */
@@ -202,13 +192,21 @@ object_sizes_set (struct object_size_info *osi, unsigned 
varno, tree val,
 
 /* Initialize OFFSET_LIMIT variable.  */
 static void
-init_offset_limit (void)
+init_limits (void)
 {
   if (tree_fits_uhwi_p (TYPE_MAX_VALUE (sizetype)))
 offset_limit = tree_to_uhwi (TYPE_MAX_VALUE (sizetype));
   else
 offset_limit = -1;
   offset_limit /= 2;
+
+  for (int i = 0; i < OST_END; i++)
+{
+  if (i & OST_MINIMUM)
+   initval[i] = tree_to_uhwi (size_int (HOST_WIDE_INT_M1U));
+  else
+   unknown[i] = tree_to_uhwi (size_int (HOST_WIDE_INT_M1U));
+}
 }
 
 /* Bytes at end of the object with SZ from offset OFFSET.  If WHOLESIZE is not
@@ -705,7 +703,7 @@ compute_builtin_object_size (tree ptr, int object_size_type,
   *psize = size_unknown (object_size_type);
 
   if (! offset_limit)
-init_offset_limit ();
+init_limits ();
 
   if (TREE_CODE (ptr) == ADDR_EXPR)
 return addr_object_size (NULL, ptr, object_size_type, psize);
@@ -1374,7 +1372,7 @@ init_object_sizes (void)
   computed[object_size_type] = BITMAP_ALLOC (NULL);
 }
 
-  init_offset_limit ();
+  init_limits ();
 }
 
 
-- 
2.31.1



[PATCH] tree-optimization/103759: Truncate unknown to sizetype on compare

2021-12-17 Thread Siddhesh Poyarekar
Since all computations in tree-object-size are now done in sizetype and
not HOST_WIDE_INT, comparisons after conversion to HOST_WIDE_INT would
be incorrect.  Instead, truncate unknown (object_size_type) to sizetype
to compare with the computed size to evaluate if it is unknown.

gcc/ChangeLog:

PR tree-optimization/103759
* tree-object-size (size_unknown_p): Construct a size_unknown
and compare with VAL.

Signed-off-by: Siddhesh Poyarekar 
---
This fixes all the 32-bit torture failures on i686, tested with
configuration:

--enable-clocale=gnu --with-system-zlib --enable-shared --enable-cet
--with-demangler-in-ld --enable-libmpx i686-linux --with-fpmath=sse
--enable-languages=c,c++,lto --disable-bootstrap

and also with x86_64 to ensure I didn't regress there.  I have a full
bootstrap build and test run in progress.

 gcc/tree-object-size.c | 18 +-
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c
index 71f6b747d05..71c7935cb07 100644
--- a/gcc/tree-object-size.c
+++ b/gcc/tree-object-size.c
@@ -100,15 +100,6 @@ unknown (int object_size_type)
   return ~initval (object_size_type);
 }
 
-/* Return true if VAL is represents an unknown size for OBJECT_SIZE_TYPE.  */
-
-static inline bool
-size_unknown_p (tree val, int object_size_type)
-{
-  return (tree_fits_uhwi_p (val)
- && tree_to_uhwi (val) == unknown (object_size_type));
-}
-
 /* Return a tree with initial value for OBJECT_SIZE_TYPE.  */
 
 static inline tree
@@ -125,6 +116,15 @@ size_unknown (int object_size_type)
   return size_int (unknown (object_size_type));
 }
 
+/* Return true if VAL is represents an unknown size for OBJECT_SIZE_TYPE.  */
+
+static inline bool
+size_unknown_p (tree val, int object_size_type)
+{
+  return (TREE_CODE (val) == INTEGER_CST
+ && tree_int_cst_compare (val, size_unknown (object_size_type)));
+}
+
 /* Grow object_sizes[OBJECT_SIZE_TYPE] to num_ssa_names.  */
 
 static inline void
-- 
2.31.1



Re: [PATCH v4 0/6] __builtin_dynamic_object_size

2021-12-17 Thread Siddhesh Poyarekar

On 12/18/21 00:59, David Edelsohn wrote:

Siddhesh,

This patch series seems to have caused testsuite regressions for
memcpy-chk, etc. in 32 bit mode (i386, x86-64 -m32 and -mx32, AIX 32
bit).

I have opened PR 103759.


Thanks, I've assigned it to myself.  I'll take a look.

Siddhesh


Re: [PATCH v4 1/6] tree-object-size: Use trees and support negative offsets

2021-12-16 Thread Siddhesh Poyarekar

On 12/16/21 21:19, Jakub Jelinek wrote:

Yes, but please fix up formatting, wholeval should go below old_wholeval.
Though, perhaps it would be better to:

   if (tree_int_cst_compare (oldval, val))
 return true;

   gcc_checking_assert (tree_int_cst_compare (old_wholeval, wholeval) == 0);
   return false;

Ok with that change.

Jakub



I thought about this some more and I think I'm wrong in assuming that 
wholeval won't change in subsequent passes; my tests show I'm wrong too. 
 I'm now testing with the condition fixed up to:


  return (tree_int_cst_compare (oldval, val) != 0
  || tree_int_cst_compare (old_wholeval, wholeval) != 0);

as you had suggested earlier and will push it if it passes bootstrap and 
a clean testsuite run.  I'm doing a ubsan bootstrap too because it's 
been quite useful in catching corner cases in __bos before.


Thanks,
Siddhesh


<    1   2   3   4   >