oracle / truffleruby

A high performance implementation of the Ruby programming language, built on GraalVM.
https://www.graalvm.org/ruby/
Other
2.99k stars 180 forks source link

Odd directory traversal behaviour (different compared to ruby and jruby)? #3464

Closed hainesr closed 4 months ago

hainesr commented 4 months ago

When using Dir to create and list items in a directory I think I've spotted different behaviour in truffleruby compared to ruby and jruby.

TL;DR: if I create a directory, and some items in it, then immediately try to loop through the new directory's contents, the new items are not traversed until the directory is rewound. In ruby and jruby they are traversed immediately.

To replicate I used this script:

require 'tmpdir'

Dir.mktmpdir do |dir|
  test_dir = File.join(dir, 'test_dir')
  Dir.mkdir(test_dir)
  Dir.open(test_dir) do |d|
    puts "\nList empty directory"
    d.each { |f| p f }

    puts "\nCreating a file and a subdirectory..."
    Dir.mkdir(File.join(test_dir, 'subdir'))
    File.open(File.join(test_dir, 'test.txt'), 'w') { |f| f.puts 'testing' }

    puts "\nList non-empty directory"
    d.each { |f| p f }

    puts "\nRewind and list non-empty directory again"
    d.rewind
    d.each { |f| p f }
  end
end

With ruby:

$ ruby -v dir_test.rb 
ruby 3.2.0 (2022-12-25 revision a528908271) [arm64-darwin21]

List empty directory
"."
".."

Creating a file and a subdirectory...

List non-empty directory
"."
".."
"subdir"
"test.txt"

Rewind and list non-empty directory again
"."
".."
"subdir"
"test.txt"

With jruby:

$ ruby -v dir_test.rb 
jruby 9.4.6.0 (3.1.4) 2024-02-20 576fab2c51 Java HotSpot(TM) 64-Bit Server VM 17.0.2+8-LTS-86 on 17.0.2+8-LTS-86 +jit [arm64-darwin]

List empty directory
"."
".."

Creating a file and a subdirectory...

List non-empty directory
"."
".."
"subdir"
"test.txt"

Rewind and list non-empty directory again
"."
".."
"subdir"
"test.txt"

With truffleruby:

$ ruby -v dir_test.rb 
truffleruby 23.1.2, like ruby 3.2.2, Oracle GraalVM Native [aarch64-darwin]

List empty directory
"."
".."

Creating a file and a subdirectory...

List non-empty directory

Rewind and list non-empty directory again
"."
".."
"subdir"
"test.txt"

In the truffleruby case you can see that nothing is listed second time, almost as if it's remembering where it ended up after listing the empty directory, but not having "seen" the new entries yet either. In the other rubies you can keep looping through the directory entries without rewinding in between.

eregon commented 4 months ago

Thank you for the report. From that behavior it looks like Dir#each automatically rewinds just before returning. It should be trivial to fix, we just need to verify that is indeed what the implementation does in CRuby.

eregon commented 4 months ago

Actually it's the opposite, Dir#each rewinds before starting to iterate: https://github.com/ruby/ruby/blob/dddf62426b7a384715dd558773723ecbdfa37a11/dir.c#L844-L859

andrykonchin commented 4 months ago

Fixed in db4908a963b6b41ad8a4901da89b76bce1cbcf32.