Heap corruption when using make_shared - c++

I have a class with private member variable
shared_ptr<short> m_p_data;
I get heap corruption when I use this constructor:
Volume2D(const int dimX, const int dimY) :m_dimX{ dimX }, m_dimY{ dimY }, m_p_data{ make_shared<short>(dimX*dimY) } {
}
but there is no heap corruption if I do this instead:
Volume2D(const int dimX, const int dimY) :m_dimX(dimX), m_dimY(dimY) {
m_p_data.reset(new short[dimX*dimY]);
}
To be more specific, here is the code that corrupts the heap:
Volume2D vol(10, 1);
for (auto i = 0; i < 10; ++i) {
vol(i, 0) = i;
cout << "value = " << vol(i, 0) << endl;
}
return 0;

Both versions of your code are problematic.
The first version,
make_shared<short>(dimX*dimY)
creates a single heap-allocated short with the value dimX*dimY. It is apparent from the rest of your question, that your code later treats this logically as an array of dimension dimX*dimY, which is exactly what's causing the heap corruption (you only allocated a single short, but you're treating it like many).
The second version has the opposite problem. You're allocating dimX*dimY shorts, but, as far as your shared_ptr, it doesn't know that. So it doesn't have your heap corruption, but the shared_ptr destructor calls delete, not delete[] (even though you allocated with new[], not new).
For this case, its' unclear why you need a shared_ptr to begin with. Why not use std::vector<short>, or std::vector<std::vector<short>>?

Related

Allocating memory thorugh malloc for std::string array not working

I'm having trouble allocating memory on the heap for an array of strings. Allocating with new works but malloc segfaults each time. The reason I want to use malloc in the first place is that I don't want to call the constructor unnecessarily.
This works fine
std::string* strings = new std::string[6];
This doesn't
std::string* strings = (std::string *)malloc(sizeof(std::string[6]));
One thing I've noticed is that the first variant (using new) allocates 248 bytes of memory while the second allocates only 240. This 8 byte difference is constant no matter the size of the array from what I've gathered and I cannot find what the source of the difference is.
Here's the whole code that segfaults.
#include <iostream>
void* operator new(size_t size)
{
std::cout << size << std::endl;
return malloc(size);
}
void* operator new [](size_t size)
{
std::cout << size << std::endl;
return malloc(size);
}
int main() {
std::string* strings = new std::string[6];
strings = (std::string *)malloc(sizeof(std::string[6]));
strings[0] = std::string("test");
return 0;
}
Another thing I've noticed is that the above code seems to work if I use memset after malloc to set all of the bytes I allocated with malloc to 0. I don't understand where the 8 byte difference comes from if this works and also why this variant works at all. Why would it work just because I set all of the bytes to 0?
malloc() only allocates raw memory, but it does not construct any objects inside of that memory.
new and new[] both allocate memory and construct objects.
If you really want to use malloc() to create an array of C++ objects (which you really SHOULD NOT do!), then you will have to call the object constructors yourself using placement-new, and also call the object destructors yourself before freeing the memory, eg:
std::string* strings = static_cast<std::string*>(
malloc(sizeof(std::string) * 6)
);
for(int i = 0; i < 6; ++i) {
new (&strings[i]) std::string;
}
...
for(int i = 0; i < 6; ++i) {
strings[i].~std::string();
}
free(strings);
In C++11 and C++14, you should use std::aligned_storage to help calculate the necessary size of the array memory, eg:
using string_storage = std::aligned_storage<sizeof(std::string), alignof(std::string)>::type;
void *buffer = malloc(sizeof(string_storage) * 6);
std::string* strings = reinterpret_cast<std::string*>(buffer);
for(int i = 0; i < 6; ++i) {
new (&strings[i]) std::string;
}
...
for(int i = 0; i < 6; ++i) {
strings[i].~std::string();
}
free(buffer);
In C++17 and later, you should use std::aligned_alloc() instead of malloc() directly, eg:
std::string* strings = static_cast<std::string*>(
std::aligned_alloc(alignof(std::string), sizeof(std::string) * 6)
);
for(int i = 0; i < 6; ++i) {
new (&strings[i]) std::string;
}
...
for(int i = 0; i < 6; ++i) {
strings[i].~std::string();
}
std::free(strings);
Allocating via new means the constructor is run. Please always use new and delete with C++ classes (and std::string is a C++ class), whenever you can.
When you do malloc() / free(), only memory allocation is done, constructor (destructor) is not run. This means, the object is not initialized. Technically you might still be able to use placement new (i.e., new(pointer) Type) to initialize it, but it's better and more conformant to use classic new.
If you wanted to allocate multiple objects, that's what containers are for. Please use them. Multiple top-grade engineers work on std::vector<>, std::array<>, std::set<>, std::map<> to work and be optimal - it's very hard to beat them in performance, stability or other metrics and, even if you do, the next coder at the same company needs to learn into your specific data structures. So it's suggested not to use custom and locally implemented allocations where a container could be used, unless for a very strong reason (or, of course, didactic purposes).

C++ placement new, Invalid read and InvalidInvalid free() / delete / delete[] / realloc()

I'm experimenting the usage of placement new to try to understand how it works.
Executing the code below:
#include <iostream>
#define SHOW(x) std::cout << #x ": " << x << '\n'
template<typename T>
static T *my_realloc(T *ptr, size_t count) {
return (T *) realloc((void *) ptr, count * sizeof(T));
}
template<typename T>
static void my_free(T *ptr) {
free((T *) ptr);
}
int main() {
constexpr int count = 40;
int cap = 0;
int size = 0;
std::string *strs = nullptr;
auto tmp_str = std::string();
for(int i = 0; i < count; i++) {
tmp_str = std::to_string(i);
if(size == cap) {
if(cap == 0)
cap = 1;
else
cap *= 2;
strs = my_realloc(strs, cap);
}
new (&strs[size++]) std::string(std::move(tmp_str));
}
for(int i = 0; i < size; i++)
SHOW(strs[i]);
std::destroy_n(strs, size);
my_free(strs);
return 0;
}
I get the errors:
Invalid read of size 1
Invalid free() / delete / delete[] / realloc()
Removing the line
std::destroy_n(strs, size);
The error of invalid free is solved, but somehow all memory of the program is freed and no leaks are generated. But i can't find how the std::string destructor is called in the program.
If you want to store non-trivial types (such as std::string), then realloc simply cannot be used. You will find that standard library containers like e.g. std::vector will also not use it.
realloc may either extend the current allocation, without moving it in memory, or it might internally make a new allocation in separate memory and copy the contents of the old allocation to the new one. This step is performed as if by std::memcpy. The problem here is that std::memcpy will only work to actually create new objects implicitly in the new allocation and copy the values correctly if the type is trivially-copyable and if it and all of its subobjects are implicit-lifetime types. This definitively doesn't apply to std::string or any other type that manages some (memory) resource.
You are also forgetting to check the return value of realloc. If allocation failed, it may return a null pointer, which you will then use regardless, causing a null pointer dereference, as well as a memory leak of the old allocation.
Instead of using realloc you should make a new allocation for the new size, then placement-new copies of the objects already in the old allocation into the new one and then destroy the objects in the old allocation and free it.
If you want to guarantee that there won't be memory leaks when exceptions are thrown things become somewhat complicated. I suggest you look at the std::vector implementation of one of the standard library implementations if you want to figure out the details.
strs = my_realloc(strs, cap);
strs is a pointer to a std::string, and this will result in the contents of the pointer to be realloc()ed.
This is undefined behavior. C++ objects cannot be malloced, realloced, or freeed. Using a wrapper function, or placement new, at some point along the way, does not change that.
Everything from this point on is undefined behavior, and the resulting consequences are of no importance.

Vector of structs containing allocation pointers is failing to destruct

In my project I use a class for paged memory allocation.
This class uses a struct to store all of its allocations:
enum PageStatus : uint_fast8_t { //!< possible use stati of an allocated page
PAGE_STATUS_INVALID = 0b00,
PAGE_STATUS_FREE = 0b01, //!< the page is free
PAGE_STATUS_USED = 0b10, //!< the page is (partially) used
};
struct PhysicalPage { //!< represents a page that has been allocated
char* pData; //!< pointer to the allocation
PageStatus status; //!< status of the allocation
};
These PhysicalPages are stored in a vector std::vector<PhysicalPage> physicalAllocations {};.
During runtime pages are added to the vector and some may be removed. During the removal the last element is popped and the memory is returned using delete page.pData. However a problem occurs when the allocator class reaches end of life and gets deallocated from the stack. When pyhsicalAllocations's vector destructor is called it tries to destruct not only the elements themself but also the reserved memory (which the vector keeps as a buffer for when the size is changed). That causes invalid memory pointers to be deleted, stopping program execution:
double free or corruption (!prev)
Signal: SIGABRT (Aborted)
It's probably also worth mentioning that allocations are done in chunks larger than pages, which means that only one in every x pointers are actually valid allocations. All other pointers are just offsets from the actual memory locations.
To prevent the error from occurring I tried:
deleting manually (this is a bit overcomplicated due to chunked allocation)
for (size_t i = physicalAllocations.size(); 0 < i; i -= 1 << allocationChunkSize) {
delete physicalAllocations[i - (1 << allocationChunkSize)].pData;
for (size_t a = 0; a < 1 << allocationChunkSize; a++)
physicalAllocations.pop_back();
}
clearing the vector
physicalAllocations.clear();
swapping for a clear vector
std::vector<PhysicalPage>(0).swap(physicalAllocations);
of which none worked.
I've been working on this problem for a lot longer that I would like to admit and your help is very much appreciated. Thanks!
std::shared_ptr<char[]> pData and its aliasing constructor (8) might help. (that might even allow to get rid of PageStatus).
It would look something like:
constexpr std::size_t page_size = 6;
struct PhysicalPage {
std::shared_ptr<char[]> pData;
};
int main()
{
std::vector<PhysicalPage> pages;
{
std::shared_ptr<char[]> big_alloc = std::unique_ptr<char[]>(new char[42]{"hello world. 4 8 15 16 23 42"});
for (std::size_t i = 0; i != 42 / page_size; ++i) {
pages.push_back(PhysicalPage{std::shared_ptr<char[]>{big_alloc, big_alloc.get() + i * page_size}});
}
}
pages.erase(pages.begin());
pages.erase(pages.begin() + 2);
for (auto& p : pages) {
std::cout << std::string_view(p.pData.get(), page_size) << std::endl;
}
}
Demo

How to release the memory outside of a function if I forgot to release the memory before the function returns

my question can be briefly shown as the following example.
void func(int n){
char *p = (char*)malloc(n);
// some codes
memset(p,0,sizeof(name));
// free(p); // Commenting this line represents that I forget to release the allocated memory.
}
int main(){
// some codes
for (int i; i < Nl; i++){
func(100);
// How can I release the allocated memory of p outside of the func?
}
}
I whish to release the allocated memory, which is allocated in a function, outside of this function.
Thank you.
The pointer in question is not returned from the function in any way, so if you don't free it in the function then the memory is leaked. You would need to modify the function to either assign the pointer to a global, return it from the function, or assign it to a dereferenced pointer passed to the function.
If your goal is to find and fix memory leaks in your program, there are tools such as valgrind which can help you with that.
To solve the problem it's better to use std::unique_ptr. If you use smart pointer it will be released whenever it's not required anymore.
Foe example :
void my_func()
{
std::unique_ptr<int> valuePtr(new int(15));
int x = 45;
// ...
if (x == 45)
return; // no memory leak anymore!
// ...
}
You can check the link to study more :
https://en.cppreference.com/book/intro/smart_pointers
Two solutions in C
a) use VLA
void foo(int n) {
char p[n];
// use p
// no need to free, p automatically releases its memory
}
b) return the pointer to the caller
char *foo(int n) {
char *p = malloc(n);
// use p
return p;
}
int main(void) {
char *bar = foo(100);
free(bar);
}
If I understand you correctly, you are struggling with the basic concept of memory management.
Looking at your code you are malloc, which is a core C memory management aspect, although you tagged the question as C and C++. I can go into depth on why there ain't a thing like C/C++, though it's better explained here: https://cor3ntin.github.io/posts/c/
One of the elements C and C++ programmers disagree is the use of malloc, which is standard in C and and only used in exceptional cases in C++.
If we look from a C++ standpoint, I'd argue you should be learning it with a recent version. Here the answer is simple: use std::make_unique:
auto p = std::make_unique<char[]>(n);
Or in this case as you are trying to do something with strings, just use std::string. Trust me, doing so will prevent a lot of grief. Let me also remark that you often don't need memory allocations, more about that can be found here: https://stackoverflow.com/a/53898150/2466431
If you however ain't programming C++, you can use malloc. Here it is important to understand that every pointer returned by malloc ends up as an argument for free. (Exceptions on this ain't for beginners)
After you call free, you can't use what the pointer points to, not the value stored in the pointer. Calling free twice for the same pointer is also an issue.
Hence, unlike in the C++ code where the memory gets freed when no longer used. You need to keep detailed attention for this and call free.
In your function, uncommenting the free is the correct solution.
If you have the intention to let the data outlive the function call, you should be returning the pointer to the caller, this is than responsible for the ownership:
char * func(int n){
char *p = (char*)malloc(n);
// some codes
memset(p,0,sizeof(name));
return p;
}
int main(){
// some codes
for (int i; i < Nl; i++){
char *s = func(100);
free(s);
}
}
Let me show the same with the previously mentioned C++:
#include <memory>
std::unique_ptr<char[]> func(int n){
auto p = std::make_unique<char[]>(n);
// some codes
return p;
}
int main(){
// some codes
for (int i; i < Nl; i++){
auto s = func(100);
}
}
Or using std::string
#include <string>
std::string func(int n){
auto p = std::string(n, '\0');
// some codes
return p;
}
int main(){
// some codes
for (int i; i < Nl; i++){
auto s = func(100);
}
}

Returning an array pointer from a function in C/C++ without static integer

I'm going to write a piece of code (Function) that returns a pointer to an array.
but I don't know how to do that.
The code I wrote is :
int* prime_factor(int temp){
int ctr;
int *ret;
int i = 0;
while (temp != 1){
ctr = 2;
if (temp%ctr != 0){
ctr++;
}
else {
*(ret + i) = ctr;
temp /= ctr;
}
}
return ret;
}
I guess that there's a need to such the thing :
else {
ret = new int[1];
*(ret +i) = ctr;
temp /= ctr;
}
But as you know , implementation of this stuff needs to be deleted the memory that you have allocated , so we have to delete the memory outside of the function , so it going to be nonstandard function.
Indeed, i want to calculate the Prime factors of a number then return them out.
Any idea to do that ? I don't know what should I do to gain the goal.
thank you so much.
I see your question has also the tag C++ so, you could use C++. I don't really know what you mean with without static integer ....
Use vector.
#include <vector>
vector<int> prime_factor(int number)
{
int ctr = 2;
vector<int> factors;
while (number != 1)
{
if (number % ctr != 0)
ctr++;
else
{
factors.push_back(ctr);
number /= ctr;
}
}
return factors;
}
As you will be using the vector with integers it knows how to destroy ("delete") it self.
Example:
int main()
{
for (auto &x : prime_factor(20)) // C++11
{
cout << x << endl;
}
}
Output:
2
2
5
Yes, putting burden of deleting the array on user is not preferable. Here you would be better off using vector instead of plain array.
You can also pass array as an argument(created in the caller so that it would be more intuitive to use delete on that array) to this function.
The line *(ret + i) = ctr; will create a memory violation right away, since your ret pointer has no allocated memory pointing to. You nee do preallocate a memory for it, either statically (array declaration) in the code CALLING this function, and passing it to the function as a parameter, or dynamically (using malloc or similar) and then freeing it in some point. Dynamic allocation can be done either in the function itself or in the calling code. But again, free the memory afterwards.
int *ret;
In your case ret doesn't point to any memory location.You are trying to reference some unallocated memory location which might cause segmentation fault.
Just to show how to return a pointer and free it below is the example:
int *some()
{
int *ret = malloc(sizeof(int));
*ret = 10;
return ret;
}
int main()
{
int *p = some();
printf("%d\n",*p);
free(p);
}
"But as you know , implementation of this stuff needs to be deleted the memory that you have allocated , so we have to delete the memory outside of the function , so it going to be nonstandard function."
To avoid that dilemma c++ has introduced Dynamic memory management support.
Instead of using raw pointers like int* use one appropriate of
std::unique_ptr<int> (to transfer ownership)
std::shared_ptr<int> (to share ownership)
std::weak_ptr<int> (to share ownership, but not count as reference)
std::auto_ptr<int> (to transfer ownership "the old way")
Besides that, it looks like using a std::vector<int> would be much more appropriate, than using a simple int*. The std::vector<int> class also is purposed to release you from getting the dynamic memory management right on your own.