Description
openedon Mar 9, 2022
I've found this interesting article about bugs in "Hello World" style programs, exploring how writing to full files is almost never checked. I was curious to try this in julia, so I wrote the following test.jl
:
function main()
println("Hello World")
exit(0)
end
main()
and ran it like
$ julia test.jl > /dev/full
which redirects the stdout output to /dev/full
, a device that always pretends to be full. I got the following error/stackdump:
$ julia test.jl > /dev/full
error in running finalizer: Base.SystemError(prefix="close", errnum=28, extrainfo=nothing)
#systemerror#69 at ./error.jl:174
systemerror##kw at ./error.jl:174
systemerror##kw at ./error.jl:174
#systemerror#68 at ./error.jl:173 [inlined]
systemerror at ./error.jl:173 [inlined]
close at ./iostream.jl:63
jl_apply at /home/sukera/julia/src/julia.h:1788 [inlined]
run_finalizer at /home/sukera/julia/src/gc.c:278
jl_gc_run_finalizers_in_list at /home/sukera/julia/src/gc.c:365
run_finalizers at /home/sukera/julia/src/gc.c:394 [inlined]
run_finalizers at /home/sukera/julia/src/gc.c:372
jl_atexit_hook at /home/sukera/julia/src/init.c:240
jl_exit at /home/sukera/julia/src/jl_uv.c:633
exit at ./initdefs.jl:28 [inlined]
main at /home/sukera/projects/test.jl:3
unknown function (ip: 0x7fa5d003819f)
jl_apply at /home/sukera/julia/src/julia.h:1788 [inlined]
do_call at /home/sukera/julia/src/interpreter.c:126
eval_value at /home/sukera/julia/src/interpreter.c:215
eval_stmt_value at /home/sukera/julia/src/interpreter.c:166 [inlined]
eval_body at /home/sukera/julia/src/interpreter.c:583
jl_interpret_toplevel_thunk at /home/sukera/julia/src/interpreter.c:731
top-level scope at /home/sukera/projects/test.jl:6
jl_toplevel_eval_flex at /home/sukera/julia/src/toplevel.c:885
jl_toplevel_eval_flex at /home/sukera/julia/src/toplevel.c:830
jl_toplevel_eval_in at /home/sukera/julia/src/toplevel.c:944
eval at ./boot.jl:373 [inlined]
include_string at ./loading.jl:1196
_include at ./loading.jl:1253
include at ./Base.jl:418
exec_options at ./client.jl:292
_start at ./client.jl:495
jfptr__start_40004 at /home/sukera/julia/usr/lib/julia/sys.so (unknown line)
jl_apply at /home/sukera/julia/src/julia.h:1788 [inlined]
true_main at /home/sukera/julia/src/jlapi.c:559
jl_repl_entrypoint at /home/sukera/julia/src/jlapi.c:701
main at julia (unknown line)
__libc_start_call_main at /usr/lib/libc.so.6 (unknown line)
__libc_start_main at /usr/lib/libc.so.6 (unknown line)
_start at julia (unknown line)
and a return code of 0
, indicating success:
$ echo $?
0
The program encountered a fatal error and (decisively) shouldn't exit with 0
, indicating success - moreover, the error message doesn't really give any indication what went wrong here, so that could be improved as well. Notably, if I remove the exit(0)
from the file, the stacktrace shrinks because the default exit path gets hit instead but it still crashes when trying to close the pipe provided as stdout
. IMO it should have already crashed at that point, when the device it was trying to write to reported that the write failed:
$ strace -etrace=write julia test.jl > /dev/full
write(5, "*", 1) = 1
write(12, "hello world\n", 12) = -1 ENOSPC (No space left on device)
[...] # the write calls from the error message of `close` follow
+++ exited with 0 +++
As noted in the article, e.g. Python3 dutifully reports the OSError: No space left on device
, allowing the bug to be debugged.