public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Qing Zhao <qing.zhao@oracle.com>
To: Richard Biener <richard.guenther@gmail.com>
Cc: "jakub@redhat.com" <jakub@redhat.com>,
	gcc Patches <gcc-patches@gcc.gnu.org>
Subject: Re: HELP: Questions on unshare_expr
Date: Mon, 22 Jan 2024 16:54:29 +0000	[thread overview]
Message-ID: <C6A49742-05BD-4329-AAD4-5C22D9199C08@oracle.com> (raw)
In-Reply-To: <4AFCA347-8A7C-4A96-B76A-33529E20D546@oracle.com>

One update, last Friday, I merged all my patches for counted-by support 
(including the Patch to workaround the LTO issue)  with the latest trunk, bootstrapped
 and run the testing, everything is good.

Today, when I disabled the Patch that workaround the LTO issue, surprisingly, I cannot
repeat the LTO issue anymore with the latest trunk + my counted-by support patches.
I.e., without the LTO workaround, everything works just fine with the latest gcc.

I suspected that some change in the latest GCC “fixed” (or hide) the issue. 

Qing

> On Jan 22, 2024, at 9:52 AM, Qing Zhao <qing.zhao@oracle.com> wrote:
> 
> 
> 
>> On Jan 22, 2024, at 2:40 AM, Richard Biener <richard.guenther@gmail.com> wrote:
>> 
>> On Fri, Jan 19, 2024 at 5:26 PM Qing Zhao <qing.zhao@oracle.com> wrote:
>>> 
>>> 
>>> 
>>>> On Jan 19, 2024, at 4:30 AM, Richard Biener <richard.guenther@gmail.com> wrote:
>>>> 
>>>> On Thu, Jan 18, 2024 at 3:46 PM Qing Zhao <qing.zhao@oracle.com> wrote:
>>>>> 
>>>>> 
>>>>> 
>>>>>> On Jan 17, 2024, at 1:43 AM, Richard Biener <richard.guenther@gmail.com> wrote:
>>>>>> 
>>>>>> On Wed, Jan 17, 2024 at 7:42 AM Richard Biener
>>>>>> <richard.guenther@gmail.com> wrote:
>>>>>>> 
>>>>>>> On Tue, Jan 16, 2024 at 9:26 PM Qing Zhao <qing.zhao@oracle.com> wrote:
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>>> On Jan 15, 2024, at 4:31 AM, Richard Biener <richard.guenther@gmail.com> wrote:
>>>>>>>>> 
>>>>>>>>>> All my questions for unshare_expr relate to a  LTO bug that I currently stuck with
>>>>>>>>>> when using .ACCESS_WITH_SIZE in bound sanitizer (only with -flto, without -flto, no issue):
>>>>>>>>>> 
>>>>>>>>>> [opc@qinzhao-aarch64-ol8 gcc]$ sh t
>>>>>>>>>> during IPA pass: modref
>>>>>>>>>> t.c:20:1: internal compiler error: tree code ‘ssa_name’ is not supported in LTO streams
>>>>>>>>>> 0x14c3993 lto_write_tree
>>>>>>>>>>    ../../latest-gcc-write/gcc/lto-streamer-out.cc:561
>>>>>>>>>> 0x14c3aeb lto_output_tree_1
>>>>>>>>>> 
>>>>>>>>>> And the value of the tree node that triggered the ICE is:
>>>>>>>>>> (gdb) call debug_tree(expr)
>>>>>>>>>> <ssa_name 0xfffff5761e60 type <error_mark 0xfffff56c0e58>
>>>>>>>>>> nothrow
>>>>>>>>>> def_stmt
>>>>>>>>>> version:13 in-free-list>
>>>>>>>>>> 
>>>>>>>>>> Is there any good way to debug LTO bug?
>>>>>>>>> 
>>>>>>>>> This happens usually when you have a VLA type and its type fields are not
>>>>>>>>> properly gimplified which usually happens because the frontend fails to
>>>>>>>>> insert a gimplification point for it (a DECL_EXPR).
>>>>>>>> 
>>>>>>>> I found an old gcc bug
>>>>>>>> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97172
>>>>>>>> ICE: tree code ‘ssa_name’ is not supported in LTO streams since r11-3303-g6450f07388f9fe57
>>>>>>>> 
>>>>>>>> Which is very similar to the bug I am having right now.
>>>>>>>> 
>>>>>>>> After further study, I suspect that the issue I am having right now with the LTO streaming also
>>>>>>>> relate to “unshare_expr”, “save_expr”, and the combination of these two, I suspect that
>>>>>>>> the current gcc cannot handle the combination of these two correctly for my case.
>>>>>>>> 
>>>>>>>> My testing case is:
>>>>>>>> 
>>>>>>>> #include <stdlib.h>
>>>>>>>> void __attribute__((__noinline__)) setup_and_test_vla (int n1, int n2, int m)
>>>>>>>> {
>>>>>>>> struct foo {
>>>>>>>>    int n;
>>>>>>>>    int p[][n2][n1] __attribute__((counted_by(n)));
>>>>>>>> } *f;
>>>>>>>> 
>>>>>>>> f = (struct foo *) malloc (sizeof(struct foo) + m*sizeof(int[n2][n1]));
>>>>>>>> f->n = m;
>>>>>>>> f->p[m][n2][n1]=1;
>>>>>>>> return;
>>>>>>>> }
>>>>>>>> 
>>>>>>>> int main(int argc, char *argv[])
>>>>>>>> {
>>>>>>>> setup_and_test_vla (10, 11, 20);
>>>>>>>> return 0;
>>>>>>>> }
>>>>>>>> 
>>>>>>>> Failed with
>>>>>>>> my_gcc -Os -fsanitize=bounds -flto
>>>>>>>> 
>>>>>>>> If changing either n1 or n2 to a constant, the testing passed.
>>>>>>>> If deleting -flto, the testing passed too.
>>>>>>>> 
>>>>>>>> I double checked my code per the suggestions provided by you and Jakub in this
>>>>>>>> email thread, and I think the code should be fine.
>>>>>>>> 
>>>>>>>> The code is following:
>>>>>>>> 
>>>>>>>> =====
>>>>>>>> 504 /* Instrument array bounds for INDIRECT_REFs whose pointers are
>>>>>>>> 505    POINTER_PLUS_EXPRs of calls to .ACCESS_WITH_SIZE. We create special
>>>>>>>> 506    builtins that gets expanded in the sanopt pass, and make an array
>>>>>>>> 507    dimension of it.  ARRAY is the pointer to the base of the array,
>>>>>>>> 508    which is a call to .ACCESS_WITH_SIZE, *OFFSET is the offset to the
>>>>>>>> 509    beginning of array.
>>>>>>>> 510    Return NULL_TREE if no instrumentation is emitted.  */
>>>>>>>> 511
>>>>>>>> 512 tree
>>>>>>>> 513 ubsan_instrument_bounds_indirect_ref (location_t loc, tree array, tree *offset)
>>>>>>>> 514 {
>>>>>>>> 515   if (!is_access_with_size_p (array))
>>>>>>>> 516     return NULL_TREE;
>>>>>>>> 517   tree bound = get_bound_from_access_with_size (array);
>>>>>>>> 518   /* The type of the call to .ACCESS_WITH_SIZE is a pointer type to
>>>>>>>> 519      the element of the array.  */
>>>>>>>> 520   tree element_size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (array)));
>>>>>>>> 521   gcc_assert (bound);
>>>>>>>> 522
>>>>>>>> 523   /* Given the offset, and the size of each element, the index can be
>>>>>>>> 524      computed as: offset/element_size.  */
>>>>>>>> 525   *offset = save_expr (*offset);
>>>>>>>> 526   tree index = fold_build2 (EXACT_DIV_EXPR,
>>>>>>>> 527                            sizetype, *offset,
>>>>>>>> 528                            unshare_expr (element_size));
>>>>>>>> 529   /* Create a "(T *) 0" tree node to describe the original array type.
>>>>>>>> 530      We get the original array type from the first argument of the call to
>>>>>>>> 531      .ACCESS_WITH_SIZE (REF, COUNTED_BY_REF, 1, num_bytes, -1).
>>>>>>>> 532
>>>>>>>> 533      Originally, REF is a COMPONENT_REF with the original array type,
>>>>>>>> 534      it was converted to a pointer to an ADDR_EXPR, and the ADDR_EXPR's
>>>>>>>> 535      first operand is the original COMPONENT_REF.  */
>>>>>>>> 536   tree ref = CALL_EXPR_ARG (array, 0);
>>>>>>>> 537   tree array_type
>>>>>>>> 538     = unshare_expr (TREE_TYPE (TREE_OPERAND (TREE_OPERAND(ref, 0), 0)));
>>>>>>>> 539   tree zero_with_type = build_int_cst (build_pointer_type (array_type), 0);
>>>>>>>> 540   return build_call_expr_internal_loc (loc, IFN_UBSAN_BOUNDS,
>>>>>>>> 541                                        void_type_node, 3, zero_with_type,
>>>>>>>> 542                                        index, bound);
>>>>>>>> 543 }
>>>>>>>> 
>>>>>>>> =====
>>>>>>>> 
>>>>>>>> Inside gdb, the guilty IR failed in LTO streaming is from the above line 520:
>>>>>>>> TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (array))),
>>>>>>>> 
>>>>>>>> When I use this tree node as an operand of the expression at line 526, I added
>>>>>>>> unshare_expr.
>>>>>>>> 
>>>>>>>> However, I still see the guilty IR as in gdb:
>>>>>>>> 
>>>>>>>>         unit-size <mult_expr 0xfffff5aabf90 type <integer_type 0xfffff57c0000 sizetype>
>>>>>>>>             side-effects
>>>>>>>>             arg:0 <mult_expr 0xfffff5aabf68 type <integer_type 0xfffff57c0000 sizetype>
>>>>>>>> 
>>>>>>>>                 arg:0 <ssa_name 0xfffff5761e18 type <error_mark 0xfffff56c0e58>
>>>>>>>>                     nothrow
>>>>>>>>                     def_stmt
>>>>>>>>                     version:12 in-free-list>
>>>>>>>>                 arg:1 <ssa_name 0xfffff5761e60 type <error_mark 0xfffff56c0e58>
>>>>>>>>                     nothrow
>>>>>>>>                     def_stmt
>>>>>>>>                     version:13 in-free-list>>
>>>>>>>>             arg:1 <integer_cst 0xfffff56c10c8 constant 4>>
>>>>>>>> 
>>>>>>>> 
>>>>>>>> I have been stuck with this bug for quite some time.
>>>>>>>> Any help is helpful.
>>>>>>> 
>>>>>>> The above hasn't been gimplified correctly, you'd instead see
>>>>>>> a D.1234 in there, not an expression with SSA names.  That happens
>>>>>>> when the frontend fails to emit a DECL_EXPR for a decl with this
>>>>>>> type.
>>>>>> 
>>>>>> .. which then also results in missing unsharing of this expression
>>>>>> (so the SSA names leak in)
>>>>> 
>>>>> Thanks a lot for the hints.
>>>>> 
>>>>> One correction first, the LTO bug is not related to -fsanitize=bounds.  Deleting -fsanitize=bounds still can
>>>>> repeat the failure.
>>>>> 
>>>>> After further debugging into the gimplification phase related with the SAVE_EXPR, I finally locate the place
>>>>> where the unshareing of the expression is missing.   This is in the routine “pointer_int_sum” of c-family/c-common.cc:
>>>>> 
>>>>> 3330     {
>>>>> 3331       if (!complain && !COMPLETE_TYPE_P (TREE_TYPE (result_type)))
>>>>> 3332         return error_mark_node;
>>>>> 3333       size_exp = size_in_bytes_loc (loc, TREE_TYPE (result_type));
>>>>> 3334       /* Wrap the pointer expression in a SAVE_EXPR to make sure it
>>>>> 3335          is evaluated first when the size expression may depend
>>>>> 3336          on it for VM types.  */
>>>>> 3337       if (TREE_SIDE_EFFECTS (size_exp)
>>>>> 3338           && TREE_SIDE_EFFECTS (ptrop)
>>>>> 3339           && variably_modified_type_p (TREE_TYPE (ptrop), NULL))
>>>>> 3340         {
>>>>> 3341           ptrop = save_expr (ptrop);
>>>>> 3342           size_exp = build2 (COMPOUND_EXPR, TREE_TYPE (intop), ptrop, size_exp);
>>>>> 3343         }
>>>>> 3344     }
>>>>> 
>>>>> In the above, at line 3333, the tree node, TYPE_SIZE_UNIT (TREE_TYPE(result_type)), is returned directly as
>>>>> the size_exp,
>>>>> 
>>>>> (gdb) call debug_tree(size_exp)
>>>>> <mult_expr 0xfffff5a6f910
>>>>>  type <integer_type 0xfffff57c0000 sizetype public unsigned DI
>>>>>      size <integer_cst 0xfffff56c0e70 constant 64>
>>>>>      unit-size <integer_cst 0xfffff56c0e88 constant 8>
>>>>>      align:64 warn_if_not_align:0 symtab:0 alias-set -1 canonical-type 0xfffff57c0000 precision:64 min <integer_cst 0xfffff56c0ea0 0> max <integer_cst 0xfffff56d05e0 18446744073709551615>>
>>>>>  side-effects
>>>>>  arg:0 <mult_expr 0xfffff5a6f8e8 type <integer_type 0xfffff57c0000 sizetype>
>>>>>      side-effects
>>>>>      arg:0 <nop_expr 0xfffff56dc540 type <integer_type 0xfffff57c0000 sizetype>
>>>>>          side-effects
>>>>>          arg:0 <save_expr 0xfffff56dc4c0 type <integer_type 0xfffff57c05e8 int>
>>>>>              side-effects arg:0 <parm_decl 0xfffff76b6f80 n1>>>
>>>>>      arg:1 <nop_expr 0xfffff56dc600 type <integer_type 0xfffff57c0000 sizetype>
>>>>>          side-effects
>>>>>          arg:0 <save_expr 0xfffff56dc580 type <integer_type 0xfffff57c05e8 int>
>>>>>              side-effects arg:0 <parm_decl 0xfffff76b7000 n2>>>>
>>>>>  arg:1 <integer_cst 0xfffff56c10c8 type <integer_type 0xfffff57c0000 sizetype> constant 4>>
>>>>> 
>>>>> 
>>>>> Without unshare_expr to this size_exp, the above TYPE_SIZE_UNIT node containing SAVE_EXPRs
>>>>> is gimpflified to expressions with SSA_NAME during gimplification.  (This is unaccepted by LTO).
>>>>> 
>>>>> Adding an unshare_expr (size_exp) resolved this problem.
>>>>> 
>>>>> Although I still think that there might be potential issue with the gimpflication of SAVE_EXPRs, I dare not
>>>>> to modify that part of the code.
>>>>> 
>>>>> At this moment, I will add unshare_expr to the routine “pointer_int_sum” to workaround this issue.
>>>> 
>>>> It's only a workaround mind you.  The bug is that the frontend fails
>>>> to emit a DECL_EXPR which would
>>>> trigger both unsharing and proper gimplification of the type size.
>>> 
>>> For a simple testing case:
>>> 
>>> $ cat test.c
>>> struct annotated {
>>> unsigned int foo;
>>> char b;
>>> int array[] __attribute__((counted_by (foo)));
>>> };
>>> extern struct annotated * alloc_buf (int index);
>>> 
>>> static void bar ()
>>> {
>>> struct annotated *p2 = alloc_buf (10);
>>> p2->array[11] = 0;
>>> return;
>>> }
>>> 
>>> The C FE generates the following IR:
>>> 
>>> [opc@qinzhao-ol8u3-x86 108896]$ cat test.c.005t.original
>>> ;; Function bar (null)
>>> ;; enabled by -tree-original
>>> 
>>> 
>>> {
>>> struct annotated * p2 = alloc_buf (10);
>>> 
>>>   struct annotated * p2 = alloc_buf (10);
>>> *(.ACCESS_WITH_SIZE ((int *) &p2->array, &p2->foo, 1, 32, -1) + 44) = 0;
>>> return;
>>> }
>>> 
>>> Do you see any obvious IR issue in the above? Do I miss to generate any DECL_EXPR in the above IR?
>> 
>> It's an interesting question - I don't see where the gimplifier would
>> need to access DECL/TYPE_SIZE
> 
> My bad, the above simple example did not expose the LTO error. Just used to show the IR generated for the array access.
> 
> The LTO error only happens with multi-dimension array, whose inner dimensions are VLA.  And the outermost dimension is flexible array member.  Like following:
> 
> 
>   void __attribute__((__noinline__)) setup_and_test_vla (int n1, int n2, int m)
> {
>   struct foo {
>       int n;
>       int p[][n2][n1] __attribute__((counted_by(n)));
>   } *f;
> 
>   f = (struct foo *) malloc (sizeof(struct foo) + m*sizeof(int[n2][n1]));
>   f->n = m;
>   f->p[m][n2][n1]=1;
>   return;
> }
> 
> And the IR for the routine “setup_and_test_vla” is:
> 
> {
>  typedef struct foo struct struct foo;
>  struct foo * f;
> 
>  SAVE_EXPR <n1>;, SAVE_EXPR <n2>;;, {
>        typedef struct foo struct struct foo;
>  };
>    struct foo * f;
>  f = (struct foo *) malloc (0, SAVE_EXPR <n1>;, SAVE_EXPR <n2>;;, ((long unsigned int) m * (long unsigned int) ((sizetype) SAVE_EXPR <n1> * (sizetype) SAVE_EXPR <n2>) + 1) * 4;);
>  f->n = m;
>  (*(.ACCESS_WITH_SIZE ((int[0:(sizetype) ((long int) SAVE_EXPR <n2> + -1)][0:(sizetype) ((long int) SAVE_EXPR <n1> + -1)] *) &f->p, &f->n, 1, 32, -1) + (sizetype) (((long unsigned int) m * (long unsigned int) ((sizetype) SAVE_EXPR <n1> * (sizetype) SAVE_EXPR <n2>)) * 4)))[n2][n1] = 1;
>  return;
> }
> 
> 
> 
>> so the mistake, if any, should be that you need to unshare the size
>> expressions you are using as
>> argument to .ACCESS_WITH_SIZE?
> 
> Hm, I tried that in the beginning, but didn’t work. I will check again. 
> 
>> Mind, you are replacing an ARRAY_REF
>> with a pointer indirection
>> as well
> 
> Yes, this is for resolving a very early gimplification issue as I reported last Nov:
> https://gcc.gnu.org/pipermail/gcc-patches/2023-November/638793.html
> 
> Since no-one responded at that time, I fixed the issue by replacing the ARRAY_REF
> With a pointer indirection:
> https://gcc.gnu.org/pipermail/gcc-patches/2023-December/639605.html
> 
> The reason for such change is:  return a flexible array member TYPE is not allowed
> by C language (our gimplification follows this rule), so, we have to return a pointer TYPE instead. 
> 
> 
>> - IMO we shouldn't replace accesses this way but instead make
>> it possible for analysis to
>> discover the base/size values?
> 
> Yes, if keeping the ARRAY_REF, then bound sanitizer instrumentation will be much simpler since the INDEX
> Information is kept in the TYPE NODE of the ARRAY_REF.  
> However, due to the above reason, we have to replace the ARRAY_REF with a pointer INDIRECT_REF. 
> Such change made the bound sanitizer more difficult due to the INDEX was lost when the ARRAY_REF was
> Converted to the INDIRECT_REF.
> 
> I resolved this issue by adding a new argument to .ACCESS_WITH_SIZE to record the INDEX when converting
> The ARRAY_REF to INDIRECT_REF during C FE.
> 
> Let me know if you have any comment.
> 
> Thanks.
> 
> Qing
>> 
>>> Thanks.
>>> 
>>> Qing
>>> 
>>> 
>>> I compared it with the following testing case without the “counted-by” annotation
>>> and use an user-defined “access_with_size” function, The IR looks like exactly the same:
>>> 
>>> $ cat test_1.c
>>> struct annotated {
>>> unsigned int foo;
>>> char b;
>>> int array[];
>>> };
>>> extern struct annotated *alloc_buf (int);
>>> extern int *access_with_size (int * ref, unsigned int * size, int a, int b, int c);
>>> 
>>> static void bar ()
>>> {
>>> struct annotated *p2 = alloc_buf (10);
>>> access_with_size ((int *) &p2->array, &p2->foo, 1, 32, -1)[11] = 0;
>>> return;
>>> }
>>> [opc@qinzhao-ol8u3-x86 108896]$ cat test_1.c.005t.original
>>> 
>>> ;; Function bar (null)
>>> ;; enabled by -tree-original
>>> 
>>> 
>>> {
>>> struct annotated * p2 = alloc_buf (10);
>>> 
>>>   struct annotated * p2 = alloc_buf (10);
>>> *(access_with_size ((int *) &p2->array, &p2->foo, 1, 32, -1) + 44) = 0;
>>> return;
>>> }
>>> 
>>> 
>>> 
>>>> 
>>>>> Let me know if you have any comment and suggestion.
>>>>> 
>>>>> Thanks a lot.
>>>>> 
>>>>> Qing
>>>>> 
>>>>>>> 
>>>>>>>> 
>>>>>>>> Qing
>>>>>>>> 
>>>>>>>>> 
>>>>>>>>>> Thanks a lot for the help.
>>>>>>>>>> 
>>>>>>>>>> Qing



      reply	other threads:[~2024-01-22 16:54 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-01-12 15:54 Qing Zhao
2024-01-12 16:28 ` Richard Biener
2024-01-12 17:30   ` Qing Zhao
2024-01-15  8:13     ` Eric Botcazou
2024-01-15 16:42       ` Qing Zhao
2024-01-15  9:31     ` Richard Biener
2024-01-15 14:54       ` Qing Zhao
2024-01-15 15:06         ` Jakub Jelinek
2024-01-15 16:41           ` Qing Zhao
2024-01-16 20:25       ` Qing Zhao
2024-01-17  6:42         ` Richard Biener
2024-01-17  6:43           ` Richard Biener
2024-01-18 14:45             ` Qing Zhao
2024-01-19  9:30               ` Richard Biener
2024-01-19 16:25                 ` Qing Zhao
2024-01-22  7:40                   ` Richard Biener
2024-01-22 14:52                     ` Qing Zhao
2024-01-22 16:54                       ` Qing Zhao [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=C6A49742-05BD-4329-AAD4-5C22D9199C08@oracle.com \
    --to=qing.zhao@oracle.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jakub@redhat.com \
    --cc=richard.guenther@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).