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.
Related
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;
}
}
}
I am learning classes and OOP, so I was doing some practice programs, when I came across the weirdest bug ever while programming.
So, I have the following files, beginning by my class "pessoa", located in pessoa.h:
#pragma once
#include <string>
#include <iostream>
using namespace std;
class pessoa {
public:
//constructor (nome do aluno, data de nascimento)
pessoa(string newname="asffaf", unsigned int newdate=1996): name(newname), DataN(newdate){};
void SetName(string a); //set name
void SetBornDate(unsigned int ); //nascimento
string GetName(); //get name
unsigned int GetBornDate();
virtual void Print(){}; // print
private:
string name; //nome
unsigned int DataN; //data de nascimento
};
Whose functions are defined in pessoa.cpp
#include "pessoa.h"
string pessoa::GetName ()
{
return name;
}
void pessoa::SetName(string a)
{
name = a;
}
unsigned int pessoa::GetBornDate()
{
return DataN;
}
void pessoa::SetBornDate(unsigned int n)
{
DataN=n;
}
A function, DoArray, declared in DoArray.h, and defined in the file DoArray.cpp:
pessoa** DoArray(int n)
{
pessoa* p= new pessoa[n];
pessoa** pointer= &p;
return pointer;
}
And the main file:
#include <string>
#include <iostream>
#include "pessoa.h"
#include "DoArray.h"
#include <cstdio>
using namespace std;
int main()
{
//pessoa P[10];
//cout << P[5].GetBornDate();
pessoa** a=DoArray(5);
cerr << endl << a[0][3].GetBornDate() << endl;
cerr << endl << a[0][3].GetName() << endl;
return 0;
}
The weird find is, if I comment one of the methods above, "GetBornDate" or GetName, and run, the non-commented method will run fine and as supposed. However, if both are not commented, then the first will run and the program will crash before the 2nd method.
Sorry for the long post.
Let's look into this function:
int *get()
{
int i = 0;
return &i;
}
what is the problem with it? It is returning pointer to a local variable, which does not exist anymore when function get() terminates ie it returns dangling pointer. Now your code:
pessoa** DoArray(int n)
{
pessoa* p= new pessoa[n];
return &p;
}
do you see the problem?
To clarify even more:
typedef pessoa * pessoa_ptr;
pessoa_ptr* DoArray(int n)
{
pessoa_ptr p= whatever;
return &p;
}
you need to understand that whatever you assign to p does not change lifetime of p itself. Pointer is the same variable as others.
I have encountered the following strange situation: I have managed to have a global static variable with two instances ... Is this normal or is this a bug in the compiler or is this a hidden realm of C++? The following reproduction is an extract from a larger project (where the behaviour is the same), obviously the names were changed to protect the culprit (and yes, I know there are memory leaks in this code).
Here comes the code:
// other.h
#ifndef _OTHER_H_
#define _OTHER_H_
struct other
{
long longer;
int inter;
char charer;
};
void dosomething();
#endif
And
// other.cpp
#include "other.h"
#include "util.h"
void dosomething()
{
other* something = alloc_mem(other, 4);
}
And
// util.h
#ifndef _UTIL_H_
#define _UTIL_H_
#include <memory.h>
#include <string>
#include "test_class.h"
template <class T> T* allocate(size_t count, const char* f, long l, const char* sth)
{
T* tmp = new T[count];
memset(tmp, 0, count * sizeof(T));
test_class<T*>::instance().throwIn(tmp, f, l, sth, count);
return tmp;
}
#define alloc_mem(type,count) allocate<type>(count, __FILE__, __LINE__, (char*)0)
#endif
And
// main.cpp
#include "other.h"
#include "util.h"
int main()
{
int* i = alloc_mem(int, 1);
int* i1 = alloc_mem(int, 20);
char* c = alloc_mem(char, 1);
dosomething();
int* i3 = alloc_mem(int, 1);
}
And the main part:
// test_class.h
#ifndef test_class_H
#define test_class_H
#include <stdlib.h>
#include <iostream>
#include <typeinfo>
#include <cxxabi.h>
static long int all_alloc = 0; // THIS will get linked in two times!
template <typename T>
class test_class
{
private:
test_class() {}
static test_class<T>* pinstance;
public:
~test_class() {}
static test_class& instance() {
if(pinstance == NULL) {
pinstance = new test_class();
}
return *pinstance;
}
void throwIn(T item, const char* file, long line, const char* _compiler, long count) {
int status;
char* s = abi::__cxa_demangle(typeid(T).name(), 0, 0, &status) ;
std::cout << "request:" << sizeof(T) * count << " bytes, type:" << s << " # "<<
file << ":" << line << " global_addr:" << &all_alloc << std::endl;
all_alloc += sizeof(T) * count ;
free(s);
std::cout<<"All memory:" << all_alloc << std::endl;
}
};
template <class T> test_class<T>* test_class<T>::pinstance = NULL;
#endif
So, you have to compile this as:
g++ main.cpp other.cpp -o test
and the run it, and:
$ ./test
request:8 bytes, type:int* # main.cpp:6 global_addr:0x6022d8
All memory:8
request:160 bytes, type:int* # main.cpp:7 global_addr:0x6022d8
All memory:168
request:8 bytes, type:char* # main.cpp:8 global_addr:0x6022d8
All memory:176
request:32 bytes, type:other* # other.cpp:6 global_addr:0x6022f8
All memory:32
request:8 bytes, type:int* # main.cpp:11 global_addr:0x6022d8
All memory:184
so, as I could see with a pretty big surprise, I have two global addresses for all_alloc... Indeed, nm -C test shows:
00000000006022d8 b all_alloc
00000000006022f8 b all_alloc
So, obviously the questions:
Why? How is this possible? Is there something allowing this kind of behaviour or is this a bug somewhere in the compiler or linker?
In this case, I don't think you want to declare your all_alloc static. In this case, it means that the linkage is internal. In your case, you get two copies since two files include the header.
If you remove static, then you will have two copies that clash, and result in a linker error. Which is not good.
I believe what you want to do is to change static to extern, then in one cpp file, define the variable and its value.
header:
extern long int all_alloc;
cpp:
long int all_alloc = 0;
This will provide one copy of all_alloc that is shared among your code.
When you have global variable it already has static duration, so static keyword means something different for it. As you have class definition in the file you define your global static variable I assume that is a header. Why it is bad idea to use static global variable in header and what you will get you can read here
So answer is: it is expected behavior and not a bug.
Are there known issues with passing linked lists from C code to C++?
I have a Qt dialogue that I'm adding to legacy C code. A Qt class (in a C++ library) calls a C library function, which returns a static pointer to a linked list. That list is created in the C library. For example:
C code:
typedef my_struct_s my_struct_t, *my_struct_p;
struct {
int some_data;
double some_more_data;
my_struct_p next;
} my_struct_s;
void create_list()
{
my_struct_p next;
SP_head = (my_struct_p) calloc(1, sizeof(my_struct_t));
next = (my_struct_p) calloc(1, sizeof(my_struct_t));
SP_head->some_data = 1;
next->some_data = 2;
SP_head->next = next;
}
static my_struct_p SP_head=(my_struct_p)0;
extern my_struct_p get_list() {
if(!SP_head)
create_list();
return SP_head;
}
C++ code:
myclass::do_something()
{
my_struct_p list = get_list();
for(my_struct_p ptr = list; ptr; ptr = ptr->next)
{
std::cout << ptr->value;
}
}
SP_head is valid and contains a bunch of entries when I obtain it. In my debugger I can see the next entries are populated and valid on return from the function get_list().
When I try to assign ptr=ptr->next, whether inside a for loop or at the end of a while loop or via a temporary pointer, the value is null. i.e
temp_ptr = ptr->next;
// temp_ptr is null
// but I can see ptr->next looks ok in a debugger
I've now changed the code to copy each element of the list into an array and return that array, and it works fine. Is this something to do with the stack and an incompatibility with C and C++, or just an indication that I have a memory problem somewhere else?
Of course, C++ is prepared to handle C, then you should assume that there are no incompatibility when the proper interface is used.
After all, there are many SW out there implemented in C and interfaced from C++. I'm using, for instance, SWI-Prolog - implemented in C - from Qt.
But to compile your code, I had to do several changes: here the bottom line
file my_list.h
#ifdef __cplusplus
extern "C" {
#endif
struct my_struct_s {
int some_data;
double some_more_data;
struct my_struct_s *next;
};
typedef struct my_struct_s my_struct_t, *my_struct_p;
void create_list();
extern my_struct_p get_list();
#ifdef __cplusplus
}
#endif
file my_list.c
#include "my_list.h"
#include <stdio.h>
#include <stdlib.h>
static my_struct_p SP_head=(my_struct_p)0;
void create_list()
{
my_struct_p next;
SP_head = (my_struct_p) calloc(1, sizeof(my_struct_t));
next = (my_struct_p) calloc(1, sizeof(my_struct_t));
SP_head->some_data = 1;
next->some_data = 2;
SP_head->next = next;
}
my_struct_p get_list() { return SP_head; }
file main.cpp
#include "my_list.h"
#include <iostream>
class myclass {
public:
void do_something()
{
my_struct_p list = get_list();
for(my_struct_p ptr = list; ptr; ptr = ptr->next)
std::cout << ptr->some_data << std::endl;
}
};
int main() {
create_list();
myclass c;
c.do_something();
}
now that compile and run:
g++ my_list.c main.cpp
./a.out
1
2
I'm getting a runtime error ("memory can't be written") that, after inspection through the debugger, leads to the warning in the tittle.
The headers are the following:
componente.h:
#ifndef COMPONENTE_H
#define COMPONENTE_H
using namespace std;
class componente
{
int num_piezas;
int codigo;
char* proovedor;
public:
componente();
componente(int a, int b, const char* c);
virtual ~componente();
virtual void print();
};
#endif // COMPONENTE_H
complement.h implementation
#include "Componente.h"
#include <string.h>
#include <iostream>
componente::componente()
{
num_piezas = 0;
codigo = 0;
strcpy(proovedor, "");
//ctor
}
componente::componente(int a = 0, int b = 0, const char* c = "")
{
num_piezas = a;
codigo = b;
strcpy(proovedor, "");
}
componente::~componente()
{
delete proovedor;//dtor
}
void componente::print()
{
cout << "Proovedor: " << proovedor << endl;
cout << "Piezas: " << num_piezas << endl;
cout << "Codigo: " << codigo << endl;
}
teclado.h
#ifndef TECLADO_H
#define TECLADO_H
#include "Componente.h"
class teclado : public componente
{
int teclas;
public:
teclado();
teclado(int a, int b, int c, char* d);
virtual ~teclado();
void print();
};
#endif // TECLADO_H
teclado.h implementation
#include "teclado.h"
#include <iostream>
teclado::teclado() : componente()
{
teclas = 0;//ctor
}
teclado::~teclado()
{
teclas = 0;//dtor
}
teclado::teclado(int a = 0, int b = 0, int c = 0, char* d = "") : componente(a,b,d)
{
teclas = c;
}
void teclado::print()
{
cout << "Teclas: " << teclas << endl;
}
The main method where I get the runtime error is the following:
#include <iostream>
#include "teclado.h"
using namespace std;
int main()
{
componente a; // here I have the breakpoint where I check this warning
a.print();
return 0;
}
BUT, if instead of creating an "componente" object, I create a "teclado" object, I don't get the runtime error. I STILL get the warning during debugging, but the program behaves as expected:
#include <iostream>
#include "teclado.h"
using namespace std;
int main()
{
teclado a;
a.print();
return 0;
}
This returns "Teclas = 0" plus the "Press any key..." thing.
Do you have any idea why the linker is having troube with this? It doesn't show up when I invoke the virtual function, but before, during construction.
Two errors that I can see:
strcpy(proovedor, ""); // No memory has been allocated to `proovedor` and
// it is uninitialised.
As it is uninitialised this could be overwriting anywhere in the process memory, so could be corrupting the virtual table.
You could change this to (in both constructors):
proovedor = strdup("");
Destructor uses incorrect delete on proovedor:
delete proovedor; // should be delete[] proovedor
As this is C++ you should considering using std::string instead of char*.
If you do not change to std::string then you need to either:
Implement a copy constructor and assignment operator as the default versions are incorrect if you have a member variable that is dynamically allocated, or
Make the copy constructor and assignment operator private to make it impossible for them to be used.
Another source of this same message is that gdb can get confused by not-yet-initialized variables. (This answers the question title, but not the OP's question, since a web search led me here looking for an answer.)
Naturally, you shouldn't have uninitialized variables, but in my case gdb attempts to show function local variables even before they are declared/initialized.
Today I'm stepping through another developer's gtest case and this message was getting dumped to output every time the debugger stopped. In this case, the variable in question was declared on ~line 245, but the function started on ~line 202. Every time I stopped the debugger between these lines, I received the message.
I worked around the issue by moving the variable declaration to the top of the function.
For reference, I am testing with gdb version 7.11.1 in QtCreator 4.1.0 and I compiled with g++ version 5.4.1