Re: g++ problem with order of evaluation of arguments of delete.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 4 May 2023 at 10:46, Georg-Johann Lay <avr@xxxxxxxx> wrote:
>
> Given the following C++ code:
>
> struct Lexer;
>
> struct Token
> {
>      Lexer* const lexer_;
>      Token (Lexer *l) : lexer_(l) {}
>      ~Token() = default;
>
>      Token() = delete;
>      Token (const Token&) = delete;
>      Token (Token&&) = delete;
>      void operator= (const Token&) = delete;
>      void operator= (Token&&) = delete;
> };
>
> struct Lexer
> {
>      Token *token_;
>      Lexer() = default;
>      ~Lexer() { delete token_; }
>
>      Lexer (const Lexer&) = delete;
>      Lexer (Lexer&&) = delete;
>      void operator= (const Lexer&) = delete;
>      void operator= (Lexer&&) = delete;
> };
>
> int main()
> {
>      Lexer *lexer = new Lexer();
>      Token *token = new Token (lexer);
>      lexer->token_ = token;
>      delete token->lexer_;
>      // delete lexer; // is OK
> }
>
> When I compile this with g++ v11.3 (same with g++ from master from
> 2023-04-20) and run
>
> $ g++ main-3.cpp -Os -W -Wall -Wextra -dumpbase "" -save-temps -dp  &&
> ./a.out
>
> Segmentation fault (core dumped)
>
> The assembly shows that the generated code does two calls to "delete"
> but just one call to "new", so it's clear something is going wrong.
>
> As far as I understand, the "delete token_" in ~Lexer is a sequence
> point, so that dereferencing token in "delete->lexer_" must be sequenced
> before calling ~Token ?
>
> Segmentation fault also occurs with -O0, but goes away when removing the
> "const" in "Lexer* const lexer_;".
>
> My question: Is this a GCC problem, or a problem with the code and
> sequence points?

It's definitely a GCC bug.

The code is compiled to something like:

token->lexer_->~Lexer();
operator delete(token->lexer_);

But that means that we evaluate 'token' twice, even though it's been
invalidated by the destructor. It should be compiled to something more
like:

auto* p = token->lexer_;
p->~Lexer();
operator delete(p);



[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux