Segmentation fault in operator delete[] [duplicate]
Asked Answered
U

2

15

I get segmentation fault exception on the next code:

class A {
public:
    A() {}
    virtual ~A(){}
    double m_d;
};
class B : public A {
public:
    B() {}
    virtual ~B(){}
    int x;
};
int main()
{
    A* ptr = new B[5];
    delete[] ptr;
    return 0;
}

If delete d'tors, no exception. Expected to NOT receive an exception.

Compiler: g++ (Ubuntu 11.2.0-19ubuntu1) 11.2.0

Unswerving answered 22/11, 2022 at 19:7 Comment(8)
What happens if you declare ptr to have type B*?Elwina
A* ptr = new B[5]; yeah that's a bad idea. The 2 objects have different sizes so any attempt to access anything other than ptr[0] will fail horriblySudan
Nothing is crashing for me: godbolt.org/z/185Ta8b6GStringendo
@MaciejPolański it's a gcc only crash - live - godbolt.org/z/dMeo9sWaMJarret
delete[] ptr; invokes undefined behavior because ptr points to an array of B objects, not an array of A objectsSudan
Expected to NOT receive an exception -- To be more clear, you did not receive a C++ exception. Your program simply crashed due to a segmentation fault.Syllabub
If delete d'tors, no exception. -- "If I remove the brakes, the car runs smoothly".Syllabub
An array of a class is a different type than the class itself, and inheritance does follow through when the type changes, so while a B is-a A an array of B is-not-a array of A.Miticide
S
13

Array delete doesn't respect virtual destructors. Attempting to pass a base class pointer to it causes undefined behavior.

[expr.delete]/2

... In a single-object delete expression, the value of the operand of delete may be a null pointer value, a pointer value that resulted from a previous non-array new-expression, or a pointer to a base class subobject of an object created by such a new-expression. If not, the behavior is undefined. In an array delete expression, the value of the operand of delete may be a null pointer value or a pointer value that resulted from a previous array new-expression. If not, the behavior is undefined.

Note the second list excluding "base class subobject..." part.

[expr.delete]/3

... In an array delete expression, if the dynamic type of the object to be deleted is not similar to its static type, the behavior is undefined.

Where "static type" is the type as determined at compile-time, "dynamic type" is the type of the most-derived object determined at runtime, and "similar" more or less means "the same type", but allows some differences in constness and more.

Scamander answered 22/11, 2022 at 19:40 Comment(1)
The undefined behavior aspect of this cannot be overstated. I compiled and ran the OP's code without a segfault, and this might easily be mistaken for this code being safe to expect to work as expected.Hofuf
G
7

This is not allowed, as described here: Why is it undefined behavior to delete[] an array of derived objects via a base pointer?

Excerpt: C++03 Standard under 5.3.5 [expr.delete] p3: In the second alternative (delete array) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined

I also made, out of curiosity, logging version:

#include <iostream> 

class A {
public:
    A() {}
    virtual ~A(){ std::cout << m_d << " ; ";}
    double m_d {0.5};
};
class B : public A {
public:
    B() {}
    virtual ~B(){ std::cout << x << " : "; }
    int x {2};
};
int main()
{
    A* ptr = new B[5];
    delete[] ptr;
    std::cout << "Hi, nothing crashed here!\n";
    return 0;
}

https://godbolt.org/z/Y7xGdKd3f

Clang: calls base class destructor using incorrect data

2.07634e-317 ; 0.5 ; 9.88131e-324 ; 2.07634e-317 ; 0.5 ; Hi, nothing crashed here!

Gnu: politely crashes

Program returned: 139

M$: works as expected :)

2 : 0.5 ; 2 : 0.5 ; 2 : 0.5 ; 2 : 0.5 ; 2 : 0.5 ; Hi, nothing crashed here

Glop answered 22/11, 2022 at 19:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.