free vs delete and would this leak?

This code was given to me, via wikipedia. see :http://www.cplusplus.com/forum/beginner/273703/
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
#include <stdlib.h>
#include <cxxabi.h>

int main() {
	const char *mangled_name = "_ZNK3MapI10StringName3RefI8GDScriptE10ComparatorIS0_E16DefaultAllocatorE3hasERKS0_";
	int status = -1;
	char *demangled_name = abi::__cxa_demangle(mangled_name, NULL, NULL, &status);
	printf("Demangled: %s\n", demangled_name);
	free(demangled_name);
	return 0;
}


I want to put it in a function that returns a string and use std::unique_ptr.

My problem is it's C code and it is using free. How does free know the size of the character array that demangle_name points to?
Or is there a problem with this code and it is only releasing the memory of one character pointer?

My question is would this leak and how should I use std::unique_ptr instead of a char*?

edit:

I found this on stackoverflow which answers some of my question, but not my major question does free know to free the whole buffer?
https://stackoverflow.com/questions/45022504/abi-cxa-demangle-why-buffer-needs-to-be-malloc-ed
Last edited on
The documentation for abi::__cxa_demangle() https://panthema.net/2008/0901-stacktrace-demangled/cxa_demangle.html says that the memory is allocated via malloc() if output_buffer is NULL. As malloc() is used, then free() is correct and will free all the allocated memory.

To put it in a function that returns a std::string (not tried),

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <cstdlib>
#include <cxxabi.h>
#include <string>

std::string demangle(const char* mangled_name)
{
	int status = -1;
	char* demangled_name = abi::__cxa_demangle(mangled_name, NULL, NULL, &status);
	std::string demangled(demangled_name);
	//printf("Demangled: %s\n", demangled_name)
	std::free(demangled_name);

	return demangled;
}


int main()
{
	const std::string demangled_name = demangle("_ZNK3MapI10StringName3RefI8GDScriptE10ComparatorIS0_E16DefaultAllocatorE3hasERKS0_");

	std::cout << "Demangled: " << demangled_name << '\n';
}

Last edited on
How does free know how much memory to free? does it check the length of a char* before it frees it?

I want to replace the char* with unique_ptr, it is just exercise to help me. The above function may work, but I'm not convinced it doesn't leak.
Last edited on
The CRT knows how much memory that free() should release. It frees the amount of memory that was allocated - there's no leakage. As malloc() is used by __cxa_demangle(), then free() must be used. See https://en.cppreference.com/w/cpp/memory/c/free
How does free know how much memory to free?

How does delete [] know how much to free?

The malloc()/free() and new/delete talk to different systems. It is those systems that keep the accounting of the (size of) memory blocks that they have handed out.

I want to replace the char* with unique_ptr, it is just exercise to help me.

The unique_ptr calls delete by default, so simply using it will be an error.
However, creating a unique_ptr with custom deleter that calls free() is possible. See https://en.cppreference.com/w/cpp/memory/unique_ptr/get_deleter

The above function may work, but I'm not convinced it doesn't leak.

Where can it leak?
The abi::__cxa_demangle allocates memory with malloc() and that allocated memory block is deallocated with free().

The constructor of std::string demangled allocates memory for the demangled name.
Ok, if that throws, then free() would not be called, but the entire program quits at that point (unless you catch and handle exceptions).

The space allocated by constructor of demangled will be deallocated by its destructor at the end of the function (or any other exit path), but before that the caller can copy the value.
How does free know how much memory to free?

Most compilers do it like this:
foo = new thing[100];

memory bytes:
{01 02 03 04 05 06 07 08} {09 10 11 12 ....}
^^^ 64 bit int for size of memory ^^^ you get 09 as the pointer
could be 32 bit etc ... but the same approach. its a fixed size, so delete just backs up that many bytes. You can try it: allocate something and back up 8 bytes (or 4 if on a 32 bit sys) and cast to integer and print it.

you can do it like this, for the above, then:
char * cp = (char*)(thing);
int size = *(int*)(&(cp[-8]));


free works the same way. The problem is that it may not be the exact offset; there could be more stuff in the pre-memory header block than just the size of it. Finding the size could take trial and error and may vary across compilers.
First of all thank you for all who answered this thread so far.

Just to make sure I understand, if a char* to an array buffer is created using malloc, the compiler ensures that when free is called on the that char* it will release all the memory associated with the array buffer.

Second, please look at this use of unique_ptr and tell me if it could be done better:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<iostream>
#include<cxxabi.h>
#include<memory>


std::string demangled(const char* mangled_name) {
    int status = -1;
    auto deleter=[&](char* p){free(p);};
    std::unique_ptr<char,decltype(deleter)>str(abi::__cxa_demangle(mangled_name, NULL, NULL, &status),deleter);

    return str.get();
}
    
int main() {

    const char *mangled_name = "_ZNK3MapI10StringName3RefI8GDScriptE10ComparatorIS0_E16DefaultAllocatorE3hasERKS0_";
    std::cout << demangled(mangled_name) << '\n';
    return 0;

}



And last how do I return this unique_ptr? Or can I return it?
Last edited on
Figure out how to return a unique_ptr, but I'll still leave this here in case there is a mistake I didn't see.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<iostream>
#include<cxxabi.h>
#include<memory>

struct unique_free{
    void operator()(char* p) {free(p);}
};

auto demangled(const char* mangled_name) {

    int status = -1;
    return std::unique_ptr<char,unique_free>(abi::__cxa_demangle(mangled_name, NULL, NULL, &status),unique_free());

}
    
int main() {

    const char *mangled_name = "_ZNK3MapI10StringName3RefI8GDScriptE10ComparatorIS0_E16DefaultAllocatorE3hasERKS0_";
    std::cout << demangled(mangled_name).get() << '\n';

    return 0;

}
Last edited on
Why don't you use the example from seeplus - first answer?
It's the simplest and easiest solution and also follows the KISS principle.
There is no need for unique_ptr.
Because this was an exercise for me in how to use unique_ptr. In every way I can imagine needing to demangle names, whether the program leaked or not, is immaterial.

I learned quite a bit this morning. I learned that while mixing delete and free on Linux is usually not important it can be a serious problem with other operating systems.

I learned to use valgrind so I can test for memory leaks.

I learned how to create an unique_ptr that with a custom deleter, and how to return a unique_ptr. I can I imagine that I'll use this information when I use the sqlite library.

Today was a total win for me.

I don't know how other people post questions, but I often simplify my problems before I post. Doing that I get better answers. Occasionally you get, "why don't you do it this way instead", but I always thank those people, even if their answer wasn't what I needed. You never know when you'll need help and it is best not to offend.
Last edited on
Topic archived. No new replies allowed.