fix(lua): replace os.spawn with io.popen to prevent fd-inheritance corruption - #1759
fix(lua): replace os.spawn with io.popen to prevent fd-inheritance corruption#1759lbssousa wants to merge 1 commit into
Conversation
Address review feedback on PR gregorio-project#1759: - The f_pos corruption silently rewinds the read offset (not "advances"); fix the comment to match the observed behaviour. - Extract gre_exec(cmd) to eliminate the duplicated io.popen block that existed in both get_prog_output and compile_gabc. gre_exec returns 0 on success, a positive integer on failure, or nil when io.popen could not open a handle (nil is the sentinel compile_gabc uses to report that shell-escape may not be activated). get_prog_output maps nil → 1 with the "or 1" idiom, preserving its existing rc semantics. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
I think this just needs an entry in CHANGELOG.md and then it looks good to me. |
Address review feedback on PR gregorio-project#1759: - The f_pos corruption silently rewinds the read offset (not "advances"); fix the comment to match the observed behaviour. - Extract gre_exec(cmd) to eliminate the duplicated io.popen block that existed in both get_prog_output and compile_gabc. gre_exec returns 0 on success, a positive integer on failure, or nil when io.popen could not open a handle (nil is the sentinel compile_gabc uses to report that shell-escape may not be activated). get_prog_output maps nil → 1 with the "or 1" idiom, preserving its existing rc semantics. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
It looks to me like it should be possible to generate a test file that follows your test plan and add it to the test repository. @lbssousa, can you please do that? |
|
I'm reviewing the code for this PR. I thought about opening a new one, but on second thought, I decided to just force push to this one instead. |
… (issue gregorio-project#1757) On Unix, os.spawn() leaks open file descriptors to the child process, which can silently rewind the read offset of a \input-ted .tex file that LuaTeX is still scanning. Route gabc/score compilation through io.popen() instead, which doesn't exhibit this behavior. Windows is unaffected and keeps using os.spawn().
Address review feedback on PR gregorio-project#1759: - The f_pos corruption silently rewinds the read offset (not "advances"); fix the comment to match the observed behaviour. - Extract gre_exec(cmd) to eliminate the duplicated io.popen block that existed in both get_prog_output and compile_gabc. gre_exec returns 0 on success, a positive integer on failure, or nil when io.popen could not open a handle (nil is the sentinel compile_gabc uses to report that shell-escape may not be activated). get_prog_output maps nil → 1 with the "or 1" idiom, preserving its existing rc semantics. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Just smoothed out the rough edges here. Could you please review it once again? |
|
What changed from before? (I can't tell because of the force-push.) I haven't tested, but it looks reasonable to me. |
Just removed a local variable in favour of inline if-condition in I've also refactored the corredponding test gregorio-project/gregorio-test#426 from scripted to tex-output, as suggested. |
Summary
os.spawn()withio.popen()at both call sites intex/gregoriotex.luawhere agregoriochild process is launched.gre_shellquote,gre_build_cmdstr,gre_use_popen) defined once, beforeget_prog_output.gre_use_popenisfalsewhenos.type == 'windows', preserving the originalos.spawn()path.Problem
os.spawn()on Unix is implemented asfork()+execve()without settingFD_CLOEXECon any file descriptor. Thegregoriochild process therefore inherits every fd open in the LuaTeX parent — including the fd of any.texfile currently being\input-ted. Parent and child share the same kernel-levelstruct file(which holds the seek positionf_pos); any fd activity in the child can silently advance the read offset LuaTeX still relies on, corrupting TeX's input state.Both call sites are affected:
get_prog_output()\gabcsnippet→direct_gabc()compile_gabc()\gregorioscore→include_score()The bug manifests only when
\gregorioscoreor\gabcsnippetis used inside an\input-ted file and no cached.gtexexists (clean-state build). Observed on NixOS sandboxes and GitHub Actions.Typical symptoms:
! Misplaced \noalign./! Undefined control sequence. \gre(hard error)Fix
io.popen()invokes/bin/sh -c, which manages its own fd space before the finalexec, eliminating the inheritance. Arguments are individually POSIX-single-quoted bygre_shellquote()so paths with spaces or shell metacharacters remain safe.Closes #1757