Override libc functions without LD_PRELOAD - c++

I'm planning to implement my own malloc/free and I ran into some problems while trying to link my shared library with my executable.
Right now, I can get it to work with LD_PRELOAD, but not by linking the .so to the executable, although I can get similiar libraries, like tcmalloc, to work properly just by linking them to my executable, and would like to do the same.
I'm building everything with cmake, this is the CMakeLists of my shared library:
cmake_minimum_required(VERSION 2.8)
project(allocator)
add_library(allocator SHARED exports.cpp)
target_link_libraries(allocator dl)
target_compile_features(allocator PRIVATE cxx_range_for)
and this is exports.cpp:
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <dlfcn.h>
typedef void * (*MallocType)(size_t);
typedef void (*FreeType)(void *);
static bool g_initialized = false;
static MallocType real_malloc = nullptr;
static FreeType real_free = nullptr;
static void alloc_init(void)
{
real_malloc = (MallocType) dlsym(RTLD_NEXT, "malloc");
if (!real_malloc)
{
fprintf(stderr, "Error in `dlsym`: %s\n", dlerror());
}
real_free = (FreeType) dlsym(RTLD_NEXT, "free");
if (!real_free)
{
fprintf(stderr, "Error in `dlsym`: %s\n", dlerror());
}
g_initialized = true;
}
extern "C" void * malloc(size_t size)
{
if (!g_initialized)
{
alloc_init();
}
printf("Allocate %u.\n", size);
return real_malloc(size);
}
extern "C" void free(void *ptr)
{
if (!g_initialized)
{
alloc_init();
}
printf("Free %p.\n", ptr);
real_free(ptr);
}
As I said, trying to link the resulting .so to an executable doesn't really link the library (there's no entry in ldd, and libc malloc is called). I was wondering what am I doing wrong.
Edit:
I've also tried compiling with
g++ -o liballocator.so -shared exports.cpp -std=c++11 -fPIC -ldl
g++ -o test launcher.cpp memusage.cpp app.cpp -ldl -L. -lallocator -std=c++11

CMake isn't your tool of choice here. CMake creates makefiles or IDE project files for C source, and has a kind of working assumption that all the code is doing conventional things in conventional ways. That is no longer true if you have undertaken to provide your own malloc.
Most C compilers can be coaxed into linking a user-supplied version of malloc, often by playing about with the order of the link flags. But it is an error-prone process, since there might be indirect calls or submodules bound early. You can instantly solve all those problems by renaming malloc() mymalloc(), but then of course you must rewrite the client code.

Related

Lua: Cant open shared library when lua is wrapped in C++

EDIT: Nearly got the answer, I just dont completely understand it, see last paragraph.
I try to build a shared lua library and use it within a larger project. When calling the script which loads the shared library from shell everything works. However, when I wrap the script within another shell, I get a runtime error when loading the library. Dependent on the script it is just any call to a lua function from c (i.e. lua_pushnumber). Here is a minimal example.
totestlib.cpp:
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
int init(lua_State *L) {
lua_toboolean(L, -1);
return 0;
}
static const struct luaL_Reg testlib[] = {
{"init", init},
{NULL, NULL}
};
extern "C"
int luaopen_libtotestlib(lua_State *L) {
luaL_newlib(L, testlib);
return 1;
}
Compiled with: g++ -shared -fPIC -I./lua-5.4.4/src -L./lua-5.4.4/src totestlib.cpp -o libtotestlib.so
testlib.lua (testing shared library):
testlib.lua
print("start")
testlib = require("libtotestlib")
print("done")
testlib.init(true)
print("called")
Calling the lua script using ./lua-5.4.4/src/lua testlib.lua works. Everything is printed. Wrapping script in the following c++ code does not work:
call_testlib.cpp
extern "C" {
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}
#include <unistd.h>
static lua_State *L;
int main(int argc, char *argv[]) {
L = luaL_newstate();
luaL_openlibs(L);
int tmp = luaL_loadfile(L, "testlib.lua");
if(tmp != 0) {
return 1;
}
tmp = lua_pcall(L, 0, 0, 0);
if(tmp != 0) {
printf("error pcall\n");
return 1;
}
}
Compiled with g++ call_testlib.cpp -o ./call_testlib -I./lua-5.4.4/src -L./lua-5.4.4/src -llua it prints "error pcall". If I print the error message on the lua stack, I get:
string error loading module 'libtotestlib' from file './libtotestlib.so':
./libtotestlib.so: undefined symbol: luaL_checkversion_
In this case the undefined symbol is luaL_checkversion_ (which I dont call myself), but with other scripts it is usually the first lua_... function that I call.
I have tried several things to fix this. For example, linking -llua when compiling the shared library, but this does not work (and should not be the problem as calling the script itself works). I also tried to load preload the library from c++ (as done in this question) instead of from lua, but I guess it does not really make a difference and I am getting the same error. I also uninstalled all lua versions from my path to make sure I always use the same version.
What is the difference between calling the script directly from shell and calling it inside a c function? Am I doing something wrong?
EDIT: Nearly got the answer. When using MYCFLAGS= -fPIC when compiling lua I can link lua to the shared library. At least this one works, but does not seem like a good solution to me and does not really answer my question: Why can lua itself (from shell) somehow add these symbols to the library while the wrapped c version can not? Additionally, my program has lua once linked in the shared library and once in the compiled C++ project (not optimal imo).

Local dynamic library

Right off the bat, I want to say that I've never worked with dynamic libraries so It's possible that I don't even understand how they work properly.
I want to have a fully loaded code running and after some trigger (probably user interaction) I want to load a specific library and execute a function inside that library. Preferably close it afterwards. Essentially allowing me to change it and re-load it during run time.
This is the simple dynamic library (called dynlib.so located in the same directory as the main code):
int getInt(int arg_0)
{
return (arg_0 + 7);
}
And this is the main program:
#include <iostream>
#include <dlfcn.h>
int main() {
void *lib_handle = dlopen("./dynlib.so", RTLD_LAZY | RTLD_NOW);
if (!lib_handle) {
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
typedef int (*func_ptr)(int);
func_ptr func = (func_ptr)dlsym(lib_handle, "getInt");
std::cout << func(13);
dlclose(lib_handle);
}
I'm compiling it using: g++ -std=c++11 -ldl loadlibtest.cpp -o main.
The error I'm catching is ./libshared.so: file too short In my if (!lib_handle) {.
It works fine for me. I've compiled dynlib.so with
$ gcc dynlib.c -fPIC -shared -o dynlib.so
(Obviously, you need to either compile it as C or C++ with extern "C" to avoid name mangling).
and I needed to place -ldl after the source file in the g++ invocation.
gcc: 4.8.5; g++: 5.3.0
dlsym may fail too and casting from void* to function pointers is technically UB. You should base it on the usage snippet from the
manpage(modified for your function):
dlerror(); /* Clear any existing error */
/* Writing: func = (int (*)(int)) dlsym(handle, "getInt");
would seem more natural, but the C99 standard leaves
casting from "void *" to a function pointer undefined.
The assignment used below is the POSIX.1-2003 (Technical
Corrigendum 1) workaround; see the Rationale for the
POSIX specification of dlsym(). */
*(void **) (&func) = dlsym(handle, "getInt");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
exit(EXIT_FAILURE);
}
After some great replies I discovered what I'm doing wrong.
1) I wasn't using extern "C" for my library functions, so dlsym was unable to find the function.
2) I didn't know that dynamic libraries had to be compiled << pretty stupid of me.
I still want to know if there is a way to use uncompiled code as a library, but my initial problem was solved, thanks to everyone.

unresolved symbol __real_malloc while dynamically loading a library which is compiled with --wrap=malloc

As mentioned in other SO answers I am using the wrapping mechanism of GNU ld to intercept calls to malloc on Linux (see here for an example).
The used linker flag is -Wl,--wrap=malloc and the respective void __wrap_malloc(size_t) is also defined.
This works fine in a test application where all compilation unit are linked into the same binary.
Now, I need to modify a dynamically linked library which is loaded into a main program via dlopen().
Linking the library succeeds, but loading it into the main program fails with undefined symbol: __real_malloc.
Running nm on the library shows that __wrap_malloc is defined but __real_malloc is not.
But, according to man ld and this SO answer, malloc should get replaced with __wrap_malloc and __real_malloc should point to malloc when using this technique.
In the test application, I see that __real_malloc is undefined in the compiled object files but is resolved after getting linked into the executable.
So, why is the symbol resolved in the test application but not in the dynamic library?
In both cases a final link step is performed which should resolve this symbol.
Or is it required to add another library during the link step of the dynamic library in order to get __real_malloc resolved?
Just in case, it is not possible to modify the target application which loads the dynamic library via dlopen.
It should work and only requires slight changes to the code in the question you linked.
testapp.c
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
typedef void f_t(void);
int main()
{
void* h = dlopen("./malloc_wrapper.so", RTLD_NOW);
if (h == NULL)
{
puts(dlerror());
exit(1);
}
f_t* f = (f_t*)dlsym(h, "test");
if (f == NULL)
{
puts(dlerror());
exit(1);
}
(*f)();
return 0;
}
malloc_wrapper.c
#include <stdlib.h> /* added */
#include <stdio.h>
void *__real_malloc (size_t);
/* This function wraps the real malloc */
void *__wrap_malloc(size_t size)
{
void *lptr = __real_malloc(size);
printf("Malloc: %lu bytes #%p\n", size, lptr);
return lptr;
}
void test(void) /* added */
{
free(malloc(1024));
}
Compile and run.
gcc -Wl,-wrap,malloc -shared -fpic malloc_wrapper.c -o malloc_wrapper.so
gcc testapp.c -o testapp -ldl
./testapp
Malloc: 1024 bytes #0x1d44680
Compiling malloc_wrapper.so like this reproduces the error you describe:
gcc -shared -fpic malloc_wrapper.c -o malloc_wrapper.so
./testapp
./malloc_wrapper.so: undefined symbol: __real_malloc
Perhaps you were using wrap when compiling and linking the executable instead of the shared object?

dlopen a dynamic library from a static library linux C++

I've a linux application that links against a static library (.a) and that library uses the dlopen function to load dynamic libraries (.so)
If I compile the static library as dynamic and link it to the application, the dlopen it will work as expected, but if I use it as described above it won't.
Can't a static library uses the dlopen function to load shared libraries?
Thanks.
There should be no problem with what you're trying to do:
app.c:
#include "staticlib.h"
#include "stdio.h"
int main()
{
printf("and the magic number is: %d\n",doSomethingDynamicish());
return 0;
}
staticlib.h:
#ifndef __STATICLIB_H__
#define __STATICLIB_H__
int doSomethingDynamicish();
#endif
staticlib.c:
#include "staticlib.h"
#include "dlfcn.h"
#include "stdio.h"
int doSomethingDynamicish()
{
void* handle = dlopen("./libdynlib.so",RTLD_NOW);
if(!handle)
{
printf("could not dlopen: %s\n",dlerror());
return 0;
}
typedef int(*dynamicfnc)();
dynamicfnc func = (dynamicfnc)dlsym(handle,"GetMeANumber");
const char* err = dlerror();
if(err)
{
printf("could not dlsym: %s\n",err);
return 0;
}
return func();
}
dynlib.c:
int GetMeANumber()
{
return 1337;
}
and build:
gcc -c -o staticlib.o staticlib.c
ar rcs libstaticlib.a staticlib.o
gcc -o app app.c libstaticlib.a -ldl
gcc -shared -o libdynlib.so dynlib.c
First line builds the lib
second line packs it into a static lib
third builds the test app, linking in the newly created static, plus the linux dynamic linking library(libdl)
fourth line builds the soon-to-be-dynamically-loaded shared lib.
output:
./app
and the magic number is: 1337

Call a C++ function from a C++ library in Linux

I want to call a function from C++ library on linux. I have a shared object of that library.
I want to call method getAge() that return an int from ydmg library.
Following is the code that I have written:
testydmg.cpp
#include "ydmg/bd.h"
#include "yut/hash.h"
#include "dlfcn.h"
extern "C" int getAge();
class testydmg{
public:
testydmg::testydmg(const yutHash& user){
}
testydmg::testydmg(){
}
testydmg::~testydmg(){
}
int testydmg::getFunction(){
void *handle;
int (*voidfnc)();
handle = dlopen("ydmg.so",RTLD_LAZY);
if(handle == NULL){
printf("error in opening ydmg lib");
} else {
voidfnc = (int (*)())dlsym(handle, "getAge");
(*voidfnc)();
printf("class loaded");
}
ydmgBd obj;
obj.getAge();
printf("Inside getFunction()...");
dlclose(handle);
}
};
I compile and link the code as below:
gcc -fPIC -shared -l stdc++ -I/home/y/libexec64/jdk1.6.0/include -I/home/y/libexec64/jdk1.6.0/include/linux -I/home/y/include testydmg.cpp -o libTestYdmg.so libydmg.so
Then I check for the method in the new shared object i.e. libTestYdmg.so
nm -C libTestYdmg.so | egrep getAge
I get nothing by running the above command.
Does it mean that it did not get the method getAge() from the library.
Could you please correct where I am going wrong ?
You want to use ydmgDB::getAge() but you are asking to the library for getAge(). This is not correct, just simply create a ydmgDBobject and invoke it's method getAge() without loading the library that is linked with your compile command line.
You don't need to dlopen the library.
Besides, getAge is not really included in libTestYdmg.so. You must look for it in libydmg.so using:
nm -C libydmg.so | grep getAge
If you're interested in actually using dlopen in C++ code, take a look at the
C++ dlopen mini HOWTO, which includes example code and some possibly important
warnings.