Skip to content

Commit 77652fd

Browse files
authored
Validate more on assertion builds, and abort on errors (#52830)
This PR add a `jl_is_assertsbuild` function (cfr. `jl_is_debugbuild`) for checking if this is an assertions build. It's used in two places: 1. to enable additional validation, which currently often requires`-g2` 2. to make internal compiler errors fatal Both these changes are intended to help PkgEval in detecting more issues (invalid Julia IR) and make for more robust detection (a fatal signal instead of having to grep logs for `Internal error`, which leads to false positives).
1 parent a034aa1 commit 77652fd

File tree

10 files changed

+40
-10
lines changed

10 files changed

+40
-10
lines changed

base/compiler/inferencestate.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ function InferenceState(result::InferenceResult, cache_mode::UInt8, interp::Abst
479479
world = get_world_counter(interp)
480480
src = retrieve_code_info(result.linfo, world)
481481
src === nothing && return nothing
482-
validate_code_in_debug_mode(result.linfo, src, "lowered")
482+
maybe_validate_code(result.linfo, src, "lowered")
483483
return InferenceState(result, src, cache_mode, interp)
484484
end
485485
InferenceState(result::InferenceResult, cache_mode::Symbol, interp::AbstractInterpreter) =

base/compiler/optimize.jl

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ function ir_to_codeinf!(opt::OptimizationState)
186186
(; linfo, src) = opt
187187
src = ir_to_codeinf!(src, opt.ir::IRCode)
188188
opt.ir = nothing
189-
validate_code_in_debug_mode(linfo, src, "optimized")
189+
maybe_validate_code(linfo, src, "optimized")
190190
return src
191191
end
192192

@@ -934,8 +934,11 @@ function run_passes_ipo_safe(
934934
if made_changes
935935
@pass "compact 3" ir = compact!(ir, true)
936936
end
937-
if JLOptions().debug_level == 2
938-
@timeit "verify 3" (verify_ir(ir, true, false, optimizer_lattice(sv.inlining.interp)); verify_linetable(ir.linetable))
937+
if is_asserts()
938+
@timeit "verify 3" begin
939+
verify_ir(ir, true, false, optimizer_lattice(sv.inlining.interp))
940+
verify_linetable(ir.linetable)
941+
end
939942
end
940943
@label __done__ # used by @pass
941944
return ir
@@ -1056,7 +1059,7 @@ function convert_to_ircode(ci::CodeInfo, sv::OptimizationState)
10561059
ssaflags[block_end] = IR_FLAG_NOTHROW
10571060

10581061
# Verify that type-inference did its job
1059-
if JLOptions().debug_level == 2
1062+
if is_asserts()
10601063
for i = (oldidx + 1):last(sv.cfg.blocks[block].stmts)
10611064
@assert i in sv.unreachable
10621065
end

base/compiler/typeinfer.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,7 @@ function finish(me::InferenceState, interp::AbstractInterpreter)
581581
end
582582
end
583583

584-
validate_code_in_debug_mode(me.linfo, me.src, "inferred")
584+
maybe_validate_code(me.linfo, me.src, "inferred")
585585
nothing
586586
end
587587

base/compiler/utilities.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,7 @@ end
520520
is_root_module(m::Module) = false
521521

522522
inlining_enabled() = (JLOptions().can_inline == 1)
523+
523524
function coverage_enabled(m::Module)
524525
generating_output() && return false # don't alter caches
525526
cov = JLOptions().code_coverage
@@ -533,9 +534,12 @@ function coverage_enabled(m::Module)
533534
end
534535
return false
535536
end
537+
536538
function inbounds_option()
537539
opt_check_bounds = JLOptions().check_bounds
538540
opt_check_bounds == 0 && return :default
539541
opt_check_bounds == 1 && return :on
540542
return :off
541543
end
544+
545+
is_asserts() = ccall(:jl_is_assertsbuild, Cint, ()) == 1

base/compiler/validation.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,8 @@ struct InvalidCodeError <: Exception
6161
end
6262
InvalidCodeError(kind::AbstractString) = InvalidCodeError(kind, nothing)
6363

64-
function validate_code_in_debug_mode(linfo::MethodInstance, src::CodeInfo, kind::String)
65-
if JLOptions().debug_level == 2
66-
# this is a debug build of julia, so let's validate linfo
64+
function maybe_validate_code(linfo::MethodInstance, src::CodeInfo, kind::String)
65+
if is_asserts()
6766
errors = validate_code(linfo, src)
6867
if !isempty(errors)
6968
for e in errors
@@ -75,6 +74,7 @@ function validate_code_in_debug_mode(linfo::MethodInstance, src::CodeInfo, kind:
7574
linfo.def, ": ", e)
7675
end
7776
end
77+
error("")
7878
end
7979
end
8080
end

src/codegen.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9187,6 +9187,9 @@ jl_llvm_functions_t jl_emit_code(
91879187
jl_static_show((JL_STREAM*)STDERR_FILENO, jl_current_exception());
91889188
jl_printf((JL_STREAM*)STDERR_FILENO, "\n");
91899189
jlbacktrace(); // written to STDERR_FILENO
9190+
#ifndef JL_NDEBUG
9191+
abort();
9192+
#endif
91909193
}
91919194

91929195
return decls;

src/gf.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,9 @@ jl_code_info_t *jl_type_infer(jl_method_instance_t *mi, size_t world, int force)
402402
jlbacktrace(); // written to STDERR_FILENO
403403
}
404404
src = NULL;
405+
#ifndef JL_NDEBUG
406+
abort();
407+
#endif
405408
}
406409
ct->world_age = last_age;
407410
ct->reentrant_timing -= 0b10;

src/jl_exported_funcs.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@
284284
XX(jl_is_binding_deprecated) \
285285
XX(jl_is_char_signed) \
286286
XX(jl_is_const) \
287+
XX(jl_is_assertsbuild) \
287288
XX(jl_is_debugbuild) \
288289
XX(jl_is_foreign_type) \
289290
XX(jl_is_identifier) \

src/jlapi.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,19 @@ JL_DLLEXPORT int jl_is_debugbuild(void) JL_NOTSAFEPOINT
513513
#endif
514514
}
515515

516+
/**
517+
* @brief Check if Julia has been build with assertions enabled.
518+
*
519+
* @return Returns 1 if assertions are enabled, 0 otherwise.
520+
*/
521+
JL_DLLEXPORT int8_t jl_is_assertsbuild(void) JL_NOTSAFEPOINT {
522+
#ifndef JL_NDEBUG
523+
return 1;
524+
#else
525+
return 0;
526+
#endif
527+
}
528+
516529
/**
517530
* @brief Check if Julia's memory debugging is enabled.
518531
*

stdlib/InteractiveUtils/test/runtests.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,9 @@ let _true = Ref(true), f, g, h
330330
end
331331

332332
# manually generate a broken function, which will break codegen
333-
# and make sure Julia doesn't crash
333+
# and make sure Julia doesn't crash (when using a non-asserts build)
334+
is_asserts() = ccall(:jl_is_assertsbuild, Cint, ()) == 1
335+
if !is_asserts()
334336
@eval @noinline Base.@constprop :none f_broken_code() = 0
335337
let m = which(f_broken_code, ())
336338
let src = Base.uncompressed_ast(m)
@@ -371,6 +373,7 @@ let err = tempname(),
371373
rm(err)
372374
end
373375
end
376+
end
374377

375378
# Issue #33163
376379
A33163(x; y) = x + y

0 commit comments

Comments
 (0)