Would anyone please explain this case: why I am facing 'double free' problem in this simple code?
void Rreceive (myclass){}
int main () {
myclass msg (1);
Rreceive(msg);
return 0;
}
where myclass is:
class myclass
{
private:
HeaderType header;
byte * text;
public:
myclass(int ID);
~myclass();
HeaderType getHeader();
byte * getText();
};
myclass::myclass(int ID){
header.mID = ID;
text = (byte *)malloc (10);
memset (text, '.', 10);
}
myclass::~myclass(){
free (text);
}
HeaderType myclass::getHeader(){
return header;
}
byte * myclass::getText(){
return text;
}
and HeaderType is:
typedef struct {
int mID;
}HeaderType;
The error is: *** glibc detected *** ./test: double free or corruption (fasttop): 0x0868f008 ***...
When you enter your Rreceive function you call the default copy constrcuctor which will not make a deep copy of your text pointer (in other words, he will just assign the pointer to the new copy).
When exiting the Rreceive scope you free (text) from the copied instance, which will point to the same memory address.
The you will try to free the same memory address again when exiting the scope of your main function.
Related
Guys I can't seem to do simple modification of a container object member stored in a vector. This member is an object itself. Both the container and its member are allocated on the stack. I think it is trying to deallocate a stack variable of the original name of the device when assigning a new one.
Please give me a clue on how to fix this while keeping variables allocated on the stack.
class Device{
public:
Device(string name):m_name(name)
{}
string getName(){
return m_name;
}
string setName(string newName){
m_name = newName;
}
private:
string m_name;
};
Then there is a Server that contains Devices:
class Server
{
public:
Device & getDevice(int i)
{
return devices.at(i);
}
void addDevice(Device && dev)
{
devices.push_back(dev);
}
private:
vector<Device> devices;
};
Here is how I test:
int main()
{
Server s{};
s.addDevice(Device{"ONE"});
s.addDevice(Device{"TWO"});
s.addDevice(Device{"THREE"});
cout<<s.getDevice(0).getName()<<endl;
s.getDevice(0).setName("XXX");
cout<<s.getDevice(0).getName()<<endl;
return 0;
}
What I am getting out is :
ONE
*** Error in `./a.out': double free or corruption (fasttop): 0x0000000000617c20 ***
Aborted (core dumped)
You need to fix your setName method, is not returning anything and is marked to return a string.
string setName(string newName)
{
m_name = newName;
return m_name; //this is missing in the original code
}
I would like to copy the address of an object to a buffer and typecast it back at some other point. I am unable to do it. A sample code is given below.
#include <iostream>
#include <cstring>
class MyClass
{
public:
MyClass(const int & i)
{
id = i;
}
~MyClass()
{
}
void print() const
{
std::cout<<" My id: "<<id<<std::endl;
}
private:
int id;
};
int main()
{
MyClass *myClass = new MyClass(10);
std::cout<<"myClass: "<<myClass<<std::endl;
myClass->print();
// Need to copy the address to a buffer and retrieve it later
char tmp[128];
// std::vector tmp(sizeof(myClass); // preferably, we may use this instead of the previous line, and use std::copy instead of memcpy
memcpy(tmp, myClass, sizeof(myClass));
// retreiving the pointer
MyClass* myClassPtr = (MyClass*) tmp;
std::cout<<"myClassPtr: "<<myClassPtr<<std::endl;
myClassPtr->print();
return 0;
}
In fact, the pointers gives different values, which is the source of the problem. What am I doing wrong here?
You are copying (a pointer-sized part of) the object itself, not the pointer. You should do:
memcpy(tmp, &myClass, sizeof(myClass));
and then back:
MyClass *ptr;
memcpy(&ptr, tmp, sizeof(ptr));
I'm trying to return pointer from function in derived class,
This is the code:
class A
class A {
protected:
C c;
public:
virtual void func(){
unsigned char *data;
int size=getData(data);
}
}
class B
class B : public A {
private:
int size;
public:
B(const C &_c) { c=_c; };
const int B::getData(unsigned char *data) const {
data=(unsigned char *)malloc(size);
memcpy(data,c.getMem(),size);
if(!data){
//err
}
return size;
}
class C
class C {
private:
unsigned char *mem;
public:
C(unsigned char *_mem) : mem(_mem);
const unsigned char *getMem() const { return mem; };
}
main.cpp
C c(...);
B *b=new B(c);
b->func();
The error I get when getData returns
(this=0x50cdf8, data=0x2 <error: Cannot access memory at address 0x2>, size=32)
Thanks.
In class A, the func() is worthless because:
1. size is not returned to the caller.
2. The pointer data is local to func and it's contents will disappear after the end of execution in func().
You don't need to return const int from a function. A function will return a copy of variables, so they are constant (copies).
Don't use malloc in C++, use operator new. The malloc function does not call constructors for objects.
Don't use new or malloc unless absolutely necessary. Usually, dynamic memory is for containers where their capacity is not known at compile time; or for objects that live beyond a function or statement block's execution time. If you must use dynamic memory, use a smart pointer (like boost::shared_ptr).
Use std::vector for dynamic arrays. It works; it's been tested; you don't have to write your own, including memory management.
You are passing data by value (a copy of the pointer). If you want to modify a pointer, pass it by reference or pass a pointer to the pointer; (what I call the address of the pointer).
Example:
void my_function(uint8_t * & p_data)
{
p_data = new uint8_t[512];
}
Or
void another_function(unsigned char * * pp_data)
{
*pp_data = new unsigned char [1024];
}
A much better solution:
void better_function(std::vector<uint8_t>& data)
{
data.reserve(64);
for (uint8_t i = 0; i < 64; ++i)
{
data[i] = i;
}
}
I have used pointers to create an array and then wrote a delete procedure in the destructor
class cBuffer{
private:
struct entry {
uint64_t key;
uint64_t pc;
};
entry *en;
public:
cBuffer(int a, int b, int mode)
{
limit = a;
dist = b;
md = mode;
en = new entry[ limit ];
for (int i=0; i<limit; i++) {
en[i].key = 0;
en[i].pc = 0;
}
};
~cBuffer() { delete [] en; }
...
}
In another class I use cBuffer like this:
class foo() {
cBuffer *buf;
foo()
{
buf = new cBuffer(gSize, oDist, Mode);
}
};
However, valgrind complains about the new operator
==20381== 16,906,240 bytes in 32 blocks are possibly lost in loss record 11,217 of 11,221
==20381== at 0x4A0674C: operator new[](unsigned long) (vg_replace_malloc.c:305)
==20381== by 0x166D92F8: cBuffer::cBuffer(int, int, int)
cBuffer *buf;
foo()
{
buf = new cBuffer(gSize, oDist, Mode);
}
You need to call
delete buf;
Since you explicitly called new
Your class foo will cause your leak, since you never delete the dynamically allocated cBuffer. The solution is simple: there's no need for dynamic allocation at all here.
class foo {
cBuffer buf; // An object, not a pointer
foo() : buf(gSize, oDist, Mode) {}
};
More generally, when you do need dynamic allocation, be careful that you always delete what you new. The most reliable way to do this is to use RAII types such as containers and smart pointers to manage all dynamic resources for you.
In C++ How to program there is a paragraph that say:
A common programming practice is to allocate dynamic memory, assign the address of
that memory to a pointer, use the pointer to manipulate the memory and deallocate the
memory with delete when the memory is no longer needed. If an exception occurs after
successful memory allocation but before the delete statement executes, a memory leak
could occur. The C++ standard provides class template unique_ptr in header to
deal with this situation.
Any on could introduce me a real example that exception occur and memory will leak like this post?
A bit more subtle example.
Take an naive implementation of a class that holds two dynamically allocated arrays:
struct Foo {
private:
int* first;
int* second;
public:
Foo()
: first(new int[10000])
, second(new int[10000])
{ }
void Bar() { throw 42; }
~Foo()
{
delete [] first;
delete [] second;
}
};
int main()
{
Foo f;
/* more code */
}
Now, if we get an exception because we call method Bar somewhere, everything's fine - the stack unwinding guarantess that f's destructor gets called.
But if we get a bad_alloc when initializing second, we leak the memory that first points to.
class MyClass
{
public:
char* buffer;
MyClass(bool throwException)
{
buffer = new char[1024];
if(throwException)
throw std::runtime_error("MyClass::MyClass() failed");
}
~MyClass()
{
delete[] buffer;
}
};
int main()
{
// Memory leak, if an exception is thrown before a delete
MyClass* ptr = new MyClass(false);
throw std::runtime_error("<any error>");
delete ptr;
}
int main()
{
// Memory leak due to a missing call to MyClass()::~MyClass()
// in case MyClass()::MyClass() throws an exception.
MyClass instance = MyClass(true);
}
See also: C++ : handle resources if constructors may throw exceptions (Reference to FAQ 17.4]
void func()
{
char *p = new char[10];
some_function_which_may_throw(p);
delete [] p;
}
If the call to some_function_which_may_throw(p) throws an exception we leak the memory pointed to by p.
Simple example
try {
int* pValue = new int();
if (someCondition) {
throw 42;
}
delete pValue;
} catch (int&) {
}
To have a less contrived example, I recently found this potential leak in my code when allocating nodes with a given allocator object.
std::unique_ptr<node,alloc_aware> allocate_new_node(allocator& al, const value_type^ v) {
char* buffer = al.allocate(sizeof(node)); //allocate memory
return std::unique_ptr<node>(al.construct(buffer, v),{al})); //construct
}
It's less obvious how to fix this because of the buffer, but with help I got it:
struct only_deallocate {
allocator* a;
size_type s;
only_deallocate(allocator& alloc, size_type size):a(&alloc), s(size) {}
template<class T> void operator()(T* ptr) {a->deallocate(ptr, s);}
operator alloc_aware() const {return alloc_aware(*a, s);}
};
std::unique_ptr<node,alloc_aware> allocate_new_node(allocator& al, const value_type& v) {
std::unique_ptr<node, only_deallocate> buf(alloc.allocate(sizeof(node)),{alloc, sizeof(node)});//allocate memory
alloc.construct(buf.get(), value);
return std::unique_ptr<node,alloc_aware>(std::move(buf));
}
Compiling Code here