Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect calling delete on stack variables (with cast-to-pointer operator)

Tags:

c++

tldr

Is there a way, to statically detect error in following code?

struct Foo
{
    operator const int*()
    {
        return &data;
    }

    int data;
};

int main() 
{
    Foo f;
    delete f;
}

since there is a conversion from Foo to void* containing just one user defined conversion, it is actually allowed to call delete on f.

longer story

in our codebase, there was a really stupid way of deserialize strings, in pseudocode

char * buff = bar.loadString();
use buff;
delete buff;

the way was changed, to one templated load function, so now deserialize looks like

bar.load(m_IntMember);
bar.load(m_StringMember);

but all occurrences (there was a lot of them) of loadString had to be manually changed like this:

string buff;
bar.load(buff);
use buff;

we all know what human error can cause, so there are places, where code was wrongly modified like

string buff;
bar.load(buff);
use buff;
delete buff;        //notice the delete

since we are using a bit non-standard implementation of string it actually has a overloaded const char * operator, which can be casted to void* which can be deleted...

I would like to catch all of these errors at compile time (we have custom high performance allocators, so at runtime, it is easy to corrupt memory without any runtime error)

I cannot declare global delete operator accepting const char* I cannot temporarily delete delete operator from string because it is heavily used, so it is unable to compile without it (I cannot "filter out" described error from all errors, because msvc stops compilation when reaching certain amount of errors)

what can I do?

like image 248
relaxxx Avatar asked Oct 30 '22 19:10

relaxxx


1 Answers

This seems to do it:

#include <iostream>

struct Foo
{
    Foo() : data(42) {}

    operator const int*()
    {
        return &data;
    }

    int data;

    struct AmbiguousPointerConversion {};
    private: operator AmbiguousPointerConversion *() {
        throw "hi";
    }
};

int main() 
{
    Foo f;
    const int *p = f;
    std::cout << *p << '\n';
    delete f;
}

Compiling this with g++ gives me:

try.cc: In function ‘int main()’:
try.cc:25:12: error: ambiguous default type conversion from ‘Foo’
     delete f;
            ^
try.cc:25:12: note:   candidate conversions include ‘Foo::operator const int*()’ and ‘Foo::operator Foo::AmbiguousPointerConversion*()’
try.cc:25:12: error: type ‘struct Foo’ argument given to ‘delete’, expected pointer
like image 133
melpomene Avatar answered Nov 15 '22 06:11

melpomene