Interesting. It seems I misattributed my application error to the linking status of the file. The actual regression was with rust:1.48, and trivial rust binaries after this point fail the NOFILE ulimit.
FROM rust:1.48
RUN rustup target add x86_64-unknown-linux-musl
RUN echo 'fn main(){println!("hi");}' > hi.rs; rustc --target x86_64-unknown-linux-musl -o hi hi.rs
RUN python3 -c 'import resource,subprocess;print(subprocess.run(["/hi"],preexec_fn=lambda: resource.setrlimit(resource.RLIMIT_NOFILE, (0,0))))'
I ran strace on the binary (without the ulimit) and the output looks identical to me. I don't see any open calls.
strace 1.47 (which passes the above test)
execve("./hi", ["./hi"], 0x7ffecddf67a0 /* 8 vars */) = 0
mmap(NULL, 496, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4dff07c000
arch_prctl(ARCH_SET_FS, 0x7f4dff07c100) = 0
set_tid_address(0x7f4dff081d18) = 12
poll([{fd=0, events=0}, {fd=1, events=0}, {fd=2, events=0}], 3, 0) = 0 (Timeout)
rt_sigaction(SIGPIPE, {sa_handler=SIG_IGN, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7f4dff0614be}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGSEGV, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [RT_1 RT_2], NULL, 8) = 0
rt_sigaction(SIGSEGV, {sa_handler=0x7f4dff03f6c0, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK|SA_SIGINFO, sa_restorer=0x7f4dff0614be}, NULL, 8) = 0
rt_sigaction(SIGBUS, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGBUS, {sa_handler=0x7f4dff03f6c0, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK|SA_SIGINFO, sa_restorer=0x7f4dff0614be}, NULL, 8) = 0
sigaltstack(NULL, {ss_sp=NULL, ss_flags=SS_DISABLE, ss_size=0}) = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4dff022000
mprotect(0x7f4dff022000, 4096, PROT_NONE) = 0
sigaltstack({ss_sp=0x7f4dff023000, ss_flags=0, ss_size=8192}, NULL) = 0
brk(NULL) = 0x555556e89000
brk(0x555556e8a000) = 0x555556e8a000
rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1 RT_2], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
write(1, "hi\n", 3hi
) = 3
sigaltstack({ss_sp=NULL, ss_flags=SS_DISABLE, ss_size=8192}, NULL) = 0
munmap(0x7f4dff022000, 12288) = 0
exit_group(0) = ?
strace on 1.48 (which fails the above check):
execve("./hi", ["./hi"], 0x7ffecddf67a0 /* 8 vars */) = 0
mmap(NULL, 496, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4dff07c000
arch_prctl(ARCH_SET_FS, 0x7f4dff07c100) = 0
set_tid_address(0x7f4dff081d18) = 12
poll([{fd=0, events=0}, {fd=1, events=0}, {fd=2, events=0}], 3, 0) = 0 (Timeout)
rt_sigaction(SIGPIPE, {sa_handler=SIG_IGN, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7f4dff0614be}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGSEGV, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [RT_1 RT_2], NULL, 8) = 0
rt_sigaction(SIGSEGV, {sa_handler=0x7f4dff03f6c0, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK|SA_SIGINFO, sa_restorer=0x7f4dff0614be}, NULL, 8) = 0
rt_sigaction(SIGBUS, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGBUS, {sa_handler=0x7f4dff03f6c0, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK|SA_SIGINFO, sa_restorer=0x7f4dff0614be}, NULL, 8) = 0
sigaltstack(NULL, {ss_sp=NULL, ss_flags=SS_DISABLE, ss_size=0}) = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4dff022000
mprotect(0x7f4dff022000, 4096, PROT_NONE) = 0
sigaltstack({ss_sp=0x7f4dff023000, ss_flags=0, ss_size=8192}, NULL) = 0
brk(NULL) = 0x555556e89000
brk(0x555556e8a000) = 0x555556e8a000
rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1 RT_2], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
write(1, "hi\n", 3hi
) = 3
sigaltstack({ss_sp=NULL, ss_flags=SS_DISABLE, ss_size=8192}, NULL) = 0
munmap(0x7f4dff022000, 12288) = 0
exit_group(0) = ?