[Bug c++/98798] New: Custom operator new[] and delete[] is buggy for aligned class

marekr22 at wp dot pl gcc-bugzilla@gcc.gnu.org
Fri Jan 22 16:42:50 GMT 2021


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

            Bug ID: 98798
           Summary: Custom operator new[] and delete[] is buggy for
                    aligned class
           Product: gcc
           Version: 11.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: marekr22 at wp dot pl
  Target Milestone: ---

Basically when class has alignment requirement and custom operators `new[]` and
`delete[]` (C++17), then address sanitizer reports buffer overflow:

## MCVE:
```cpp
#include <iostream>
#include <memory>

class EndlineOnDone {
    std::ostream& out;
public:
    EndlineOnDone(std::ostream& out) : out{out} {}
    ~EndlineOnDone()
    {
        out << std::endl;
    }
    std::ostream& stream() { return out; }
};

#define VAR(x) " " #x "=[" << x << "]" 
#define LOG EndlineOnDone(std::cout).stream() << __PRETTY_FUNCTION__

std::ostream& operator<<(std::ostream& out, std::align_val_t a)
{
    return out << static_cast<size_t>(a);
}

class alignas(32) Foo
{
public :
    double x, y, z;

    void * operator new (size_t s, std::align_val_t a)
    {
        auto p = aligned_alloc(static_cast<size_t>(a), s);
        LOG << VAR(p) << VAR(s) << VAR(a);
        return p;
    }

    void operator delete (void * p, size_t s, std::align_val_t a)
    {
        LOG << VAR(p) << VAR(s) << VAR(a);
        if (p) free(p);
    }

#if 1
    void * operator new[ ] (size_t s, std::align_val_t a)
    {
        auto p = aligned_alloc(static_cast<size_t>(a), s);
        LOG << VAR(p) << VAR(s) << VAR(a);
        return p;
    }

    void operator delete[ ] (void *p, size_t s, std::align_val_t a)
    {
        LOG << VAR(p) << VAR(s) << VAR(a);
        if (p) free(p);
    }
#endif
};

int main()
{
    {
        LOG << " std::make_unique<Foo>";
        auto p = std::make_unique<Foo>();
    }

    {
        LOG << " std::make_unique<Foo[]>";
        auto p = std::make_unique<Foo[]>(3);
    }
}
```
https://godbolt.org/z/7xd8YM

## gcc logs (no address sanitizer):
```txt
int main() std::make_unique<Foo>
static void* Foo::operator new(size_t, std::align_val_t) p=[0x21d6ec0] s=[32]
a=[32]
static void Foo::operator delete(void*, size_t, std::align_val_t) p=[0x21d6ec0]
s=[32] a=[32]
int main() std::make_unique<Foo[]>
static void* Foo::operator new [](size_t, std::align_val_t) p=[0x21d6f40]
s=[96] a=[32]
static void Foo::operator delete [](void*, size_t, std::align_val_t)
p=[0x21d6f40] s=[3616] a=[32]
```
Note that `s` value for `Foo[]` doesn't match for `new[]` and `delete[]`
operations.

Address sanitizer reports buffer overflow.

clang is fine (didn't check msvc).

## Workaround
Adding explicit destructor `~Foo() {}` fixes this issue:
https://godbolt.org/z/WoM91Y (use of `~Foo() = default;` doesn't fix it).


https://stackoverflow.com/q/65826663/1387438


More information about the Gcc-bugs mailing list