-
Notifications
You must be signed in to change notification settings - Fork 937
Description
Describe the bug
Async-Profiler only patches libraries to track malloc calls if & only if it's started in nativemem profiling mode
Furthermore async-profiler keeps record of all found libs in it's own local cache of CodeCacheArray
This behaviour makes it possible to have a library inside CodeCacheArray but that library isn't patched to track malloc calls
Due to these optimization choices it's possible for the async-profiler to try to patch for nativemem profiling after it's unloaded from memory
Expected vs. actual behavior
async-profiler shouldn't crash on native memory profiling
Reproduction Steps
Create the following C/C++ file
- main.cpp
#include <dlfcn.h>
#include <iostream>
#include <pthread.h>
#include "asprof.h"
#define ASSERT_NO_DLERROR() \
err = dlerror(); \
if (err != NULL) { \
printf("ERROR => %s\n", err); \
exit(1); \
}
#define ASSERT_NO_ASPROF_ERR(err) \
if (err != NULL) { \
fprintf(stderr, "%s\n", _asprof_error_str(err)); \
exit(1); \
}
typedef void* (*my_malloc_t)(size_t);
typedef void (*my_free_t)(void*);
void outputCallback(const char* buffer, size_t size) {
fwrite(buffer, sizeof(char), size, stdout);
}
int main() {
void* lib;
char* err;
lib = dlopen("my_lib.so", RTLD_NOW | RTLD_GLOBAL);
ASSERT_NO_DLERROR();
printf("dlopen => %p\n", lib);
my_malloc_t local_malloc = (my_malloc_t) dlsym(lib, "my_malloc");
ASSERT_NO_DLERROR();
my_free_t local_free = (my_free_t) dlsym(lib, "my_free");
ASSERT_NO_DLERROR();
void* libprof = dlopen("libasyncProfiler.so", RTLD_NOW);
ASSERT_NO_DLERROR();
((asprof_init_t)dlsym(libprof, "asprof_init"))();
ASSERT_NO_DLERROR();
asprof_execute_t _asprof_execute = (asprof_execute_t)dlsym(libprof, "asprof_execute");
ASSERT_NO_DLERROR();
asprof_error_str_t _asprof_error_str = (asprof_error_str_t)dlsym(libprof, "asprof_error_str");
ASSERT_NO_DLERROR();
asprof_error_t asprof_err = _asprof_execute("start,nativemem,cstack=dwarf,file=output.jfr", outputCallback);
ASSERT_NO_ASPROF_ERR(asprof_err);
local_free(local_malloc(1001));
asprof_err = _asprof_execute("stop", outputCallback);
ASSERT_NO_ASPROF_ERR(asprof_err);
dlclose(lib);
lib = dlopen("my_lib_1.so", RTLD_NOW | RTLD_GLOBAL);
local_malloc = (my_malloc_t) dlsym(lib, "my_malloc");
ASSERT_NO_DLERROR();
local_free = (my_free_t) dlsym(lib, "my_free");
ASSERT_NO_DLERROR();
asprof_err = _asprof_execute("start,cstack=dwarf,file=output2.jfr", outputCallback);
ASSERT_NO_ASPROF_ERR(asprof_err);
local_free(local_malloc(1010));
asprof_err = _asprof_execute("stop", NULL);
ASSERT_NO_ASPROF_ERR(asprof_err);
dlclose(lib);
asprof_err = _asprof_execute("start,nativemem,cstack=dwarf,file=output3.jfr", outputCallback);
ASSERT_NO_ASPROF_ERR(asprof_err);
asprof_err = _asprof_execute("stop", NULL);
ASSERT_NO_ASPROF_ERR(asprof_err);
}
- lib.h
#ifndef MYLIB_H
#define MYLIB_H
#define EXPORT __attribute__((visibility("default")))
#include "stdlib.h"
EXPORT void* my_malloc(size_t size);
EXPORT void my_free(void* ptr);
#endif
- lib.c
#include "lib.h"
EXPORT void* my_malloc(size_t size) {
return malloc(size);
}
EXPORT void my_free(void* ptr) {
free(ptr);
}
Compile the files
- g++ -I${PATH_TO_ASYNC_PROFILER_SRC_DIR} main.cpp -o main -ldl -lpthread -g
- gcc -fPIC lib.c -shared -o my_lib_1.so
- gcc -fPIC lib.c -shared -o my_lib.so
Run the test:
- LD_LIBRARY_PATH=
pwd:${PATH_TO_ASYNC_PROFILER_LIB_DIR}./main
Additional Information/Context
PATH_TO_ASYNC_PROFILER_LIB_DIR ==> points to the directory containing the async-profiler so file
PATH_TO_ASYNC_PROFILER_SRC_DIR ==> points to the directory containing asprof.h file
Async-profiler version
latest
Environment details
No response