[ruby-core:123724] [Ruby Bug#21672] `IO::Buffer.new` does not check that flags are valid
Issue #21672 has been reported by trinistr (Alexander Bulancov). ---------------------------------------- Bug #21672: `IO::Buffer.new` does not check that flags are valid https://bugs.ruby-lang.org/issues/21672 * Author: trinistr (Alexander Bulancov) * Status: Open * ruby -v: ruby 3.4.7 (2025-10-08 revision 7a5688e2a2) +PRISM [x86_64-linux] * Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- `IO::Buffer.new` has a `flags` argument that allows to override automatic decision between INTERNAL and MAPPED. As far as I understand, these modes are supposed to be exclusive, however in practice there is no check, and the user is free to specify both: ``` IO::Buffer.new(10, IO::Buffer::MAPPED|IO::Buffer::INTERNAL) # => # #<IO::Buffer 0x0000555bfdccf760+10 INTERNAL MAPPED> # 0x00000000 00 00 00 00 00 00 00 00 00 00 .......... ``` From the source code in https://github.com/ruby/ruby/blob/master/io_buffer.c#L204, the real mode seems to be INTERNAL. I imagine that the order of branches can be reversed with changes, suddenly changing behavior. Even worse, if at least one of `INTERNAL` or `MAPPED` is specified, flags are not checked at all, allowing complete nonsense: ``` IO::Buffer.new(10, 0xffffff) # #<IO::Buffer 0x000055672a653190+10 EXTERNAL INTERNAL MAPPED SHARED LOCKED PRIVATE READONLY> ``` `IO::Buffer.map` also exhibits this issue, though I'm unsure if this combination of flags is actually invalid (it at least doesn't get LOCKED): ``` IO::Buffer.map(File.open('README.md', 'r+'), nil, 0, 0xffffff) # #<IO::Buffer 0x00007fd8edb90000+9024 MAPPED FILE PRIVATE READONLY> ``` -- https://bugs.ruby-lang.org/
Issue #21672 has been updated by trinistr (Alexander Bulancov). Also not sure if this is intentional, but a buffer mapped from a file with `IO::Buffer::PRIVATE` is neither internal nor external: ``` IO::Buffer.map(File.open("README.md", "r+"), nil, 0, IO::Buffer::PRIVATE).external? # => false IO::Buffer.map(File.open("README.md", "r+"), nil, 0, IO::Buffer::PRIVATE).internal? # => false ``` ---------------------------------------- Bug #21672: `IO::Buffer.new` does not check that flags are valid https://bugs.ruby-lang.org/issues/21672#change-115120 * Author: trinistr (Alexander Bulancov) * Status: Open * ruby -v: ruby 3.4.7 (2025-10-08 revision 7a5688e2a2) +PRISM [x86_64-linux] * Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- `IO::Buffer.new` has a `flags` argument that allows to override automatic decision between INTERNAL and MAPPED. As far as I understand, these modes are supposed to be exclusive, however in practice there is no check, and the user is free to specify both: ``` IO::Buffer.new(10, IO::Buffer::MAPPED|IO::Buffer::INTERNAL) # => # #<IO::Buffer 0x0000555bfdccf760+10 INTERNAL MAPPED> # 0x00000000 00 00 00 00 00 00 00 00 00 00 .......... ``` From the source code in https://github.com/ruby/ruby/blob/master/io_buffer.c#L204, the real mode seems to be INTERNAL. I imagine that the order of branches can be reversed with changes, suddenly changing behavior. Even worse, if at least one of `INTERNAL` or `MAPPED` is specified, flags are not checked at all, allowing complete nonsense: ``` IO::Buffer.new(10, 0xffffff) # #<IO::Buffer 0x000055672a653190+10 EXTERNAL INTERNAL MAPPED SHARED LOCKED PRIVATE READONLY> ``` `IO::Buffer.map` also exhibits this issue, though I'm unsure if this combination of flags is actually invalid (it at least doesn't get LOCKED): ``` IO::Buffer.map(File.open('README.md', 'r+'), nil, 0, 0xffffff) # #<IO::Buffer 0x00007fd8edb90000+9024 MAPPED FILE PRIVATE READONLY> ``` -- https://bugs.ruby-lang.org/
Issue #21672 has been updated by mame (Yusuke Endoh). Status changed from Open to Assigned Assignee set to ioquatix (Samuel Williams) ---------------------------------------- Bug #21672: `IO::Buffer.new` does not check that flags are valid https://bugs.ruby-lang.org/issues/21672#change-115154 * Author: trinistr (Alexander Bulancov) * Status: Assigned * Assignee: ioquatix (Samuel Williams) * ruby -v: ruby 3.4.7 (2025-10-08 revision 7a5688e2a2) +PRISM [x86_64-linux] * Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- `IO::Buffer.new` has a `flags` argument that allows to override automatic decision between INTERNAL and MAPPED. As far as I understand, these modes are supposed to be exclusive, however in practice there is no check, and the user is free to specify both: ``` IO::Buffer.new(10, IO::Buffer::MAPPED|IO::Buffer::INTERNAL) # => # #<IO::Buffer 0x0000555bfdccf760+10 INTERNAL MAPPED> # 0x00000000 00 00 00 00 00 00 00 00 00 00 .......... ``` From the source code in https://github.com/ruby/ruby/blob/master/io_buffer.c#L204, the real mode seems to be INTERNAL. I imagine that the order of branches can be reversed with changes, suddenly changing behavior. Even worse, if at least one of `INTERNAL` or `MAPPED` is specified, flags are not checked at all, allowing complete nonsense: ``` IO::Buffer.new(10, 0xffffff) # #<IO::Buffer 0x000055672a653190+10 EXTERNAL INTERNAL MAPPED SHARED LOCKED PRIVATE READONLY> ``` `IO::Buffer.map` also exhibits this issue, though I'm unsure if this combination of flags is actually invalid (it at least doesn't get LOCKED): ``` IO::Buffer.map(File.open('README.md', 'r+'), nil, 0, 0xffffff) # #<IO::Buffer 0x00007fd8edb90000+9024 MAPPED FILE PRIVATE READONLY> ``` -- https://bugs.ruby-lang.org/
Issue #21672 has been updated by ioquatix (Samuel Williams). Thanks, I'll review. IIRC, the flags provided can be advisory, e.g. a small buffer but use mapped memory. ---------------------------------------- Bug #21672: `IO::Buffer.new` does not check that flags are valid https://bugs.ruby-lang.org/issues/21672#change-115155 * Author: trinistr (Alexander Bulancov) * Status: Assigned * Assignee: ioquatix (Samuel Williams) * ruby -v: ruby 3.4.7 (2025-10-08 revision 7a5688e2a2) +PRISM [x86_64-linux] * Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- `IO::Buffer.new` has a `flags` argument that allows to override automatic decision between INTERNAL and MAPPED. As far as I understand, these modes are supposed to be exclusive, however in practice there is no check, and the user is free to specify both: ``` IO::Buffer.new(10, IO::Buffer::MAPPED|IO::Buffer::INTERNAL) # => # #<IO::Buffer 0x0000555bfdccf760+10 INTERNAL MAPPED> # 0x00000000 00 00 00 00 00 00 00 00 00 00 .......... ``` From the source code in https://github.com/ruby/ruby/blob/master/io_buffer.c#L204, the real mode seems to be INTERNAL. I imagine that the order of branches can be reversed with changes, suddenly changing behavior. Even worse, if at least one of `INTERNAL` or `MAPPED` is specified, flags are not checked at all, allowing complete nonsense: ``` IO::Buffer.new(10, 0xffffff) # #<IO::Buffer 0x000055672a653190+10 EXTERNAL INTERNAL MAPPED SHARED LOCKED PRIVATE READONLY> ``` `IO::Buffer.map` also exhibits this issue, though I'm unsure if this combination of flags is actually invalid (it at least doesn't get LOCKED): ``` IO::Buffer.map(File.open('README.md', 'r+'), nil, 0, 0xffffff) # #<IO::Buffer 0x00007fd8edb90000+9024 MAPPED FILE PRIVATE READONLY> ``` -- https://bugs.ruby-lang.org/
Issue #21672 has been updated by trinistr (Alexander Bulancov). Thank you! For more context: I'm working on IO::Buffer's specs for ruby/spec. This issue was created quite early, as I started with `.new`, and since then I've discovered a whole bunch of questionable or unclear behaviors (or just plain outdated documentation). I've been compiling a list in the PR here: https://github.com/ruby/spec/pull/1297. What's the usual process for dealing with a sizable list of maybe-issues? Creating separate issues for everything here seems like an overkill. I can make PRs for most of that stuff, I think, but it's hard to know what's actually intended sometimes. ---------------------------------------- Bug #21672: `IO::Buffer.new` does not check that flags are valid https://bugs.ruby-lang.org/issues/21672#change-115163 * Author: trinistr (Alexander Bulancov) * Status: Assigned * Assignee: ioquatix (Samuel Williams) * ruby -v: ruby 3.4.7 (2025-10-08 revision 7a5688e2a2) +PRISM [x86_64-linux] * Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- `IO::Buffer.new` has a `flags` argument that allows to override automatic decision between INTERNAL and MAPPED. As far as I understand, these modes are supposed to be exclusive, however in practice there is no check, and the user is free to specify both: ``` IO::Buffer.new(10, IO::Buffer::MAPPED|IO::Buffer::INTERNAL) # => # #<IO::Buffer 0x0000555bfdccf760+10 INTERNAL MAPPED> # 0x00000000 00 00 00 00 00 00 00 00 00 00 .......... ``` From the source code in https://github.com/ruby/ruby/blob/master/io_buffer.c#L204, the real mode seems to be INTERNAL. I imagine that the order of branches can be reversed with changes, suddenly changing behavior. Even worse, if at least one of `INTERNAL` or `MAPPED` is specified, flags are not checked at all, allowing complete nonsense: ``` IO::Buffer.new(10, 0xffffff) # #<IO::Buffer 0x000055672a653190+10 EXTERNAL INTERNAL MAPPED SHARED LOCKED PRIVATE READONLY> ``` `IO::Buffer.map` also exhibits this issue, though I'm unsure if this combination of flags is actually invalid (it at least doesn't get LOCKED): ``` IO::Buffer.map(File.open('README.md', 'r+'), nil, 0, 0xffffff) # #<IO::Buffer 0x00007fd8edb90000+9024 MAPPED FILE PRIVATE READONLY> ``` -- https://bugs.ruby-lang.org/
Issue #21672 has been updated by headius (Charles Nutter). @trinistr First off, Thanks for your work on specs recently. I did a quick implementation of IO::Buffer for j Ruby last year but only relied on the core tests. Having a complete set of specs will be very helpful. Along with these flags, I want to point out that there's likely platform specific behaviors in this class that will need special treatment in tests and specs. Some of the features can't be supported outside of CRuby's runtime, some of them will be specific to unix's or even specific types of unix, etc. The JRuby implementation ships with all recent builds of JRuby 10, so it would be worth comparing the specs with our version of behavior as well (and of course I'll have to pass those specs at some point anyway). Feel free to contact me directly at headius@headius.com or on the JRuby Matrix chat room if you have questions or want to work together on this. ---------------------------------------- Bug #21672: `IO::Buffer.new` does not check that flags are valid https://bugs.ruby-lang.org/issues/21672#change-115164 * Author: trinistr (Alexander Bulancov) * Status: Assigned * Assignee: ioquatix (Samuel Williams) * ruby -v: ruby 3.4.7 (2025-10-08 revision 7a5688e2a2) +PRISM [x86_64-linux] * Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- `IO::Buffer.new` has a `flags` argument that allows to override automatic decision between INTERNAL and MAPPED. As far as I understand, these modes are supposed to be exclusive, however in practice there is no check, and the user is free to specify both: ``` IO::Buffer.new(10, IO::Buffer::MAPPED|IO::Buffer::INTERNAL) # => # #<IO::Buffer 0x0000555bfdccf760+10 INTERNAL MAPPED> # 0x00000000 00 00 00 00 00 00 00 00 00 00 .......... ``` From the source code in https://github.com/ruby/ruby/blob/master/io_buffer.c#L204, the real mode seems to be INTERNAL. I imagine that the order of branches can be reversed with changes, suddenly changing behavior. Even worse, if at least one of `INTERNAL` or `MAPPED` is specified, flags are not checked at all, allowing complete nonsense: ``` IO::Buffer.new(10, 0xffffff) # #<IO::Buffer 0x000055672a653190+10 EXTERNAL INTERNAL MAPPED SHARED LOCKED PRIVATE READONLY> ``` `IO::Buffer.map` also exhibits this issue, though I'm unsure if this combination of flags is actually invalid (it at least doesn't get LOCKED): ``` IO::Buffer.map(File.open('README.md', 'r+'), nil, 0, 0xffffff) # #<IO::Buffer 0x00007fd8edb90000+9024 MAPPED FILE PRIVATE READONLY> ``` -- https://bugs.ruby-lang.org/
participants (4)
-
headius (Charles Nutter) -
ioquatix (Samuel Williams) -
mame (Yusuke Endoh) -
trinistr (Alexander Bulancov)