Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix use-after-free bugs in debuginfo #45016

Merged
merged 24 commits into from
Apr 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ee13ca0
Move debuginfo global variables to the top of debuginfo.cpp
pchintalapudi Apr 17, 2022
463560a
Lock around codeinst_in_flight
pchintalapudi Apr 17, 2022
56040d6
Lock around jl_sysimg_vars
pchintalapudi Apr 17, 2022
dc4ce81
Lock around objfilemap
pchintalapudi Apr 17, 2022
d8bad04
wrap pthread functions in a struct
pchintalapudi Apr 17, 2022
65a6842
Move debuginfo threading resources to object registry
pchintalapudi Apr 17, 2022
ffba4c7
Move libc frame registration into jit object registry
pchintalapudi Apr 17, 2022
814929c
Rename object registry to debug info registry
pchintalapudi Apr 17, 2022
982df38
Scope debug info structs
pchintalapudi Apr 18, 2022
29ff6e8
Move JITDebugInfoRegistry to its own file
pchintalapudi Apr 18, 2022
aa898e5
Add debug info to the JIT
pchintalapudi Apr 18, 2022
d326db8
Fix build
pchintalapudi Apr 18, 2022
07eb7bf
Fix whitespace
pchintalapudi Apr 18, 2022
36cd1fe
Fix windows and analyzegc failures
pchintalapudi Apr 18, 2022
f0b06f8
Merge branch 'master' into pc/debuginfo
DilumAluthge Apr 18, 2022
95475b8
Address review comments
pchintalapudi Apr 18, 2022
488d69e
move getDebugIfoRegistry to debuginfo.cpp
pchintalapudi Apr 18, 2022
6040896
Mark getDebugInfoRegistry as not a safepoint
pchintalapudi Apr 18, 2022
6a25133
Mark many methods as not safepoints
pchintalapudi Apr 18, 2022
17b999e
Mark constructors as not safepoints
pchintalapudi Apr 18, 2022
70ae826
Mark destructors as not safepoints
pchintalapudi Apr 18, 2022
d411d0a
Add move constructors for user-supplied destructors
pchintalapudi Apr 18, 2022
834227e
Merge branch 'master' into pc/debuginfo
DilumAluthge Apr 19, 2022
d34c25c
Merge branch 'master' into pc/debuginfo
DilumAluthge Apr 19, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -274,25 +274,25 @@ $(BUILDDIR)/julia_flisp.boot: $(addprefix $(SRCDIR)/,jlfrontend.scm flisp/aliase

# additional dependency links
$(BUILDDIR)/codegen-stubs.o $(BUILDDIR)/codegen-stubs.dbg.obj: $(SRCDIR)/intrinsics.h
$(BUILDDIR)/aotcompile.o $(BUILDDIR)/aotcompile.dbg.obj: $(SRCDIR)/jitlayers.h $(SRCDIR)/codegen_shared.h
$(BUILDDIR)/aotcompile.o $(BUILDDIR)/aotcompile.dbg.obj: $(SRCDIR)/jitlayers.h $(SRCDIR)/codegen_shared.h $(SRCDIR)/debug-registry.h
$(BUILDDIR)/ast.o $(BUILDDIR)/ast.dbg.obj: $(BUILDDIR)/julia_flisp.boot.inc $(SRCDIR)/flisp/*.h
$(BUILDDIR)/builtins.o $(BUILDDIR)/builtins.dbg.obj: $(SRCDIR)/iddict.c $(SRCDIR)/builtin_proto.h
$(BUILDDIR)/codegen.o $(BUILDDIR)/codegen.dbg.obj: $(addprefix $(SRCDIR)/,\
intrinsics.cpp jitlayers.h intrinsics.h codegen_shared.h cgutils.cpp ccall.cpp abi_*.cpp processor.h builtin_proto.h)
$(BUILDDIR)/debuginfo.o $(BUILDDIR)/debuginfo.dbg.obj: $(addprefix $(SRCDIR)/,debuginfo.h processor.h)
intrinsics.cpp jitlayers.h debug-registry.h intrinsics.h codegen_shared.h cgutils.cpp ccall.cpp abi_*.cpp processor.h builtin_proto.h)
$(BUILDDIR)/debuginfo.o $(BUILDDIR)/debuginfo.dbg.obj: $(addprefix $(SRCDIR)/,debuginfo.h processor.h jitlayers.h debug-registry.h)
$(BUILDDIR)/disasm.o $(BUILDDIR)/disasm.dbg.obj: $(SRCDIR)/debuginfo.h $(SRCDIR)/processor.h
$(BUILDDIR)/dump.o $(BUILDDIR)/dump.dbg.obj: $(addprefix $(SRCDIR)/,common_symbols1.inc common_symbols2.inc builtin_proto.h serialize.h)
$(BUILDDIR)/gc-debug.o $(BUILDDIR)/gc-debug.dbg.obj: $(SRCDIR)/gc.h
$(BUILDDIR)/gc-pages.o $(BUILDDIR)/gc-pages.dbg.obj: $(SRCDIR)/gc.h
$(BUILDDIR)/gc.o $(BUILDDIR)/gc.dbg.obj: $(SRCDIR)/gc.h $(SRCDIR)/gc-alloc-profiler.h
$(BUILDDIR)/init.o $(BUILDDIR)/init.dbg.obj: $(SRCDIR)/builtin_proto.h
$(BUILDDIR)/interpreter.o $(BUILDDIR)/interpreter.dbg.obj: $(SRCDIR)/builtin_proto.h
$(BUILDDIR)/jitlayers.o $(BUILDDIR)/jitlayers.dbg.obj: $(SRCDIR)/jitlayers.h $(SRCDIR)/codegen_shared.h
$(BUILDDIR)/jitlayers.o $(BUILDDIR)/jitlayers.dbg.obj: $(SRCDIR)/jitlayers.h $(SRCDIR)/codegen_shared.h $(SRCDIR)/debug-registry.h
$(BUILDDIR)/jltypes.o $(BUILDDIR)/jltypes.dbg.obj: $(SRCDIR)/builtin_proto.h
$(build_shlibdir)/libllvmcalltest.$(SHLIB_EXT): $(SRCDIR)/codegen_shared.h $(BUILDDIR)/julia_version.h
$(BUILDDIR)/llvm-alloc-helpers.o $(BUILDDIR)/llvm-alloc-helpers.dbg.obj: $(SRCDIR)/codegen_shared.h $(SRCDIR)/llvm-pass-helpers.h $(SRCDIR)/llvm-alloc-helpers.h
$(BUILDDIR)/llvm-alloc-opt.o $(BUILDDIR)/llvm-alloc-opt.dbg.obj: $(SRCDIR)/codegen_shared.h $(SRCDIR)/llvm-pass-helpers.h $(SRCDIR)/llvm-alloc-helpers.h
$(BUILDDIR)/llvm-cpufeatures.o $(BUILDDIR)/llvm-cpufeatures.dbg.obj: $(SRCDIR)/jitlayers.h
$(BUILDDIR)/llvm-cpufeatures.o $(BUILDDIR)/llvm-cpufeatures.dbg.obj: $(SRCDIR)/jitlayers.h $(SRCDIR)/debug-registry.h
$(BUILDDIR)/llvm-final-gc-lowering.o $(BUILDDIR)/llvm-final-gc-lowering.dbg.obj: $(SRCDIR)/llvm-pass-helpers.h $(SRCDIR)/codegen_shared.h
$(BUILDDIR)/llvm-gc-invariant-verifier.o $(BUILDDIR)/llvm-gc-invariant-verifier.dbg.obj: $(SRCDIR)/codegen_shared.h
$(BUILDDIR)/llvm-julia-licm.o $(BUILDDIR)/llvm-julia-licm.dbg.obj: $(SRCDIR)/codegen_shared.h $(SRCDIR)/llvm-alloc-helpers.h $(SRCDIR)/llvm-pass-helpers.h
Expand Down
3 changes: 0 additions & 3 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8328,14 +8328,11 @@ char jl_using_oprofile_jitevents = 0; // Non-zero if running under OProfile
char jl_using_perf_jitevents = 0;
#endif

void jl_init_debuginfo(void);

extern "C" void jl_init_llvm(void)
{
jl_page_size = jl_getpagesize();
jl_default_debug_info_kind = (int) DICompileUnit::DebugEmissionKind::FullDebug;
jl_default_cgparams.generic_context = jl_nothing;
jl_init_debuginfo();

InitializeNativeTarget();
InitializeNativeTargetAsmPrinter();
Expand Down
183 changes: 183 additions & 0 deletions src/debug-registry.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
#include <llvm/ADT/StringMap.h>
#include <llvm/DebugInfo/DIContext.h>
#include <llvm/IR/DataLayout.h>

#include "julia_internal.h"
#include "processor.h"

#include <map>
#include <mutex>
#include <type_traits>

typedef struct {
const llvm::object::ObjectFile *obj;
llvm::DIContext *ctx;
int64_t slide;
} objfileentry_t;


// Central registry for resolving function addresses to `jl_method_instance_t`s and
// originating `ObjectFile`s (for the DWARF debug info).
//
// A global singleton instance is notified by the JIT whenever a new object is emitted,
// and later queried by the various function info APIs. We also use the chance to handle
// some platform-specific unwind info registration (which is unrelated to the query
// functionality).
class JITDebugInfoRegistry
{
public:
template<typename ResourceT>
struct Locked {

template<typename CResourceT>
struct Lock {
std::unique_lock<std::mutex> lock;
CResourceT &resource;

Lock(std::mutex &mutex, CResourceT &resource) JL_NOTSAFEPOINT : lock(mutex), resource(resource) {}
Lock(Lock &&) JL_NOTSAFEPOINT = default;
Lock &operator=(Lock &&) JL_NOTSAFEPOINT = default;

CResourceT &operator*() JL_NOTSAFEPOINT {
return resource;
}

const CResourceT &operator*() const JL_NOTSAFEPOINT {
return resource;
}

CResourceT *operator->() JL_NOTSAFEPOINT {
return &**this;
}

const CResourceT *operator->() const JL_NOTSAFEPOINT {
return &**this;
}

operator const CResourceT &() const JL_NOTSAFEPOINT {
return resource;
}

~Lock() JL_NOTSAFEPOINT = default;
};
private:

mutable std::mutex mutex;
ResourceT resource;
public:
typedef Lock<ResourceT> LockT;
typedef Lock<const ResourceT> ConstLockT;

Locked(ResourceT resource = ResourceT()) JL_NOTSAFEPOINT : mutex(), resource(std::move(resource)) {}

LockT operator*() JL_NOTSAFEPOINT {
return LockT(mutex, resource);
}

ConstLockT operator*() const JL_NOTSAFEPOINT {
return ConstLockT(mutex, resource);
}

~Locked() JL_NOTSAFEPOINT = default;
};

template<typename datatype>
struct jl_pthread_key_t {
static_assert(std::is_trivially_default_constructible<datatype>::value, "Invalid datatype for pthread key!");
static_assert(std::is_trivially_destructible<datatype>::value, "Expected datatype to be trivially destructible!");
static_assert(sizeof(datatype) == sizeof(void*), "Expected datatype to be like a void*!");
pthread_key_t key;

void init() JL_NOTSAFEPOINT {
if (pthread_key_create(&key, NULL))
jl_error("fatal: pthread_key_create failed");
}

operator datatype() JL_NOTSAFEPOINT {
return reinterpret_cast<datatype>(pthread_getspecific(key));
}

jl_pthread_key_t &operator=(datatype val) JL_NOTSAFEPOINT {
pthread_setspecific(key, reinterpret_cast<void*>(val));
return *this;
}

void destroy() JL_NOTSAFEPOINT {
pthread_key_delete(key);
}
};

struct sysimg_info_t {
uint64_t jl_sysimage_base;
jl_sysimg_fptrs_t sysimg_fptrs;
jl_method_instance_t **sysimg_fvars_linfo;
size_t sysimg_fvars_n;
};

struct libc_frames_t {
#if defined(_OS_DARWIN_) && defined(LLVM_SHLIB)
std::atomic<void(*)(void*)> libc_register_frame_{nullptr};
std::atomic<void(*)(void*)> libc_deregister_frame_{nullptr};

void libc_register_frame(const char *Entry) JL_NOTSAFEPOINT;

void libc_deregister_frame(const char *Entry) JL_NOTSAFEPOINT;
#endif
};
private:

struct ObjectInfo {
const llvm::object::ObjectFile *object = nullptr;
size_t SectionSize = 0;
ptrdiff_t slide = 0;
llvm::object::SectionRef Section{};
llvm::DIContext *context = nullptr;
};

template<typename KeyT, typename ValT>
using rev_map = std::map<KeyT, ValT, std::greater<KeyT>>;

typedef rev_map<size_t, ObjectInfo> objectmap_t;
typedef rev_map<uint64_t, objfileentry_t> objfilemap_t;

objectmap_t objectmap{};
rev_map<size_t, std::pair<size_t, jl_method_instance_t *>> linfomap{};

// Maintain a mapping of unrealized function names -> linfo objects
// so that when we see it get emitted, we can add a link back to the linfo
// that it came from (providing name, type signature, file info, etc.)
Locked<llvm::StringMap<jl_code_instance_t*>> codeinst_in_flight{};

Locked<sysimg_info_t> sysimg_info{};

Locked<objfilemap_t> objfilemap{};

static std::string mangle(llvm::StringRef Name, const llvm::DataLayout &DL) JL_NOTSAFEPOINT;

public:

JITDebugInfoRegistry() JL_NOTSAFEPOINT;
~JITDebugInfoRegistry() JL_NOTSAFEPOINT = default;

// Any function that acquires this lock must be either a unmanaged thread
// or in the GC safe region and must NOT allocate anything through the GC
// while holding this lock.
// Certain functions in this file might be called from an unmanaged thread
// and cannot have any interaction with the julia runtime
// They also may be re-entrant, and operating while threads are paused, so we
// separately manage the re-entrant count behavior for safety across platforms
// Note that we cannot safely upgrade read->write
uv_rwlock_t debuginfo_asyncsafe{};
jl_pthread_key_t<uintptr_t> debuginfo_asyncsafe_held{};
libc_frames_t libc_frames{};

void add_code_in_flight(llvm::StringRef name, jl_code_instance_t *codeinst, const llvm::DataLayout &DL) JL_NOTSAFEPOINT;
jl_method_instance_t *lookupLinfo(size_t pointer) JL_NOTSAFEPOINT;
void registerJITObject(const llvm::object::ObjectFile &Object,
std::function<uint64_t(const llvm::StringRef &)> getLoadAddress,
std::function<void*(void*)> lookupWriteAddress) JL_NOTSAFEPOINT;
objectmap_t& getObjectMap() JL_NOTSAFEPOINT;
void set_sysimg_info(sysimg_info_t info) JL_NOTSAFEPOINT;
Locked<sysimg_info_t>::ConstLockT get_sysimg_info() const JL_NOTSAFEPOINT;
Locked<objfilemap_t>::LockT get_objfile_map() JL_NOTSAFEPOINT;
};
Loading