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

            Bug ID: 91358
           Summary: Wrong code with dynamic allocation and optional like
                    class
           Product: gcc
           Version: 9.1.1
            Status: UNCONFIRMED
          Keywords: wrong-code
          Severity: normal
          Priority: P3
         Component: middle-end
          Assignee: unassigned at gcc dot gnu.org
          Reporter: antoshkka at gmail dot com
  Target Milestone: ---

The issue is reproduced on GCCs from 5 to 9 with -O2 and -std=c++11. GCC-10
also generates wrong code with -O2 -std=c++11 -fno-allocation-dce.

Source code:

template<class T>
struct optional {
  optional() : m_initialized(false) {}

  ~optional() {
    if (m_initialized)
      reinterpret_cast<T&>(m_storage).~T();
  }

  bool m_initialized;
  alignas(T) unsigned char m_storage[sizeof(T)];
};

struct NoPtr1 {
  void *ptr = nullptr;

  ~NoPtr1() {
    if (ptr) {
      __builtin_abort();
    }
  }
};

static void test(optional<NoPtr1> ) noexcept {
  delete new unsigned;
}

void process(optional<NoPtr1> state) {
  return test(state);
}

int main() {
  process({});
}


The above code generates a conditional jump that depends on uninitialised
value. valgrind complains:
==13823==    at 0x4007B2: ~NoPtr1 (main.cpp:18)
==13823==    by 0x4007B2: ~optional (main.cpp:7)
==13823==    by 0x4007B2: process(optional<NoPtr1>) (main.cpp:29)
==13823==    by 0x40067F: main (main.cpp:33)


Running the example under GDB confirms that the destructor of NoPtr1 is called:

(gdb) break main.cpp:18
Breakpoint 1 at 0x400686: main.cpp:18. (2 locations)
(gdb) r
Breakpoint 1, NoPtr1::~NoPtr1 (this=<optimized out>, __in_chrg=<optimized out>)
at main.cpp:18
18          if (ptr) {
(gdb) bt
#0  NoPtr1::~NoPtr1 (this=<optimized out>, __in_chrg=<optimized out>) at
main.cpp:18
#1  optional<NoPtr1>::~optional (this=<optimized out>, __in_chrg=<optimized
out>) at main.cpp:7
#2  process (state=...) at main.cpp:29
#3  0x0000000000400680 in main () at main.cpp:33
(gdb) disassemble 
Dump of assembler code for function process(optional<NoPtr1>):
   0x0000000000400790 <+0>:     push   %rbp
   0x0000000000400791 <+1>:     push   %rbx
   0x0000000000400792 <+2>:     sub    $0x8,%rsp
   0x0000000000400796 <+6>:     mov    0x8(%rdi),%rbx
   0x000000000040079a <+10>:    movzbl (%rdi),%ebp
   0x000000000040079d <+13>:    mov    $0x4,%edi
   0x00000000004007a2 <+18>:    callq  0x400600 <_Znwm@plt>
   0x00000000004007a7 <+23>:    mov    %rax,%rdi
   0x00000000004007aa <+26>:    callq  0x4005f0 <_ZdlPv@plt>
=> 0x00000000004007af <+31>:    test   %rbx,%rbx
   0x00000000004007b2 <+34>:    je     0x4007b9 <process(optional<NoPtr1>)+41>
   0x00000000004007b4 <+36>:    test   %bpl,%bpl
   0x00000000004007b7 <+39>:    jne    0x4007c0 <process(optional<NoPtr1>)+48>
   0x00000000004007b9 <+41>:    add    $0x8,%rsp
   0x00000000004007bd <+45>:    pop    %rbx
   0x00000000004007be <+46>:    pop    %rbp
   0x00000000004007bf <+47>:    retq   
   0x00000000004007c0 <+48>:    callq  0x4005e0 <abort@plt>

Reply via email to