I have a shared library mod.so and it has a function getptr to return pointer to a dynamically allocated memory.It also has a function Unload which frees the memory which was allocated.
The main program loads this shared library at runtime and gets the pointer from getptr
function but when Unload function is called it gives me Segmentation Fault.
main.cpp
#include <iostream>
#include <dlfcn.h>
using namespace std;
int main()
{
void* module = dlopen("mod.so",RTLD_LAZY);
typedef int*(*func)();
typedef void(*func1)();
func f = (func)dlsym(module,"getptr");
func1 b = (func1)dlsym(module,"Unload");
int* p = f();
b();
}
mod.cpp
#include <iostream>
#include <vector>
using namespace std;
vector<int*> allocated;
extern "C"
{
int* getptr()
{
int* p = new int;
*p = 1024;
allocated.push_back(p);
return p;
}
void Unload()
{
for(auto e: allocated)
delete e;
}
}
The mod.cpp is compiled as:
g++ -shared mod.cpp -o mod.so -fPIC
dlopen("mod.so",RTLD_LAZY) returns NULL. Try this:
void* module = dlopen("./mod.so",RTLD_LAZY);
if (!module) {
fprintf(stderr, "error in dlopen: %s\n", dlerror());
return 1;
}
Edit: with this modification your code worked for me on Linux/amd64 with gcc-10.2
Mind you, should you call Unload twice, it would cause serious problems. Possible fix:
#include <iostream>
#include <vector>
using namespace std;
vector<int*> *allocated= NULL;
extern "C"
{
int* getptr()
{
if (!allocated) allocated= new vector<int *>();
int* p = new int;
*p = 1024;
allocated->push_back(p);
return p;
}
void Unload()
{
if (allocated) {
for(auto e: *allocated)
delete e;
delete allocated;
allocated= NULL;
}
}
}
Related
I have written a customized hash map, whose value contains an std::vector. And it caused core dump in real environment. There is a simplified example below. There are three questions:
Why vector size doesn't change to zero when I called the destruct function ~Value()? Does this program really release the memory allocated by vector before when I call the destruct function? And when I gdb attaches to this program, it's __M_start and __M_finish pointer still point to the same address.
Add1 and Add2 both have memory problems. Add1 won't call the construct function of vector, when I push_back int* to the vector of Value which has been erase before, it might be added to an illegal address. When I want to use the Add2 function to call the copy construct function, it might cause segment fault. Why it is still not working with Add2?
How should I change my program if I still want to use my customized map instead of std::map?
#include <iostream>
#include <functional>
#include <cstdlib>
#include <stdio.h>
#include <memory>
#include <vector>
#include <algorithm>
#include<iterator>
#include <map>
#include <iterator>
#include <limits>
#include <set>
using namespace std;
class Value
{
public:
// Value()
// {
// }
// Value(const Value &obj): stArr(obj.stArr)
// {
// cout<<"Call copy construct"<<endl;
// }
vector<int*> stArr;
};
class CustomMap
{
public:
// normal way
void Add1(int key, const Value& val)
{
stArrVal[key] = val;
}
// placement new
void Add2(int key, const Value& val)
{
new (&stArrVal[key]) Value(val);
// stArrVal[key] = val;
}
// void Add2(int key, const Value& val)
// {
// new (&stArrVal[key]) Value(val);
// }
void Erase(int key)
{
stArrVal[key].~Value();
// stArrVal[key].stArr.clear();
cout<<stArrVal[key].stArr.size()<<endl;
}
void Search(int key, Value *&pstVal)
{
pstVal = &stArrVal[key];
}
Value stArrVal[100];
};
void PrintValAddress(Value *pVal)
{
for (const auto & val : pVal->stArr)
{
cout<<&val<<", ";
}
cout<<endl;
}
int main()
{
vector<int> arr;
arr.push_back(1);
arr.push_back(3);
std::map<int, Value> stlMap;
CustomMap customMap;
Value* value = new Value();
Value* value2 = new Value();
int a = 1;
int b = 2;
int c = 3;
value->stArr.push_back(&a);
value->stArr.push_back(&b);
value->stArr.push_back(&c);
value2->stArr.push_back(&a);
value2->stArr.push_back(&b);
value2->stArr.push_back(&c);
// value2->stArr.push_back(&d);
stlMap.insert(pair<int, Value>(1, *value));
Value &stlV = stlMap[1];
Value *pstCusV = NULL;
customMap.Add1(1, *value);
customMap.Add2(2, *value);
customMap.Search(1, pstCusV);
PrintValAddress(pstCusV);
customMap.Search(2, pstCusV);
PrintValAddress(pstCusV);
// Release
customMap.Erase(1);
customMap.Erase(2);
// this line will cause segment fault.
// int* arr2 = new int[1024*1024];
customMap.Search(2, pstCusV);
// 1. still size 3
PrintValAddress(pstCusV);
// int* arr1 = new int[10];
customMap.Add1(1, *value2);
customMap.Add2(2, *value2);
customMap.Search(1, pstCusV);
PrintValAddress(pstCusV);
customMap.Search(2, pstCusV);
PrintValAddress(pstCusV);
return 0;
}
Output:
0xa14090, 0xa14098, 0xa140a0,
0xa14160, 0xa14168, 0xa14170,
3
3
0xa14160, 0xa14168, 0xa14170,
0xa14090, 0xa14098, 0xa140a0,
0xa14160, 0xa14168, 0xa14170,
Thanks a lot!
I supposed I do not have to link to a shared library when I use dlopen. However, in cmake target_link_libraries(main_dlopen dl) results in linker errors
main_dlopen.cpp.o: In function `main':
main_dlopen.cpp:25: undefined reference to `ntclass::init(char const*)'
etc...
If I use target_link_libraries(main_dlopen dl ntclass), where libntclass.so is my library, then everything is fine.
Is it really fine or am I missing something? As a background, I want to test non thread-safe libraries, as explained here, and expect that linking should be avoided with non thread-safe libs.
Partially answered myself below
A full example is below (used this as reference).
(shared library)
ntclass.h
#ifndef NTCLASS_H
#define NTCLASS_H
#include <cstddef>
class ntclass
{
private:
static char *sptr;
char *ptr;
public:
ntclass() : ptr(NULL) {}
~ntclass();
void init(const char* str);
void print();
};
typedef ntclass* create_t();
#endif // NTCLASS_H
ntclass.cpp
#include "ntclass.h"
#include <stdio.h>
#include <string.h>
#include <iostream>
char *gptr = NULL;
char *ntclass::sptr = NULL;
ntclass::~ntclass()
{
if (gptr)
{
delete[] gptr;
gptr = NULL;
}
if (sptr)
{
delete[] sptr;
sptr = NULL;
}
if (ptr)
{
delete[] ptr;
ptr = NULL;
}
}
void ntclass::init(const char* str)
{
int size = strlen(str)*sizeof(char);
gptr = new char[size];
memcpy(gptr, str, size);
sptr = new char[size];
memcpy(sptr, str, size);
ptr = new char[size];
memcpy(ptr, str, size);
}
void ntclass::print()
{
std::cout << "Global: " << gptr << std::endl;
std::cout << "Static: " << sptr << std::endl;
std::cout << "Normal: " << ptr << std::endl;
}
extern "C" ntclass *create()
{
return new ntclass();
}
(Main executable)
main_dlopen.cpp
#include <iostream>
#include "ntclass.h"
#include <dlfcn.h>
#include <stdlib.h>
using namespace std;
int main()
{
void *handle = dlopen("./libntclass.so", RTLD_NOW);
if (handle == NULL)
{
cerr << dlerror() << endl;
exit(-1);
}
create_t *createA = (create_t*) dlsym(handle, "create");
create_t *createB = (create_t*) dlsym(handle, "create");
ntclass *A = createA();
ntclass *B = createB();
A->init("A");
B->init("B");
A->print();
B->print();
delete A;
delete B;
return 0;
}
(cmake)
cmake_minimum_required(VERSION 2.8)
set( CMAKE_VERBOSE_MAKEFILE on )
set(CMAKE_BUILD_TYPE RelWithDebInfo)
add_library(ntclass SHARED ntclass.cpp)
add_executable(main_dlopen main_dlopen.cpp)
target_link_libraries(main_dlopen dl) # <-- Here is a problem
Partial answer:
I added keyword virtual for ntclass methods (init, print, ~ntclass) and it works fine now. Still, can anyone explain why is it needed?
Your "partial answer" is a correct fix. For explanations, see that nice answer about virtual keyword.
In short:
Until init method in ntclass is declared as virtual, expression
A->init("A")
uses definition of the method in that class (independent on which actual type object A has). And because this definition is absent in main_dlopen.cpp, linker generates the error.
With virtual keyword, resolution of init method is deffered to runtime, when actual type of A object will be known.
It seems this problem is the so-called dangling pointer problem. Basically I'm trying to parse a pointer into a function (that stores the pointer as a global variable) inside a class, and I want the pointer to be stored in that class and can be used now and then. So from inside the class, I can manipulate this pointer and its value which is outside of the class.
I simplified the code and re-created the situation as the following:
main.cpp
#include <iostream>
#include "class.h"
using namespace std;
void main() {
dp dp1;
int input = 3;
int *pointer = &input;
dp1.store(pointer);
dp1.multiply();
}
class.h
#pragma once
#include <iostream>
using namespace std;
class dp {
public:
void store(int *num); // It stores the incoming pointer.
void multiply(); // It multiplies whatever is contained at the address pointed by the incoming pointer.
void print();
private:
int *stored_input; // I want to store the incoming pointer so it can be used in the class now and then.
};
class.cpp
#include <iostream>
#include "class.h"
using namespace std;
void dp::store(int *num) {
*stored_input = *num;
}
void dp::multiply() {
*stored_input *= 10;
print();
}
void dp::print() {
cout << *stored_input << "\n";
}
There is no compile error but after running it, it crashes.
It says:
Unhandled exception thrown: write access violation.
this->stored_input was 0xCCCCCCCC.
If there is a handler for this exception, the program may be safely continued.
I pressed "break" and it breaks at the 7th line of class.cpp:
*stored_input = *num;
It is not a dangling pointer, but a not initialized, you probably want:
void dp::store(int *num) {
stored_input = num;
}
I wrote the below program to set a value (here it's 3) to some location at memory that is pointed by a pointer named p using a function named f() and print it in the main:
#include <iostream>
using namespace std;
void f(float* q)
{
q=new float;
*q=3;
}
int main()
{
float *p= nullptr;
f(p);
cout<<*p;
return 0;
}
But when I want to compile it, I receive this compile time error :
ap1019#sharifvm:~$ g++ myt.cpp
myt.cpp: In function âint main()â:
myt.cpp:12:11: error: ânullptrâ was not declared in this scope
float *p=nullptr;
^
ap1019#sharifvm:~$
What's wrong?
It seems that pointer literal nullptr is not supported by your compiler.
You may use null pointer constant instead. For example
float *p = 0;
But in any case your program is wrong. It has a memory leak because you store the address of the allocated memory in a local variable of function f that will be destroyed after exiting the function.
The program could look the following way
#include <iostream>
using namespace std;
void f( float **q)
{
*q = new float;
**q = 3;
}
int main()
{
float *p = 0;
f( &p );
cout << *p;
delete p;
return 0;
}
Or you could use reference to the pointer. For example
#include <iostream>
using namespace std;
void f( float * &q)
{
q = new float;
*q = 3;
}
int main()
{
float *p = 0;
f( p );
cout << *p;
delete p;
return 0;
}
nullptr is only supported from gcc-4.6 or later.
You can easily workaround that with a const void *nullptr=(void*)0;, but to avoid later problems with a gcc upgrade, I suggest to
upgrade your gcc (4.6 is quite old)
or don't use it.
It is only syntactic sugar, you don't need that.
The word null is not reserved by the C++ standard.
Use NULL instead.
#include <iostream>
#include <iterator>
using namespace std;
void print(int ia[])
{
int *p = begin(ia);
while(p != end(ia))
cout<<*p++<<'\t';
}
int main()
{
int ia[] = {1,2,3,4},i;
print(ia);
return 0;
}
P pointer to the first element in ia.
why it said"error: no matching function for call to 'begin(int*&)' c++"
thanks!:)
Because inside print(), the variable ia is a pointer, not an array. It doesn't make sense to call begin() on a pointer.
You are using the begin and end free functions on a pointer, that's not allowed.
You can do something similar with C++11's intializer_list
//g++ -std=c++0x test.cpp -o test
#include <iostream>
#include <iterator>
using namespace std;
void print(initializer_list<int> ia)
{
auto p = begin(ia);
while(p != end(ia))
cout<<*p++<<'\t';
}
int main()
{
print({1,2,3,4});
return 0;
}
As others pointed out, your array is decaying to a pointer. Decaying is historical artifact from C. To do what you want, pass array as reference and deduce array size:
template<size_t X>
void print(int (&ia)[X])
{
int *p = begin(ia);
while(p != end(ia))
cout<<*p++<<'\t';
}
print(ia);