Skip to content

Commit 8a47793

Browse files
vtjnashKristofferC
authored andcommitted
ccall: report static compile-time load issues correctly (#34062)
* ccall: report static compile-time load issues correctly fix #34061 * add a test * Update ccall.jl
1 parent 8260059 commit 8a47793

File tree

3 files changed

+42
-58
lines changed

3 files changed

+42
-58
lines changed

src/ccall.cpp

Lines changed: 17 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
// Map from symbol name (in a certain library) to its GV in sysimg and the
66
// DL handle address in the current session.
7-
typedef StringMap<std::pair<GlobalVariable*,void*>> SymMapGV;
7+
typedef StringMap<GlobalVariable*> SymMapGV;
88
static StringMap<std::pair<GlobalVariable*,SymMapGV>> libMapGV;
99
#ifdef _OS_WINDOWS_
1010
static SymMapGV symMapExe;
@@ -43,85 +43,58 @@ lazyModule(Func &&func)
4343

4444
// Find or create the GVs for the library and symbol lookup.
4545
// Return `runtime_lib` (whether the library name is a string)
46-
// Optionally return the symbol address in the current session
47-
// when `symaddr != nullptr`.
4846
// The `lib` and `sym` GV returned may not be in the current module.
4947
template<typename MT>
5048
static bool runtime_sym_gvs(const char *f_lib, const char *f_name, MT &&M,
51-
GlobalVariable *&lib, GlobalVariable *&sym,
52-
void **symaddr=nullptr)
49+
GlobalVariable *&lib, GlobalVariable *&sym)
5350
{
54-
void *libsym = NULL;
5551
bool runtime_lib = false;
5652
GlobalVariable *libptrgv;
5753
SymMapGV *symMap;
5854
#ifdef _OS_WINDOWS_
5955
if ((intptr_t)f_lib == 1) {
6056
libptrgv = jlexe_var;
61-
libsym = jl_exe_handle;
6257
symMap = &symMapExe;
6358
}
6459
else if ((intptr_t)f_lib == 2) {
6560
libptrgv = jldll_var;
66-
libsym = jl_dl_handle;
6761
symMap = &symMapDl;
6862
}
6963
else
7064
#endif
7165
if (f_lib == NULL) {
7266
libptrgv = jlRTLD_DEFAULT_var;
73-
libsym = jl_RTLD_DEFAULT_handle;
7467
symMap = &symMapDefault;
7568
}
7669
else {
7770
std::string name = "ccalllib_";
7871
name += f_lib;
7972
runtime_lib = true;
80-
auto iter = libMapGV.find(f_lib);
81-
if (iter == libMapGV.end()) {
73+
auto &libgv = libMapGV[f_lib];
74+
if (libgv.first == NULL) {
8275
libptrgv = new GlobalVariable(*M, T_pint8, false,
8376
GlobalVariable::ExternalLinkage,
84-
NULL, name);
85-
auto &libgv = libMapGV[f_lib];
86-
libgv = std::make_pair(global_proto(libptrgv), SymMapGV());
87-
symMap = &libgv.second;
88-
libsym = jl_get_library(f_lib);
89-
assert(libsym != NULL);
90-
*jl_emit_and_add_to_shadow(libptrgv) = libsym;
77+
Constant::getNullValue(T_pint8), name);
78+
libgv.first = global_proto(libptrgv);
9179
}
9280
else {
93-
libptrgv = iter->second.first;
94-
symMap = &iter->second.second;
81+
libptrgv = libgv.first;
9582
}
83+
symMap = &libgv.second;
9684
}
97-
if (libsym == NULL) {
98-
libsym = *(void**)jl_get_globalvar(libptrgv);
99-
}
100-
assert(libsym != NULL);
10185

102-
GlobalVariable *llvmgv;
103-
auto sym_iter = symMap->find(f_name);
104-
if (sym_iter == symMap->end()) {
86+
GlobalVariable *&llvmgv = (*symMap)[f_name];
87+
if (llvmgv == NULL) {
10588
// MCJIT forces this to have external linkage eventually, so we would clobber
10689
// the symbol of the actual function.
10790
std::string name = "ccall_";
10891
name += f_name;
10992
name += "_";
11093
name += std::to_string(globalUnique++);
11194
llvmgv = new GlobalVariable(*M, T_pvoidfunc, false,
112-
GlobalVariable::ExternalLinkage, NULL, name);
95+
GlobalVariable::ExternalLinkage,
96+
Constant::getNullValue(T_pvoidfunc), name);
11397
llvmgv = global_proto(llvmgv);
114-
void *addr;
115-
jl_dlsym(libsym, f_name, &addr, 0);
116-
(*symMap)[f_name] = std::make_pair(llvmgv, addr);
117-
if (symaddr)
118-
*symaddr = addr;
119-
*jl_emit_and_add_to_shadow(llvmgv) = addr;
120-
}
121-
else {
122-
if (symaddr)
123-
*symaddr = sym_iter->second.second;
124-
llvmgv = sym_iter->second.first;
12598
}
12699

127100
lib = libptrgv;
@@ -218,7 +191,7 @@ static GlobalVariable *emit_plt_thunk(
218191
const AttributeList &attrs,
219192
CallingConv::ID cc, const char *f_lib, const char *f_name,
220193
GlobalVariable *libptrgv, GlobalVariable *llvmgv,
221-
void *symaddr, bool runtime_lib)
194+
bool runtime_lib)
222195
{
223196
PointerType *funcptype = PointerType::get(functype, 0);
224197
libptrgv = prepare_global_in(M, libptrgv);
@@ -237,8 +210,7 @@ static GlobalVariable *emit_plt_thunk(
237210
auto gname = funcName.str();
238211
GlobalVariable *got = new GlobalVariable(*M, T_pvoidfunc, false,
239212
GlobalVariable::ExternalLinkage,
240-
nullptr, gname);
241-
*jl_emit_and_add_to_shadow(got) = symaddr;
213+
ConstantExpr::getBitCast(plt, T_pvoidfunc), gname);
242214
BasicBlock *b0 = BasicBlock::Create(jl_LLVMContext, "top", plt);
243215
IRBuilder<> irbuilder(b0);
244216
Value *ptr = runtime_sym_lookup(irbuilder, funcptype, f_lib, f_name, plt, libptrgv,
@@ -274,6 +246,7 @@ static GlobalVariable *emit_plt_thunk(
274246
}
275247
}
276248
irbuilder.ClearInsertionPoint();
249+
277250
got = global_proto(got); // exchange got for the permanent global before jl_finalize_module destroys it
278251
jl_finalize_module(M, true);
279252

@@ -297,21 +270,19 @@ static Value *emit_plt(
297270
assert(!functype->isVarArg());
298271
GlobalVariable *libptrgv;
299272
GlobalVariable *llvmgv;
300-
void *symaddr;
301273
auto LM = lazyModule([&] {
302274
Module *m = new Module(f_name, jl_LLVMContext);
303275
jl_setup_module(m);
304276
return m;
305277
});
306-
bool runtime_lib = runtime_sym_gvs(f_lib, f_name, LM,
307-
libptrgv, llvmgv, &symaddr);
278+
bool runtime_lib = runtime_sym_gvs(f_lib, f_name, LM, libptrgv, llvmgv);
308279
PointerType *funcptype = PointerType::get(functype, 0);
309280

310281
auto &pltMap = allPltMap[attrs];
311282
auto key = std::make_tuple(llvmgv, functype, cc);
312283
GlobalVariable *&shadowgot = pltMap[key];
313284
if (!shadowgot) {
314-
shadowgot = emit_plt_thunk(LM.get(), functype, attrs, cc, f_lib, f_name, libptrgv, llvmgv, symaddr, runtime_lib);
285+
shadowgot = emit_plt_thunk(LM.get(), functype, attrs, cc, f_lib, f_name, libptrgv, llvmgv, runtime_lib);
315286
}
316287
else {
317288
// `runtime_sym_gvs` shouldn't have created anything in a new module

src/jitlayers.cpp

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -460,13 +460,13 @@ void JuliaOJIT::addModule(std::unique_ptr<Module> M)
460460
{
461461
#ifndef JL_NDEBUG
462462
// validate the relocations for M
463-
for (Module::iterator I = M->begin(), E = M->end(); I != E; ) {
464-
Function *F = &*I;
463+
for (Module::global_object_iterator I = M->global_object_begin(), E = M->global_object_end(); I != E; ) {
464+
GlobalObject *F = &*I;
465465
++I;
466466
if (F->isDeclaration()) {
467467
if (F->use_empty())
468468
F->eraseFromParent();
469-
else if (!(isIntrinsicFunction(F) ||
469+
else if (!((isa<Function>(F) && isIntrinsicFunction(cast<Function>(F))) ||
470470
findUnmangledSymbol(F->getName()) ||
471471
SectionMemoryManager::getSymbolAddressInProcess(
472472
getMangledName(F->getName())))) {
@@ -495,9 +495,10 @@ void JuliaOJIT::addModule(std::unique_ptr<Module> M)
495495
#endif
496496
// Force LLVM to emit the module so that we can register the symbols
497497
// in our lookup table.
498-
auto Err = CompileLayer.emitAndFinalize(key);
498+
Error Err = CompileLayer.emitAndFinalize(key);
499499
// Check for errors to prevent LLVM from crashing the program.
500-
assert(!Err);
500+
if (Err)
501+
report_fatal_error(std::move(Err));
501502
}
502503

503504
void JuliaOJIT::removeModule(ModuleHandleT H)
@@ -770,12 +771,15 @@ static void jl_merge_recursive(Module *m, Module *collector)
770771
// since the declarations may get destroyed by the jl_merge_module call.
771772
// this is also why we copy the Name string, rather than save a StringRef
772773
SmallVector<std::string, 8> to_finalize;
773-
for (Module::iterator I = m->begin(), E = m->end(); I != E; ++I) {
774-
Function *F = &*I;
774+
for (Module::global_object_iterator I = m->global_object_begin(), E = m->global_object_end(); I != E; ++I) {
775+
GlobalObject *F = &*I;
775776
if (!F->isDeclaration()) {
776777
module_for_fname.erase(F->getName());
777778
}
778-
else if (!isIntrinsicFunction(F)) {
779+
else if (isa<Function>(F) && !isIntrinsicFunction(cast<Function>(F))) {
780+
to_finalize.push_back(F->getName().str());
781+
}
782+
else if (isa<GlobalValue>(F) && module_for_fname.count(F->getName())) {
779783
to_finalize.push_back(F->getName().str());
780784
}
781785
}
@@ -838,11 +842,13 @@ void jl_finalize_module(Module *m, bool shadow)
838842
{
839843
// record the function names that are part of this Module
840844
// so it can be added to the JIT when needed
841-
for (Module::iterator I = m->begin(), E = m->end(); I != E; ++I) {
842-
Function *F = &*I;
845+
for (Module::global_object_iterator I = m->global_object_begin(), E = m->global_object_end(); I != E; ++I) {
846+
GlobalObject *F = &*I;
843847
if (!F->isDeclaration()) {
844-
bool known = incomplete_fname.erase(F->getName());
845-
(void)known; // TODO: assert(known); // llvmcall gets this wrong
848+
if (isa<Function>(F)) {
849+
bool known = incomplete_fname.erase(F->getName());
850+
(void)known; // TODO: assert(known); // llvmcall gets this wrong
851+
}
846852
module_for_fname[F->getName()] = m;
847853
}
848854
}

test/ccall.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1535,3 +1535,10 @@ let
15351535
@test isa(ptr, Ptr{Cvoid})
15361536
@test arr[1] == '0'
15371537
end
1538+
1539+
# issue #34061
1540+
o_file = tempname()
1541+
run(`$(Base.julia_cmd()) --output-o=$o_file -e 'Base.reinit_stdio();
1542+
f() = ccall((:dne, :does_not_exist), Cvoid, ());
1543+
precompile(f, ())'`)
1544+
@test isfile(o_file)

0 commit comments

Comments
 (0)