I noticed that when I attempted to open a file with bad permissions, such as one that is owned by root, it will cause a runtime crash/segmentation fault, a very confusing one at that. Would it be possible to add a runtime check to determine if opening a file has failed, and if so throw a runtime error that is a bit more helpful, such as open: "Bad file permissions for file %FILENAME%".
Can you show more about the error? E.g. example code, steps to reproduce?
I tried to reproduce:
proc test() {
var f = open("testfile.txt", iomode.rw);
}
test();
$ ls -l testfile.txt
-rw------- 1 root user 0 Jul 9 14:59 testfile.txt
running the program results in:
uncaught PermissionError: Permission denied (in open with path "testfile.txt")
x.chpl:2: thrown here
x.chpl:2: uncaught here
Segmentation Fault
proc badFn(fileName) throws {
var badFile = open(fileName, iomode.cw).writer();
}
badFn("out.dot");
Output
*** Caught a fatal signal: SIGSEGV(11) on node 0/1
[0] 0: ./BadFilePermissionMWE_real() [0x4b6c3f] gasneti_bt_execinfo gasnet_tools.c:?
[0] 1: ./BadFilePermissionMWE_real() [0x4bc7ff] gasneti_print_backtrace ??:?
[0] 2: ./BadFilePermissionMWE_real() [0x52d98f] gasneti_defaultSignalHandler ??:?
[0] 3: /lib/x86_64-linux-gnu/libc.so.6(+0x354b0) [0x7f1b5cb854b0] ?? ??:0
[0] 4: ./BadFilePermissionMWE_real() [0x5392eb] _ZL20AMUDP_RequestGeneric16amudp_category_tP8amudp_epjhPvimiP13__va_list_taghh.constprop.7 amudp_reqrep.cpp:?
[0] 5: ./BadFilePermissionMWE_real() [0x539c16] AMUDP_RequestIVA ??:?
[0] 6: ./BadFilePermissionMWE_real() [0x4b186a] gasnetc_AMRequestMediumM ??:?
[0] 7: ./BadFilePermissionMWE_real() [0x48a83e] chpl_comm_execute_on ??:?
[0] 8: ./BadFilePermissionMWE_real() [0x452f3b] chpl_executeOn /home/LouisJenkinsCS/chgl/src/modules/LocaleModelHelpFlat.chpl:55
[0] 9: ./BadFilePermissionMWE_real() [0x46b8df] deinit_chpl3 /home/LouisJenkinsCS/chgl/src/modules/IO.chpl:2010 (discriminator 2)
[0] 10: ./BadFilePermissionMWE_real() [0x4588c8] badFn_chpl /home/LouisJenkinsCS/chgl/src/modules/BadFilePermissionMWE.chpl:2 (discriminator 7)
[0] 11: ./BadFilePermissionMWE_real() [0x4583eb] chpl__init_BadFilePermissionMWE /home/LouisJenkinsCS/chgl/src/modules/BadFilePermissionMWE.chpl:4 (discriminator 1)
[0] 12: ./BadFilePermissionMWE_real() [0x458d07] chpl_gen_main /home/LouisJenkinsCS/chgl/src/modules/BadFilePermissionMWE.chpl:1
[0] 13: ./BadFilePermissionMWE_real() [0x480288] chpl_executable_init ??:?
[0] 14: ./BadFilePermissionMWE_real() [0x4856e1] main_wrapper tasks-qthreads.c:?
[0] 15: ./BadFilePermissionMWE_real() [0x545da8] qthread_wrapper qthread.c:?
About
Compilation command: chpl BadFilePermissionMWE.chpl --devel -g --cpp-lines
Chapel compiler version: 1.18.0 pre-release (2bcd25f)
Chapel environment:
CHPL_HOME: /home/LouisJenkinsCS/chapel
CHPL_ATOMICS: intrinsics
CHPL_AUX_FILESYS: none
CHPL_COMM: gasnet
CHPL_COMM_SUBSTRATE: udp
CHPL_COMPILER_SUBDIR: linux64/gnu/llvm-none
CHPL_GASNET_SEGMENT: everything
CHPL_GMP: gmp
CHPL_GMP_UNIQ_CFG_PATH: linux64-gnu-unknown
CHPL_HOST_COMPILER: gnu
CHPL_HOST_MEM: cstdlib
CHPL_HOST_PLATFORM: linux64
CHPL_HWLOC: hwloc
CHPL_HWLOC_UNIQ_CFG_PATH: linux64-gnu-unknown-flat
CHPL_JEMALLOC: jemalloc
CHPL_JEMALLOC_UNIQ_CFG_PATH: linux64-gnu-unknown
CHPL_LAUNCHER: amudprun
CHPL_LAUNCHER_SUBDIR: linux64/gnu/loc-flat/comm-gasnet/udp/everything/tasks-qthreads/launch-amudprun/tmr-generic/unwind-none/mem-jemalloc/atomics-intrinsics
CHPL_LIBUNWIND_UNIQ_CFG_PATH: linux64-gnu-unknown
CHPL_LLVM: none
CHPL_LOCALE_MODEL: flat
CHPL_MAKE: make
CHPL_MASSIVETHREADS_UNIQ_CFG_PATH: linux64-gnu-unknown
CHPL_MEM: jemalloc
CHPL_NETWORK_ATOMICS: none
CHPL_ORIG_TARGET_COMPILER: gnu
CHPL_QTHREAD_UNIQ_CFG_PATH: linux64-gnu-unknown-flat
CHPL_RE2_UNIQ_CFG_PATH: linux64-gnu-unknown
CHPL_REGEXP: re2
CHPL_RUNTIME_ARCH: unknown
CHPL_RUNTIME_INCL: /home/LouisJenkinsCS/chapel/runtime/include
CHPL_RUNTIME_LIB: /home/LouisJenkinsCS/chapel/lib
CHPL_RUNTIME_SUBDIR: linux64/gnu/arch-unknown/loc-flat/comm-gasnet/udp/everything/tasks-qthreads/tmr-generic/unwind-none/mem-jemalloc/atomics-intrinsics/hwloc/re2/fs-none
CHPL_TARGET_ARCH: unknown
CHPL_TARGET_ARCH_FLAG: none
CHPL_TARGET_BACKEND_ARCH: unknown
CHPL_TARGET_COMPILER: gnu
CHPL_TARGET_MEM: jemalloc
CHPL_TARGET_PLATFORM: linux64
CHPL_TASKS: qthreads
CHPL_THIRD_PARTY: /home/LouisJenkinsCS/chapel/third-party
CHPL_THIRD_PARTY_LINK_ARGS: -lgmp -lchpl -lqthread -L/home/LouisJenkinsCS/chapel/third-party/hwloc/install/linux64-gnu-unknown-flat/lib -L/home/LouisJenkinsCS/chapel/third-party/
jemalloc/install/linux64-gnu-unknown/lib -ljemalloc -lhwloc -lm -lre2 -lpthread
CHPL_TIMERS: generic
CHPL_UNWIND: none
Although, I am getting weird behavior while experimenting with this... Like, sometimes I saw it spin indefinitely, other times I immediately saw a GASNet active message error.
Disregard the above, turns out it was mixing and matching older (likely cached) files with new ones causing the interesting behavior. I still get a segfault but not with the above example.
Try this one?
proc badFn(unusedObj, fileName = "out.dot") throws {
var f = open(fileName, iomode.cw).writer();
proc innerFn(v, ref str) {
f.writeln(v);
}
f.writeln("}");
f.close();
}
proc main() {
badFn(new object());
}
And you can generate file of course via sudo touch out.dot
Also note that if you pass badFn(1) instead of new object() I get the throw error message. Its almost like undefined behavior. For example, try this...
proc badFn(unusedObj, fileName = "out.dot") throws {
var f = open(fileName, iomode.cw).writer();
proc innerFn(v, ref str) {
f.writeln(v);
}
f.writeln("}");
f.close();
}
record R {var x = 1; var y = 2; var z = 3; var w = 4; }
proc main() {
var r : R;
badFn(r);
}
The output I get is...
AMUDP int sendPacket(ep_t, amudp_msg_t*, size_t, en_t, packet_type) returning an error code: AM_ERR_RESOURCE (Problem with requested resource)
from function sendPacket
at /home/LouisJenkinsCS/chapel/third-party/gasnet/gasnet-src/other/amudp/amudp_reqrep.cpp:113
reason: Address family not supported by protocol
AMUDP int AMUDP_RequestGeneric(amudp_category_t, ep_t, amudp_node_t, handler_t, void*, int, uintptr_t, int, __va_list_tag*, uint8_t, uint8_t) returning an error code: AM_ERR_RESOURCE (Problem with requested resource)
at /home/LouisJenkinsCS/chapel/third-party/gasnet/gasnet-src/other/amudp/amudp_reqrep.cpp:1107
GASNet gasnetc_AMRequestMediumM encountered an AM Error: AM_ERR_RESOURCE(3)
at /home/LouisJenkinsCS/chapel/third-party/gasnet/gasnet-src/udp-conduit/gasnet_core.c:701
GASNet gasnetc_AMRequestMediumM returning an error code: GASNET_ERR_RESOURCE (Problem with requested resource)
at /home/LouisJenkinsCS/chapel/third-party/gasnet/gasnet-src/udp-conduit/gasnet_core.c:705
ERROR calling: gasnet_AMRequestMedium0(node, op, f, small_msg_size)
at: comm-gasnet.c:1548
error: GASNET_ERR_RESOURCE (Problem with requested resource)
config var oneline = true;
proc badFn(fileName) throws {
if (oneline) {
var badFile = open(fileName, iomode.cw).writer();
} else {
var badFile = open(fileName, iomode.cw);
var w = badFile.writer();
}
}
badFn("out.dot");
fortytwo@magrathea:~/src/chapel (master)$ ./badfn -nl 1 --oneline=false
uncaught PermissionError: Permission denied (in open with path "out.dot")
$CHPL_HOME/modules/standard/SysError.chpl:411: thrown here
badfn.chpl:11: uncaught here
fortytwo@magrathea:~/src/chapel (master)$ ./badfn -nl 1 --oneline=true
*** Caught a fatal signal: SIGSEGV(11) on node 0/1
NOTICE: Before reporting bugs, run with GASNET_BACKTRACE=1 in the environment to generate a backtrace.
Thank you @cassella, its good to confirm that its not just my configuration/setup. @mppf I believe this needs to be flagged as a Compiler issue as well.
I get the same behavior with a file-not-found by changing the open to use iomode.r, and the writer() to reader(). It's the same behavior, but simpler to run the test without having to create a file as root.
If I change the oneline version to var badFile = try! open(...).reader(), it behaves as expected,
fortytwo@magrathea:~/src/chapel (master)$ ./badfn -nl 1 --oneline=true
uncaught FileNotFoundError: No such file or directory (in open with path "oot.doot")
badfn.chpl:5: thrown here
badfn.chpl:5: uncaught here
I forget the ramifications of the various error-handling strictness modes, but I think there's really supposed to be a try around every function call that can throw, even if the function it's in is marked throws.
I'm putting this in the backlog under the assumption that it might be a quick fix. If that's not the case, I'm very open to moving it to the icebox.
The problem isn't specific to the IO module:
record R {
var s = "world";
proc hello() { writeln("Hello ", s); return this; }
proc init() { writeln("in init"); }
proc deinit() { writeln("in deinit"); }
}
proc gimmeanr(): R throws {
var ret: R;
throw new Error();
return ret;
}
proc intro() throws {
var r = gimmeanr().hello();
}
intro();
fortytwo@magrathea:~/src/chapel (master)$ ./foo -nl 1
in init
in deinit
in deinit
*** Caught a fatal signal: SIGSEGV(11) on node 0/1
More calls to deinit than to init seems fishy to me.
In a valgrind-compatible CHPL_COMM=none build,
...
==7084==
in init
in deinit
in deinit
==7084== Thread 2:
==7084== Conditional jump or move depends on uninitialised value(s)
==7084== at 0x40E6C3: deinit16 (in /home/fortytwo/src/chapel-none/foo)
==7084== by 0x42D874: deinit_chpl6 (in /home/fortytwo/src/chapel-none/foo)
==7084== by 0x42DA32: intro_chpl (in /home/fortytwo/src/chapel-none/foo)
==7084== by 0x42D3F1: chpl__init_foo (in /home/fortytwo/src/chapel-none/foo)
==7084== by 0x42D5B4: chpl_gen_main (in /home/fortytwo/src/chapel-none/foo)
==7084== by 0x442517: chpl_executable_init (in /home/fortytwo/src/chapel-none/foo)
==7084== by 0x445EA9: do_callMain (in /home/fortytwo/src/chapel-none/foo)
==7084== by 0x4E416B9: start_thread (pthread_create.c:333)
==7084== by 0x546741C: clone (clone.S:109)
...
uncaught Error:
foo.chpl:11: thrown here
foo.chpl:19: uncaught here
deinit16 seems to be string.deinit().
deinit_chpl6 is my R.deinit().
The problem is in the generated code for intro:
static void intro_chpl(Error * error_out_chpl) {
R_chpl r_chpl;
R_chpl call_tmp_chpl;
Error error_chpl = NULL;
R_chpl ret_tmp_chpl;
chpl_bool errorExists_chpl;
_ref_R i_x_chpl = NULL;
error_chpl = nil;
gimmeanr_chpl(&error_chpl, &ret_tmp_chpl);
call_tmp_chpl = ret_tmp_chpl;
errorExists_chpl = (error_chpl != nil);
if (errorExists_chpl) {
*(error_out_chpl) = error_chpl;
i_x_chpl = &r_chpl;
deinit_chpl7(i_x_chpl); // r_chpl was never initialized, so we shouldn't deinit it
goto _endintro_chpl;
}