build/command.rb: route mrbc output through tempfile to avoid pipe race

The previous IO.popen capture of mrbc stdout (`-o-`) is vulnerable
to a Windows MinGW race: with parallel rake (-m), stdout pipe
inheritance can allow unrelated `_pp` build-progress messages from
sibling worker threads to leak into the captured pipe content,
corrupting the generated C file (recently seen as `CC build/...`
text inside gem_test.c, causing compile errors at unrelated lines).

Switch to `mrbc -o <tmpfile>` so the output is materialised in a
file before merging into the destination, fully isolating mrbc
from the parent's STDOUT.

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2026-05-11 09:52:35 +09:00
parent ad0ea8571f
commit 3dbf5f6e27
+10 -5
View File
@@ -343,16 +343,21 @@ module MRuby
opt = @compile_options % {funcname: funcname}
opt << " -S" if cdump
opt << " -s" if static
# Have mrbc write to a private tempfile (-o) instead of stdout (-o-)
# to avoid pipe-inheritance races with parallel rake on Windows MinGW,
# where unrelated _pp build-progress lines from sibling workers can
# leak into the captured stdout and corrupt the generated C file.
tmpout = "#{out.path}.#{funcname}.mrbcout"
opt = opt.sub(/\s-o-(?=\s|\z)/, %Q[ -o "#{filename tmpout}"])
cmd = %["#{filename @command}" #{opt} #{filename(infiles).map{|f| %["#{f}"]}.join(' ')}]
puts cmd if Rake.verbose
IO.popen(cmd, 'r') do |io|
out.puts io.read
end
# if mrbc execution fail, drop the file
unless $?.success?
unless system(cmd)
rm_f tmpout
rm_f out.path
fail "Command failed with status (#{$?.exitstatus}): [#{cmd[0,42]}...]"
end
out.write File.binread(tmpout)
rm_f tmpout
end
end