Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding behavior of overloading operator new in shared library

I am working on a shared library and application on Centos platform [clang++, llvm3.9.0 and libc++] , and both library and application overload their own operator new and operator delete.

Everything is working fine except for 1 case. On calling copy constructor of std::string always calling operator new of application side:

Here is the senario:

std::string str1 ( "A very strange issue on CentOS using clang and libc++" ); //operator new of library side called.

std::string str2(str1); //operator new of application side called. WHY??

operator delete on both cases are called for library side.

Here are the logs when running the following code:

====================================================
operator new in shared library
operator new called Application side
operator delete in shared library
operator delete in shared library
====================================================

Shared Library side operator new and delete:

    void * operator new ( size_t len ) throw ( std::bad_alloc )
    {
        printf("operator new in shared library\n");
        void * mem = malloc( len );
        if ( (mem == 0) && (len != 0) ) throw std::bad_alloc();
        return mem;
    }

    void * operator new[] ( size_t len ) throw ( std::bad_alloc )
    {
        printf("operator new[] in shared library\n");
        void * mem = malloc( len );
        if ( (mem == 0) && (len != 0) ) throw std::bad_alloc();
        return mem;
    }

    void operator delete ( void * ptr ) throw()
    {
        printf("operator delete in shared library\n");
        if ( ptr != 0 ) free ( ptr );
    }

    void operator delete[] ( void * ptr ) throw()
    {
        printf("operator delete[] in shared library\n");
        if ( ptr != 0 ) free ( ptr );
    }

Application side operator new and operator delete:

void * operator new ( size_t len ) throw ( std::bad_alloc )
{
    void * mem = malloc ( len );
    printf("operator new called Application side\n");
    if ( (mem == 0) && (len != 0) ) throw std::bad_alloc();
        return mem;
}

void * operator new[] ( size_t len ) throw ( std::bad_alloc )
{
    void * mem = malloc ( len );
    printf("operator new[] called Application side\n");
    if ( (mem == 0) && (len != 0) ) throw std::bad_alloc();
        return mem;
}

void operator delete ( void * ptr ) throw()
{
    printf("operator delete[] called Application side\n");
    if ( ptr != 0 )free ( ptr );
}

void operator delete[] ( void * ptr ) throw()
{
    printf("operator delete[] called Application side\n");
    if ( ptr != 0 ) free ( ptr );
}

Please help.

like image 542
aga Avatar asked Mar 08 '23 19:03

aga


1 Answers

Short answer: Don't do that.

There's only supposed to be one replacement operator new (ok, there are a bunch of flavors, like noexcept, and [], etc, but only one of each flavor).

If you have more than one, then - as you have discovered - it is not clear which one gets called, and you can get mismatched calls to new and delete, which is a quick trip to undefined behavior.

I could explain why you're getting the exact behavior that you're reporting, but it has to do with inlining, and extern templates, and it doesn't really matter. You have two replacement functions for operator new, and that's the problem.

like image 95
Marshall Clow Avatar answered Apr 26 '23 09:04

Marshall Clow