Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ dll heap memory allocation issue

From this link, I know that we(application) should always don't delete a heap memory allocation from dll, because the heap memory manager are different.

I have few questions:

1.) How about .so file (Linux), is it the same case ?

2.) Is there anyway to make sure that application and library(.dll and .so) are using same heap memory manager or using same heap memory section ? So we can delete and new separately (new at .dll/.so, delete at application ).

Thank you.

like image 556
Anson Tan Avatar asked Dec 31 '19 09:12

Anson Tan


People also ask

Can a DLL allocate memory?

A function in the DLL allocates memory on the heap and passes a pointer to that memory to the exe.

Does a DLL have its own heap?

It is up to the DLL whether it wants to create its own heap, or whether it wants to use an existing heap. In fact, a DLL doesn't need to be consistent in its decision. It could use its own heap for some things and an existing heap for other things.

How do I stop memory allocation on heap?

First, overload the “new” operator in the class. So that, when we create object using “new”, it will not request memory from operating system but will call overloaded “new” method from the class itself for memory allocation. Make the overload new method private to make it in-accessible from outside of the class.

What happens when heap memory is full in C?

Your heap will get full. But here, your program will exit, since you're breaking out of the while loop in case malloc() fails to allocate memory. In 1st case it will return null.


1 Answers

1.) How about .so file (Linux), is it the same case ?

Yes, a library built using a different implementation of the Standard C++ Library than the program it's finally linked with may do allocations in a slightly different manner. g++'s libstdc++ and clang++'s libc++ are examples of two different implementations. They may be 100% ABI compatible - but a third unknown library may not be.

2.) Is there anyway to make sure that application and library(.dll and .so) are using same heap memory manager or using same heap memory section ? So we can delete and new separately (new at .dll/.so, delete at application ).

No, what's compiled into the library is what will be used by the library, unless there's a way to initialize the library upon loading it, telling it to use a specific heap manager.

Please explain in details. I wish to know for .so (Linux), is it using only one heap manager for both application and .so (library). Let's said, my application compiled by compiler version A, while my .so complied by compiler version B, is it still ok ?

Because of the reason mentioned above, no, you can't be sure. Since you are the library creator you could however make your API so that the new and delete memory allocations/deallocations for types in your library are delegated to member functions compiled into the library, which in turn does the real allocations/deallocations (described in operator new, operator new[] and operator delete, operator delete[]). Pointers to objects of your types could then be newed and passed between the library and application and be deleted on either side.


Here's an (incomplete) example of how that could look using a class-specific allocation function:
void* T::operator new(std::size_t count);

and a class-specific usual deallocation function:
void T::operator delete(void* ptr);

It contains foo.hpp and foo.cpp used to create libfoo.so (or libfoo.a) and code for a program using the library.

foo.hpp

#pragma once

#include <new>

class Foo {
public:
    // The "usual" part of your class definition:
    Foo(int x);
    ~Foo();

    // This part does NOT get compiled into your library.
    // It'll only be used by users of your library:
#ifndef BUILDING_LIB
    // Note: operator new and delete are static by default

    // single object allocation/deallocation:
    void* operator new(std::size_t /* byte_count */) { return Alloc(); }
    void operator delete(void* addr) { Free(addr); }

    // array allocation/deallocation:
    // TODO: operator new[] and delete[]
#endif
private:
    int value;

    // the functions really doing the memory management
    static void* Alloc();
    static void Free(void* p);
};

foo.cpp

// Define BUILDING_LIB to disable the proxy operator new/delete functions when building
// the library.
#define BUILDING_LIB
#include "foo.hpp"

#include <cstdlib> // std::aligned_alloc
#include <iostream>

Foo::Foo(int x) : value(x) {
    std::cout << "Foo:Foo(" << value << ")\n";
}

Foo::~Foo() {
    std::cout << "Foo:~Foo() " << value << "\n";
}

void* Foo::Alloc() {
    void* addr = std::aligned_alloc(alignof(Foo), sizeof(Foo));
    std::cout << "Alloc() " << sizeof(Foo) << "\t@ " << addr << '\n';
    return addr;
}

void Foo::Free(void* addr) {
    std::cout << "Free()\t\t@ " << addr << '\n';
    std::free(addr);
}

uselib.cpp

#include "foo.hpp"

#include <memory>

int main() {
    auto a = std::make_unique<Foo>(123); // heap allocation

    // An automatic variable will use the applications memory manager and will not
    // use Alloc/Free.
    Foo b(456);
}

Possible output:

Alloc() 4       @ 0x1af7eb0
Foo:Foo(123)
Foo:Foo(456)
Foo:~Foo() 456
Foo:~Foo() 123
Free()          @ 0x1af7eb0
like image 139
Ted Lyngmo Avatar answered Nov 14 '22 23:11

Ted Lyngmo