Skip to content

Commit 8f78a94

Browse files
Pangorawvtjnash
andauthored
throw runtime TypeError on invalid ccall symbol (JuliaLang#49142)
Throw runtime `TypeError` on invalid ccall or cglobal symbol, rather than throwing an internal compilation error. Closes JuliaLang#49141 Closes JuliaLang#45187 Co-authored-by: Jameson Nash <vtjnash@gmail.com>
1 parent bc33c81 commit 8f78a94

File tree

4 files changed

+57
-22
lines changed

4 files changed

+57
-22
lines changed

src/ccall.cpp

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ static void typeassert_input(jl_codectx_t &ctx, const jl_cgval_t &jvinfo, jl_val
516516
ctx.builder.CreateCondBr(istype, passBB, failBB);
517517

518518
ctx.builder.SetInsertPoint(failBB);
519-
emit_type_error(ctx, mark_julia_type(ctx, vx, true, jl_any_type), boxed(ctx, jlto_runtime), msg);
519+
just_emit_type_error(ctx, mark_julia_type(ctx, vx, true, jl_any_type), boxed(ctx, jlto_runtime), msg);
520520
ctx.builder.CreateUnreachable();
521521
ctx.builder.SetInsertPoint(passBB);
522522
}
@@ -568,8 +568,15 @@ typedef struct {
568568
jl_value_t *gcroot;
569569
} native_sym_arg_t;
570570

571+
static inline const char *invalid_symbol_err_msg(bool ccall)
572+
{
573+
return ccall ?
574+
"ccall: first argument not a pointer or valid constant expression" :
575+
"cglobal: first argument not a pointer or valid constant expression";
576+
}
577+
571578
// --- parse :sym or (:sym, :lib) argument into address info ---
572-
static void interpret_symbol_arg(jl_codectx_t &ctx, native_sym_arg_t &out, jl_value_t *arg, const char *fname, bool llvmcall)
579+
static void interpret_symbol_arg(jl_codectx_t &ctx, native_sym_arg_t &out, jl_value_t *arg, bool ccall, bool llvmcall)
573580
{
574581
Value *&jl_ptr = out.jl_ptr;
575582
void (*&fptr)(void) = out.fptr;
@@ -599,9 +606,7 @@ static void interpret_symbol_arg(jl_codectx_t &ctx, native_sym_arg_t &out, jl_va
599606
jl_cgval_t arg1 = emit_expr(ctx, arg);
600607
jl_value_t *ptr_ty = arg1.typ;
601608
if (!jl_is_cpointer_type(ptr_ty)) {
602-
const char *errmsg = !strcmp(fname, "ccall") ?
603-
"ccall: first argument not a pointer or valid constant expression" :
604-
"cglobal: first argument not a pointer or valid constant expression";
609+
const char *errmsg = invalid_symbol_err_msg(ccall);
605610
emit_cpointercheck(ctx, arg1, errmsg);
606611
}
607612
arg1 = update_julia_type(ctx, arg1, (jl_value_t*)jl_voidpointer_type);
@@ -647,19 +652,14 @@ static void interpret_symbol_arg(jl_codectx_t &ctx, native_sym_arg_t &out, jl_va
647652
f_name = jl_symbol_name((jl_sym_t*)t0);
648653
else if (jl_is_string(t0))
649654
f_name = jl_string_data(t0);
650-
else
651-
JL_TYPECHKS(fname, symbol, t0);
652655

653656
jl_value_t *t1 = jl_fieldref(ptr, 1);
654657
if (jl_is_symbol(t1))
655658
f_lib = jl_symbol_name((jl_sym_t*)t1);
656659
else if (jl_is_string(t1))
657660
f_lib = jl_string_data(t1);
658661
else
659-
JL_TYPECHKS(fname, symbol, t1);
660-
}
661-
else {
662-
JL_TYPECHKS(fname, pointer, ptr);
662+
f_name = NULL;
663663
}
664664
}
665665
}
@@ -696,7 +696,15 @@ static jl_cgval_t emit_cglobal(jl_codectx_t &ctx, jl_value_t **args, size_t narg
696696
Type *lrt = ctx.types().T_size;
697697
assert(lrt == julia_type_to_llvm(ctx, rt));
698698

699-
interpret_symbol_arg(ctx, sym, args[1], "cglobal", false);
699+
interpret_symbol_arg(ctx, sym, args[1], /*ccall=*/false, false);
700+
701+
if (sym.f_name == NULL && sym.fptr == NULL && sym.jl_ptr == NULL && sym.gcroot != NULL) {
702+
const char *errmsg = invalid_symbol_err_msg(/*ccall=*/false);
703+
jl_cgval_t arg1 = emit_expr(ctx, args[1]);
704+
emit_type_error(ctx, arg1, literal_pointer_val(ctx, (jl_value_t *)jl_pointer_type), errmsg);
705+
JL_GC_POP();
706+
return jl_cgval_t();
707+
}
700708

701709
if (sym.jl_ptr != NULL) {
702710
res = ctx.builder.CreateBitCast(sym.jl_ptr, lrt);
@@ -1346,14 +1354,20 @@ static jl_cgval_t emit_ccall(jl_codectx_t &ctx, jl_value_t **args, size_t nargs)
13461354
bool llvmcall = false;
13471355
std::tie(cc, llvmcall) = convert_cconv(cc_sym);
13481356

1349-
interpret_symbol_arg(ctx, symarg, args[1], "ccall", llvmcall);
1357+
interpret_symbol_arg(ctx, symarg, args[1], /*ccall=*/true, llvmcall);
13501358
Value *&jl_ptr = symarg.jl_ptr;
13511359
void (*&fptr)(void) = symarg.fptr;
13521360
const char *&f_name = symarg.f_name;
13531361
const char *&f_lib = symarg.f_lib;
13541362

13551363
if (f_name == NULL && fptr == NULL && jl_ptr == NULL) {
1356-
emit_error(ctx, "ccall: null function pointer");
1364+
if (symarg.gcroot != NULL) { // static_eval(ctx, args[1]) could not be interpreted to a function pointer
1365+
const char *errmsg = invalid_symbol_err_msg(/*ccall=*/true);
1366+
jl_cgval_t arg1 = emit_expr(ctx, args[1]);
1367+
emit_type_error(ctx, arg1, literal_pointer_val(ctx, (jl_value_t *)jl_pointer_type), errmsg);
1368+
} else {
1369+
emit_error(ctx, "ccall: null function pointer");
1370+
}
13571371
JL_GC_POP();
13581372
return jl_cgval_t();
13591373
}

src/cgutils.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1352,13 +1352,21 @@ static Value *emit_typeof(jl_codectx_t &ctx, Value *v, bool maybenull)
13521352
}
13531353

13541354

1355-
static void emit_type_error(jl_codectx_t &ctx, const jl_cgval_t &x, Value *type, const std::string &msg)
1355+
static void just_emit_type_error(jl_codectx_t &ctx, const jl_cgval_t &x, Value *type, const std::string &msg)
13561356
{
13571357
Value *msg_val = stringConstPtr(ctx.emission_context, ctx.builder, msg);
13581358
ctx.builder.CreateCall(prepare_call(jltypeerror_func),
13591359
{ msg_val, maybe_decay_untracked(ctx, type), mark_callee_rooted(ctx, boxed(ctx, x))});
13601360
}
13611361

1362+
static void emit_type_error(jl_codectx_t &ctx, const jl_cgval_t &x, Value *type, const std::string &msg)
1363+
{
1364+
just_emit_type_error(ctx, x, type, msg);
1365+
ctx.builder.CreateUnreachable();
1366+
BasicBlock *cont = BasicBlock::Create(ctx.builder.getContext(), "after_type_error", ctx.f);
1367+
ctx.builder.SetInsertPoint(cont);
1368+
}
1369+
13621370
// Should agree with `emit_isa` below
13631371
static bool _can_optimize_isa(jl_value_t *type, int &counter)
13641372
{
@@ -1441,9 +1449,6 @@ static std::pair<Value*, bool> emit_isa(jl_codectx_t &ctx, const jl_cgval_t &x,
14411449
if (known_isa) {
14421450
if (!*known_isa && msg) {
14431451
emit_type_error(ctx, x, literal_pointer_val(ctx, type), *msg);
1444-
ctx.builder.CreateUnreachable();
1445-
BasicBlock *failBB = BasicBlock::Create(ctx.builder.getContext(), "fail", ctx.f);
1446-
ctx.builder.SetInsertPoint(failBB);
14471452
}
14481453
return std::make_pair(ConstantInt::get(getInt1Ty(ctx.builder.getContext()), *known_isa), true);
14491454
}
@@ -1581,7 +1586,7 @@ static void emit_typecheck(jl_codectx_t &ctx, const jl_cgval_t &x, jl_value_t *t
15811586
ctx.builder.CreateCondBr(istype, passBB, failBB);
15821587
ctx.builder.SetInsertPoint(failBB);
15831588

1584-
emit_type_error(ctx, x, literal_pointer_val(ctx, type), msg);
1589+
just_emit_type_error(ctx, x, literal_pointer_val(ctx, type), msg);
15851590
ctx.builder.CreateUnreachable();
15861591

15871592
ctx.f->getBasicBlockList().push_back(passBB);
@@ -3464,7 +3469,7 @@ static void emit_cpointercheck(jl_codectx_t &ctx, const jl_cgval_t &x, const std
34643469
ctx.builder.CreateCondBr(istype, passBB, failBB);
34653470
ctx.builder.SetInsertPoint(failBB);
34663471

3467-
emit_type_error(ctx, x, literal_pointer_val(ctx, (jl_value_t*)jl_pointer_type), msg);
3472+
just_emit_type_error(ctx, x, literal_pointer_val(ctx, (jl_value_t*)jl_pointer_type), msg);
34683473
ctx.builder.CreateUnreachable();
34693474

34703475
ctx.f->getBasicBlockList().push_back(passBB);

src/runtime_intrinsics.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -490,14 +490,14 @@ JL_DLLEXPORT jl_value_t *jl_cglobal(jl_value_t *v, jl_value_t *ty)
490490

491491
char *f_lib = NULL;
492492
if (jl_is_tuple(v) && jl_nfields(v) > 1) {
493-
jl_value_t *t1 = jl_fieldref_noalloc(v, 1);
494-
v = jl_fieldref(v, 0);
493+
jl_value_t *t1 = jl_fieldref(v, 1);
495494
if (jl_is_symbol(t1))
496495
f_lib = jl_symbol_name((jl_sym_t*)t1);
497496
else if (jl_is_string(t1))
498497
f_lib = jl_string_data(t1);
499498
else
500499
JL_TYPECHK(cglobal, symbol, t1)
500+
v = jl_fieldref(v, 0);
501501
}
502502

503503
char *f_name = NULL;

test/ccall.jl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1516,6 +1516,12 @@ end
15161516
@test_throws(ErrorException("ccall return type struct fields cannot contain a reference"),
15171517
@eval ccall(:fn, typeof(Ref("")), ()))
15181518

1519+
fn45187() = nothing
1520+
1521+
@test_throws(TypeError, @eval ccall(nothing, Cvoid, ()))
1522+
@test_throws(TypeError, @eval ccall(49142, Cvoid, ()))
1523+
@test_throws(TypeError, @eval ccall((:fn, fn45187), Cvoid, ()))
1524+
15191525
# test for malformed syntax errors
15201526
@test Expr(:error, "more arguments than types for ccall") == Meta.lower(@__MODULE__, :(ccall(:fn, A, (), x)))
15211527
@test Expr(:error, "more arguments than types for ccall") == Meta.lower(@__MODULE__, :(ccall(:fn, A, (B,), x, y)))
@@ -1910,6 +1916,12 @@ end
19101916
function cglobal33413_literal_notype()
19111917
return cglobal(:sin)
19121918
end
1919+
function cglobal49142_nothing()
1920+
return cglobal(nothing)
1921+
end
1922+
function cglobal45187fn()
1923+
return cglobal((:fn, fn45187))
1924+
end
19131925
@test unsafe_load(cglobal33413_ptrvar()) == 1
19141926
@test unsafe_load(cglobal33413_ptrinline()) == 1
19151927
@test unsafe_load(cglobal33413_tupleliteral()) == 1
@@ -1918,6 +1930,10 @@ end
19181930
@test unsafe_load(convert(Ptr{Cint}, cglobal33413_tupleliteral_notype())) == 1
19191931
@test cglobal33413_literal() != C_NULL
19201932
@test cglobal33413_literal_notype() != C_NULL
1933+
@test_throws(TypeError, cglobal49142_nothing())
1934+
@test_throws(TypeError, cglobal45187fn())
1935+
@test_throws(TypeError, @eval cglobal(nothing))
1936+
@test_throws(TypeError, @eval cglobal((:fn, fn45187)))
19211937
end
19221938

19231939
@testset "ccall_effects" begin

0 commit comments

Comments
 (0)