public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug libstdc++/102573] New: optimized code removes the underlying elements of the std::initializer_list being copied
@ 2021-10-03  4:04 13508417 at qq dot com
  2021-10-03  4:09 ` [Bug libstdc++/102573] " pinskia at gcc dot gnu.org
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: 13508417 at qq dot com @ 2021-10-03  4:04 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102573

            Bug ID: 102573
           Summary: optimized code removes the underlying elements of the
                    std::initializer_list being copied
           Product: gcc
           Version: 4.8.5
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: 13508417 at qq dot com
  Target Milestone: ---

Using clang++ compiler with libstdc++, the output of below program differs
whether use -O option.

----

code:
#include<iostream>
#include<initializer_list>
using namespace std;

int main()
{
    initializer_list<int> il;
    il = {111, 222};

    cout << "initializer_list size: " << il.size() << endl;
    cout << "initializer_list underlying elements: " << endl;
    for (auto i : il)
        cout << i << endl;

    return 0;
}

----

command:
➜  clang++ test_2.cpp -std=c++11 -O1 -v
clang version 10.0.0
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/local/bin
Found candidate GCC installation: /usr/lib/gcc/i686-redhat-linux/4.8.2
Found candidate GCC installation: /usr/lib/gcc/i686-redhat-linux/4.8.5
Found candidate GCC installation: /usr/lib/gcc/x86_64-redhat-linux/4.8.2
Found candidate GCC installation: /usr/lib/gcc/x86_64-redhat-linux/4.8.5
Selected GCC installation: /usr/lib/gcc/x86_64-redhat-linux/4.8.5
...

----

output without -O:
initializer_list size: 2
initializer_list underlying elements:
111
222

----

output with -O1:
initializer_list size: 2
initializer_list underlying elements:
1402476368
32767

----

Question:
>From https://timsong-cpp.github.io/cppwp/n4659/dcl.init.list, I know that the
reason is because the lifetime of the underlying array should be same as the
temporary initializer_list constructed directly from the "{111, 222}", and the
variable "il" only copy the address and length of the underlying array using
the default copy member, but cannot affect the lifetime of the underlying
array.

But my question is, since the copied initializer_list can't affect the lifetime
of the underlying array bound to the original initializer_list, can we just
prohibit the copy member in the library implementation of
std::initializer_list? It seems to me that the copy member makes not much
sense, but probably lures the user to make mistakes.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Bug libstdc++/102573] optimized code removes the underlying elements of the std::initializer_list being copied
  2021-10-03  4:04 [Bug libstdc++/102573] New: optimized code removes the underlying elements of the std::initializer_list being copied 13508417 at qq dot com
@ 2021-10-03  4:09 ` pinskia at gcc dot gnu.org
  2021-10-03  5:49 ` 13508417 at qq dot com
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: pinskia at gcc dot gnu.org @ 2021-10-03  4:09 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102573

Andrew Pinski <pinskia at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |RESOLVED
         Resolution|---                         |INVALID

--- Comment #1 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
GCC warns:
<source>: In function 'int main()':
<source>:9:19: warning: assignment from temporary 'initializer_list' does not
extend the lifetime of the underlying array [-Winit-list-lifetime]
    9 |     il = {111, 222};
      |                   ^

Plus at runtime with -fsanitize=address:

=================================================================
==1==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7ffcff6b4e10
at pc 0x00000040147d bp 0x7ffcff6b4dc0 sp 0x7ffcff6b4db8
READ of size 4 at 0x7ffcff6b4e10 thread T0
    #0 0x40147c in main /app/example.cpp:13
    #1 0x7f5915fc70b2 in __libc_start_main
(/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
    #2 0x40118d in _start (/app/output.s+0x40118d)

Address 0x7ffcff6b4e10 is located in stack of thread T0 at offset 32 in frame
    #0 0x401255 in main /app/example.cpp:7

  This frame has 2 object(s):
    [32, 40) '<unknown>' <== Memory access at offset 32 is inside this variable
    [64, 80) 'il' (line 8)
HINT: this may be a false positive if your program uses some custom stack
unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-use-after-scope /app/example.cpp:13 in main
Shadow bytes around the buggy address:
  0x10001fece970: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10001fece980: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10001fece990: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10001fece9a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10001fece9b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1
=>0x10001fece9c0: f1 f1[f8]f2 f2 f2 00 00 f3 f3 00 00 00 00 00 00
  0x10001fece9d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10001fece9e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10001fece9f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10001fecea00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10001fecea10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==1==ABORTING
initializer_list size: 2
initializer_list underlying elements: 


clang also errors out the same way.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Bug libstdc++/102573] optimized code removes the underlying elements of the std::initializer_list being copied
  2021-10-03  4:04 [Bug libstdc++/102573] New: optimized code removes the underlying elements of the std::initializer_list being copied 13508417 at qq dot com
  2021-10-03  4:09 ` [Bug libstdc++/102573] " pinskia at gcc dot gnu.org
@ 2021-10-03  5:49 ` 13508417 at qq dot com
  2021-10-03  6:20 ` pinskia at gcc dot gnu.org
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: 13508417 at qq dot com @ 2021-10-03  5:49 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102573

--- Comment #2 from wjf <13508417 at qq dot com> ---
(In reply to Andrew Pinski from comment #1)
> GCC warns:
> <source>: In function 'int main()':
> <source>:9:19: warning: assignment from temporary 'initializer_list' does
> not extend the lifetime of the underlying array [-Winit-list-lifetime]
>     9 |     il = {111, 222};
>       |                   ^
> 
> Plus at runtime with -fsanitize=address:
> 
> =================================================================
> ==1==ERROR: AddressSanitizer: stack-use-after-scope on address
> 0x7ffcff6b4e10 at pc 0x00000040147d bp 0x7ffcff6b4dc0 sp 0x7ffcff6b4db8
> READ of size 4 at 0x7ffcff6b4e10 thread T0
>     #0 0x40147c in main /app/example.cpp:13
>     #1 0x7f5915fc70b2 in __libc_start_main
> (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
>     #2 0x40118d in _start (/app/output.s+0x40118d)
> 
> Address 0x7ffcff6b4e10 is located in stack of thread T0 at offset 32 in frame
>     #0 0x401255 in main /app/example.cpp:7
> 
>   This frame has 2 object(s):
>     [32, 40) '<unknown>' <== Memory access at offset 32 is inside this
> variable
>     [64, 80) 'il' (line 8)
> HINT: this may be a false positive if your program uses some custom stack
> unwind mechanism, swapcontext or vfork
>       (longjmp and C++ exceptions *are* supported)
> SUMMARY: AddressSanitizer: stack-use-after-scope /app/example.cpp:13 in main
> Shadow bytes around the buggy address:
>   0x10001fece970: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>   0x10001fece980: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>   0x10001fece990: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>   0x10001fece9a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>   0x10001fece9b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1
> =>0x10001fece9c0: f1 f1[f8]f2 f2 f2 00 00 f3 f3 00 00 00 00 00 00
>   0x10001fece9d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>   0x10001fece9e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>   0x10001fece9f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>   0x10001fecea00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>   0x10001fecea10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> Shadow byte legend (one shadow byte represents 8 application bytes):
>   Addressable:           00
>   Partially addressable: 01 02 03 04 05 06 07 
>   Heap left redzone:       fa
>   Freed heap region:       fd
>   Stack left redzone:      f1
>   Stack mid redzone:       f2
>   Stack right redzone:     f3
>   Stack after return:      f5
>   Stack use after scope:   f8
>   Global redzone:          f9
>   Global init order:       f6
>   Poisoned by user:        f7
>   Container overflow:      fc
>   Array cookie:            ac
>   Intra object redzone:    bb
>   ASan internal:           fe
>   Left alloca redzone:     ca
>   Right alloca redzone:    cb
> ==1==ABORTING
> initializer_list size: 2
> initializer_list underlying elements: 
> 
> 
> clang also errors out the same way.

----

Hi Andrew,

I know that adding "-fsanitize=address" could detect the stack-use-after-scope
in runtime. But why not just delete the copy member in std::initializer_list
implementation? I don't see much sense to permit the copy operation.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Bug libstdc++/102573] optimized code removes the underlying elements of the std::initializer_list being copied
  2021-10-03  4:04 [Bug libstdc++/102573] New: optimized code removes the underlying elements of the std::initializer_list being copied 13508417 at qq dot com
  2021-10-03  4:09 ` [Bug libstdc++/102573] " pinskia at gcc dot gnu.org
  2021-10-03  5:49 ` 13508417 at qq dot com
@ 2021-10-03  6:20 ` pinskia at gcc dot gnu.org
  2021-10-03 14:16 ` 13508417 at qq dot com
  2021-10-04  6:55 ` redi at gcc dot gnu.org
  4 siblings, 0 replies; 6+ messages in thread
From: pinskia at gcc dot gnu.org @ 2021-10-03  6:20 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102573

--- Comment #3 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
(In reply to wjf from comment #2)
> Hi Andrew,
> 
> I know that adding "-fsanitize=address" could detect the
> stack-use-after-scope in runtime. But why not just delete the copy member in
> std::initializer_list implementation? I don't see much sense to permit the
> copy operation.

Because this is how std::initializer_list works.
Note even using LLVM's libc++ with clang produces the same runtime failure.



This is also why GCC has a warning at compile time explicitly for this case:
<source>: In function 'int main()':
<source>:9:19: warning: assignment from temporary 'initializer_list' does not
extend the lifetime of the underlying array [-Winit-list-lifetime]
    9 |     il = {111, 222};
      |                   ^

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Bug libstdc++/102573] optimized code removes the underlying elements of the std::initializer_list being copied
  2021-10-03  4:04 [Bug libstdc++/102573] New: optimized code removes the underlying elements of the std::initializer_list being copied 13508417 at qq dot com
                   ` (2 preceding siblings ...)
  2021-10-03  6:20 ` pinskia at gcc dot gnu.org
@ 2021-10-03 14:16 ` 13508417 at qq dot com
  2021-10-04  6:55 ` redi at gcc dot gnu.org
  4 siblings, 0 replies; 6+ messages in thread
From: 13508417 at qq dot com @ 2021-10-03 14:16 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102573

--- Comment #4 from wjf <13508417 at qq dot com> ---
Hi Andrew,

I've updated my gcc to 10.2.1, and find while it did show what you said for my
initial code snippet, it won't warn me anything, nor report error at runtime
with -fsanitize=address (note that clang version 10.0.0 will report error at
runtime however), for below two code snippets:

----

code 1:
#include<iostream>
#include<initializer_list>
using namespace std;

int main()
{
    initializer_list<int> il({111, 222});

    cout << "initializer_list size: " << il.size() << endl;
    cout << "initializer_list underlying elements: " << endl;
    for (auto i : il)
        cout << i << endl;

    return 0;
}

----

code 2:
#include<iostream>
#include<initializer_list>
using namespace std;

int main()
{
    initializer_list<int> il;
    {
        initializer_list<int> il2 = {111, 222};
        il = il2;
    }

    cout << "initializer_list size: " << il.size() << endl;
    cout << "initializer_list underlying elements: " << endl;
    for (auto i : il)
        cout << i << endl;

    return 0;
}

----

As you can see, above two code snippets should still have the similar
"lifespan" issue. code 1's il constructs from an temporary, but doesn't extend
the lifetime of the underlying array. code 2's il is assigned from il2, but
have longer lifetime than il2. When using clang++ optimization, the output will
be something like below:

initializer_list size: 2
initializer_list underlying elements:
1877862544
32767

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Bug libstdc++/102573] optimized code removes the underlying elements of the std::initializer_list being copied
  2021-10-03  4:04 [Bug libstdc++/102573] New: optimized code removes the underlying elements of the std::initializer_list being copied 13508417 at qq dot com
                   ` (3 preceding siblings ...)
  2021-10-03 14:16 ` 13508417 at qq dot com
@ 2021-10-04  6:55 ` redi at gcc dot gnu.org
  4 siblings, 0 replies; 6+ messages in thread
From: redi at gcc dot gnu.org @ 2021-10-04  6:55 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102573

--- Comment #5 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to wjf from comment #2)
> I know that adding "-fsanitize=address" could detect the
> stack-use-after-scope in runtime. But why not just delete the copy member in
> std::initializer_list implementation? I don't see much sense to permit the
> copy operation.

Because the standard requires it.

https://cplusplus.github.io/LWG/issue2432

Until the standard is changed, libstdc++ will define the assignment operator.

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2021-10-04  6:55 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-03  4:04 [Bug libstdc++/102573] New: optimized code removes the underlying elements of the std::initializer_list being copied 13508417 at qq dot com
2021-10-03  4:09 ` [Bug libstdc++/102573] " pinskia at gcc dot gnu.org
2021-10-03  5:49 ` 13508417 at qq dot com
2021-10-03  6:20 ` pinskia at gcc dot gnu.org
2021-10-03 14:16 ` 13508417 at qq dot com
2021-10-04  6:55 ` redi at gcc dot gnu.org

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).