-
-
Notifications
You must be signed in to change notification settings - Fork 942
Description
Environment
Environment details:
- Java HotSpot(TM) 64-Bit Server VM (25.51-b03) for windows-amd64 JRE (1.8.0_51-b16), built on Jun 8 2015 18:03:07 by "java_re" with MS VC++ 10.0 (VS2010)
- Windows 7 , 64 bit Build 7601 (6.1.7601.23572)
- JRuby 9.1.6.0
Gems in use:
- FFI 1.9.14-java
Additional source code:
- Hephaestus "jruby-fixes" branch at commit "4d40fe7"
Expected Behavior
- The syntax of
arg || CONSTANT(evaluates tonil || 0x00 # => 0) should not cause a TypeError. - When a Memory Pointer with a length which matches the source ASCII-8Bit -encoded string from which it is derived is passed, a
NULLshould not be received. - Execution of code which operates correctly in Ruby 2.3.3 (MRI) should not greatly differ when executed in JRuby 9k.
Actual Behavior
All observations are currently drawn from the source file environment.rb in the Hephaestus project, a wrapper for Vulkan written in Ruby. Insofar it works as expected on the pre-compiled mingw32-x64 build of ruby-ffi, but the -java derivative is encountering strange behavioral differences.
- At line 245,
from || VK_NULL_HANDLE, which by default translates tonil || 0x00causes aTypeError("no implicit conversion of FFI::MemoryPointer to Integer"). - Likewise at line 318,
pCode: bin.to_ptrassignment using the Struct constructor mixin to assign from kwargs causes the following, after which JRuby may segfault or simply crash with an OS-level "application not responding" warning:
ParameterValidation(ERROR): object: 0x0 type: 0 location: 190 msgCode: 4: vkCre
ateShaderModule: required parameter pCreateInfo->pCode specified as NULL
SC(ERROR): object: 0x0 type: 0 location: 10277 msgCode: 5: SPIR-V module not va
lid: Invalid SPIR-V magic number.
Inside the diagnostic output (enabled with -v on the jruby-fixes branch), the reference pCode is clearly identified as being an FFI::MemoryPointer with a real address and a length of 1281 bytes (+1 byte from appending \x00, which is reflected from core FFI behaviors).
The .to_ptr contrivance is another mix-in which allows most basic Ruby objects to be rendered into FFI::MemoryPointer instances by translating their contents. In the above case, it is shorthand for FFI::MemoryPointer.from_string( bin ).
Caveats
Redoing the test without the validation layer causes the crash regardless, making me suspect it is only potentially not an issue with Vulkan (as the SDK is now being bypassed) which is causing the crash. However, I do recall there having been a potential crash in MRI before when I had accidentally passed in the raw GLSL files (as opposed to the correct SPIR-V files).
This does not change the fact that identical syntax between the two implementations of Ruby are not behaving in an identical manner, or that a pointer appears to be shedding or losing its content without warning as though it were being released / GC'd while within the scope of its creation.
JVM Dump
I've captured some findings (replicated above), as well as the output from the JVM when the crash is encountered. You can view it in this gist here.
Test File
I've reproduced the test file below, which uses the raw source of the project (as opposed to the gem, to allow more rapid development). It has not been altered from the code I would use for my personal machine, and thus the adapter name and environment variables may not reflect what you would use.
# modify environment
ENV['PATH'] = './bin;' + ENV['PATH']
ENV['VK_LAYER_PATH'] = 'D:/VulkanSDK/1.0.33.0/Bin'
# load and track time
top = Time.now
require_relative '../vulkan'
require_relative '../lib/utils'
include Vulkan, GLFW3
puts "Loaded Vulkan in #{Time.now - top} seconds"
# mark head
$mark = Time.now
$failed = false
# setup
begin
puts 'Creating environment ...'
$env = Vulkan::Environment.new(
'Test',
adapter: 'GTX 660',
validation: 'VK_LAYER_LUNARG_standard_validation'
)
puts 'Setting up window ...'
win = Vulkan::Window.new( 1280, 800, $env )
puts 'Finishing initialization: '
puts ' - create rendering path ...'
$env.create_default_rendering_path
puts ' - create framebuffers ...'
$env.create_framebuffers
puts ' - create commandpool ...'
$env.create_commandpool
puts ' - create command buffers ...'
$env.create_commandbuffers
puts 'Done.'
rescue Exception => err
root = Dir.pwd + '/'
warn "#{err.class.name}: #{err}", *err.backtrace.map {|line| " " + line.gsub( root, '') }
$failed = true
ensure
dT = Time.now - $mark
puts "Initialization attempt #{$failed ? 'FAILED' : 'succeeded'} after #{dT} seconds",
"Environment details:",
"--------------------",
$env.inspect
end