Repository navigation
irb in a Windows console: Fiddle finds A exports, pack("p") writes a real address - #39
Conversation
…n packaging On Windows, Handle#[] tries a name as given, then with the ANSI "A" suffix, then with the stdcall decorations @0..@252, plain and after the A - the order of fiddle 1.1.8's fiddle_handle_find_func. reline asks for FillConsoleOutputCharacter, which kernel32 exports only as ...A and ...W, so irb died at startup in 4.0.2. The same change is in #38 (920e6ca). Fiddle_AnsiSuffix1 tests it; CI's smoke test and the release check start irb with piped input on every platform.
[str].pack("p") and ("P") wrote an index into the packed string's list of
Strings, not an address. reline's Win32API hands the console API every
buffer as [str].pack("p").unpack("q*") and reads what the call wrote from
str, so irb in a Windows console crashed with an access violation; so
would any gem that passes buffers that way.
Now each String pack points at gets a native block of its own
(PackedPointers), holding its bytes and a NUL for as long as the String
lives, and pack writes the block's address. Fiddle::Function#call knows
the address among its pointer arguments: it copies the String into the
block before the call and the block back into the String after it, which
is what the String's own buffer gives in CRuby. unpack("p") still finds
only Strings packed into that same string ("no associated pointer"), now
by address. reline/io/windows.rb stays as upstream has it.
- Tests: PackPointer_RealAddress1 (C reads and writes through pack("p"),
strlen and memset, all platforms) and PackPointer_RelineWin32Api1
(reline's own Win32API filling a buffer, Windows). Both check the
address before C touches it, so a regression fails them rather than
killing the run; without this change they report the old indexes.
- CI fails a test run that did not finish: an access violation ends the
process and leaves no "> FAILED" line to count.
ruby/spec core/array/pack and core/string/unpack (3193 examples) and the
C# suite pass; reading, writing and unpacking through pack("p") gives
byte-identical output to CRuby 4.0.1; and irb in a real console, with
typed input, answers as CRuby's does.
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Packed string addresses Src/Libraries/Builtins/PackedPointers.cs, Src/Libraries/Builtins/RubyEncoder.cs, Src/IronRuby.Tests/Runtime/MiscTests.cs |
Packed strings now use registered native buffers. Packing stores the buffer address, and unpacking resolves it against associated strings. Regression tests cover pointer reads, writes, round-tripping, nil, and unassociated addresses. |
Fiddle packed-pointer calls Src/Libraries/Fiddle/FiddleCall.cs, Src/IronRuby.Tests/RubyTests.cs, Src/IronRuby.Tests/Runtime/MiscTests.cs |
Fiddle tracks packed string blocks during native calls and copies eligible changes back. A regression test covers Reline's Windows API call with a packed string buffer. |
Windows symbol lookup Src/Libraries/Fiddle/FiddleHandle.cs, Src/IronRuby.Tests/Runtime/MiscTests.cs |
Windows symbol lookup tries ANSI-suffixed and stdcall-decorated names. Tests check lookup results and missing-symbol errors. |
Startup and CI checks .github/workflows/ci.yml, Util/package-release.sh |
Startup checks run an expression through irb on Windows and non-Windows platforms. CI reports an error and prints the last 40 output lines if test output has neither a terminal PASSED line nor a Repro: line. |
Priority:
Estimated code review effort: 3 (Moderate) | ~25 minutes
Change: Bug fix
Sequence Diagram(s)
sequenceDiagram
participant RubyEncoder
participant PackedPointers
participant FiddleCall
participant FiddleTarget
RubyEncoder->>PackedPointers: Get the string buffer address
RubyEncoder->>RubyEncoder: Pack the native address
FiddleCall->>PackedPointers: Find the block for the address
FiddleCall->>FiddleTarget: Pass the pointer to the native call
FiddleTarget-->>FiddleCall: Return from the native call
FiddleCall->>PackedPointers: Copy eligible buffer changes back
Possibly related PRs
- Largo/ironruby#35: Adds the launcher contract used by the irb smoke checks in this pull request.
Suggested reviewers: claude
Merge Risk: 
Minimal · up to 3b486
-
No established issue prevents merging after normal checks.
Pre-merge checks: 
5
-
Full details: Docstring Coverage
-
Explanation
Docstring coverage is 81.82% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 11 functions across 7 files. (1 skipped: 1 unsupported.)
-
Finishing Touches
-
📝 Generate docstrings
-
- Commit to this branch
- Create a new PR
🧪 Generate unit tests (beta)
-
- Commit to this branch
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands.
…upstream ships it #39 makes [str].pack("p") a real address, so reline's Win32API works as Ruby ships it. This branch's change to Src/StdLib/ruby/4.0/reline/io/windows.rb goes back to upstream's file, as on master. RubyTests.cs and MiscTests.cs are #39's, which hold this branch's Fiddle_AnsiSuffix1 and #39's PackPointer tests; the release note says how irb was fixed.
irb starts and runs in a Windows console again, with reline exactly as Ruby ships it. Both bugs were in IronRuby, not in reline.
1. Fiddle looks a Win32 name up as CRuby does
reline asks Fiddle for
FillConsoleOutputCharacter, but kernel32 exports only the...Aand...Wvariants. In 4.0.2, irb therefore died at startup withunknown symbol "FillConsoleOutputCharacter", piped or not.On Windows,
Handle#[]now tries the name as given, then with theAsuffix, then the stdcall decorations@0to@252, plain and after theA. That is the order of fiddle 1.1.8'sfiddle_handle_find_func.This change is the same as #38's
920e6ca8:FiddleHandle.csandpackage-release.share byte for byte identical. The test files are not: both PRs addFiddle_AnsiSuffix1at the same spot, and this one adds thePackPointer_*tests next to it. So merge this PR before #38. #38 then takes this PR's two test files, which contain everything its own do, reverts its reline change, and updates its 4.0.3 notes. Merged the other way round, #38's reline change would land on master.2.
pack("p")writes a real address[str].pack("p")and("P")wrote an index into the packed string's list of Strings, not an address. reline'sWin32APIhands the console API every buffer as[str].pack("p").unpack("q*")and reads what the call wrote fromstr. So in a real console, irb crashed with an access violation infiddle_calli, and so would any gem that passes buffers that way.packpoints at gets its own native block (PackedPointers), holding its bytes and a NUL for as long as the String lives.packwrites the block's address.Fiddle::Function#callrecognises the address among its pointer arguments. It copies the String into the block before the call and the block back into the String after it. In CRuby, the String's own buffer gives the same result.unpack("p"): still finds only Strings packed into that same string ("no associated pointer"), now by address.reline/io/windows.rbis not touched; it stays as upstream has it. #38 changed it to pass Strings to Fiddle instead, and it reverts that once this PR is merged.Tests
Fiddle_AnsiSuffix1: theAsuffix, and the message for an unknown symbol.PackPointer_RealAddress1, all platforms: C reads and writes throughpack("p")(strlen,memset,Fiddle::Pointer#to_s); theunpackround trip,nil, and the error for a foreign address. It checks the address before C touches it, so a regression fails the test instead of killing the run. Without the fix it reports the old indexes,[:not_an_address, 1, 1].PackPointer_RelineWin32Api1, Windows: reline's own, unmodifiedWin32APIfills a buffer throughGetModuleFileNameA. That is the path that crashed.42.> FAILEDline to count, so until now such a run passed.Checked
core/array/packandcore/string/unpack: 3193 examples, 0 failures. The full C# suite passes.pack("p")gives output byte-identical to CRuby 4.0.1.p 6 * 7, Enter,exit, Enter withWriteConsoleInputW, then runs irb, which reads them throughReadConsoleInputW. CRuby 4.0.1 and this branch show the same thing: the prompt,42, and a clean exit. On master, irb crashes with0xC0000005.Summary by CodeRabbit