Commit 7b270cf9 authored by Marius Wachtler's avatar Marius Wachtler

Register the data segment of loaded shared libraries

before we only registered BSS data (aka static vars without initalizer) now we also register static vars with initalizer.
CFFI (and probably other libraries) needs this.
parent ac69cfef
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "runtime/import.h" #include "runtime/import.h"
#include <dlfcn.h> #include <dlfcn.h>
#include <fstream>
#include <limits.h> #include <limits.h>
#include "llvm/Support/FileSystem.h" #include "llvm/Support/FileSystem.h"
...@@ -783,6 +784,63 @@ Box* impLoadDynamic(Box* _name, Box* _pathname, Box* _file) { ...@@ -783,6 +784,63 @@ Box* impLoadDynamic(Box* _name, Box* _pathname, Box* _file) {
return importCExtension(name, shortname, pathname->s()); return importCExtension(name, shortname, pathname->s());
} }
// Parses the memory map and registers all memory regions with "rwxp" permission and which contain the requested file
// path with the GC. In addition adds the BSS segment.
static void registerDataSegment(void* dl_handle, llvm::StringRef lib_path) {
std::ifstream mapmap("/proc/self/maps");
std::string line;
llvm::SmallVector<std::pair<uint64_t, uint64_t>, 4> mem_ranges;
while (std::getline(mapmap, line)) {
// format is:
// address perms offset dev inode pathname
llvm::SmallVector<llvm::StringRef, 6> line_split;
llvm::StringRef(line).split(line_split, " ", 5, false);
RELEASE_ASSERT(line_split.size() >= 5, "%zu", line_split.size());
if (line_split.size() < 6)
continue; // pathname is missing
llvm::StringRef permissions = line_split[1].trim();
llvm::StringRef pathname = line_split[5].trim();
if (permissions == "rwxp" && pathname.endswith(lib_path)) {
llvm::StringRef mem_range = line_split[0].trim();
auto mem_range_split = mem_range.split('-');
uint64_t lower_addr = 0;
bool error = mem_range_split.first.getAsInteger(16, lower_addr);
RELEASE_ASSERT(!error, "");
uint64_t upper_addr = 0;
error = mem_range_split.second.getAsInteger(16, upper_addr);
RELEASE_ASSERT(!error, "");
RELEASE_ASSERT(lower_addr < upper_addr, "");
RELEASE_ASSERT(upper_addr - lower_addr < 1000000,
"Large data section detected - there maybe something wrong");
mem_ranges.emplace_back(lower_addr, upper_addr);
}
}
RELEASE_ASSERT(mem_ranges.size() >= 1, "");
uintptr_t bss_start = (uintptr_t)dlsym(dl_handle, "__bss_start");
uintptr_t bss_end = (uintptr_t)dlsym(dl_handle, "_end");
RELEASE_ASSERT(bss_end - bss_start < 1000000, "Large BSS section detected - there maybe something wrong");
// most of the time the BSS section is inside one of memory regions, in that case we don't have to register it.
bool should_add_bss = true;
for (auto r : mem_ranges) {
if (r.first <= bss_start && bss_end <= r.second)
should_add_bss = false;
gc::registerPotentialRootRange((void*)r.first, (void*)r.second);
}
if (should_add_bss) {
// only track void* aligned memory
bss_start = (bss_start + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1);
bss_end -= bss_end % sizeof(void*);
gc::registerPotentialRootRange((void*)bss_start, (void*)bss_end);
}
}
BoxedModule* importCExtension(BoxedString* full_name, const std::string& last_name, const std::string& path) { BoxedModule* importCExtension(BoxedString* full_name, const std::string& last_name, const std::string& path) {
void* handle = dlopen(path.c_str(), RTLD_NOW); void* handle = dlopen(path.c_str(), RTLD_NOW);
if (!handle) { if (!handle) {
...@@ -805,13 +863,7 @@ BoxedModule* importCExtension(BoxedString* full_name, const std::string& last_na ...@@ -805,13 +863,7 @@ BoxedModule* importCExtension(BoxedString* full_name, const std::string& last_na
assert(init); assert(init);
// Let the GC know about the static variables. // Let the GC know about the static variables.
uintptr_t bss_start = (uintptr_t)dlsym(handle, "__bss_start"); registerDataSegment(handle, path);
uintptr_t bss_end = (uintptr_t)dlsym(handle, "_end");
RELEASE_ASSERT(bss_end - bss_start < 1000000, "Large BSS section detected - there maybe something wrong");
// only track void* aligned memory
bss_start = (bss_start + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1);
bss_end -= bss_end % sizeof(void*);
gc::registerPotentialRootRange((void*)bss_start, (void*)bss_end);
char* packagecontext = strdup(full_name->c_str()); char* packagecontext = strdup(full_name->c_str());
char* oldcontext = _Py_PackageContext; char* oldcontext = _Py_PackageContext;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment