Home > programming > Bug hunting

Bug hunting

It might seem that everything is clear about D and Ruby interaction.

Not quite so, as it turns out. Let’s consider this (almost) trivial example:

test.d:

module test;
...
import std.array : array;
import std.algorithm : splitter;

extern (C) void foo() {
 array(splitter("abc", ' ')); // any string will do
}
...

test.rb:

#!/usr/bin/env ruby
require 'ffi'
module Bar
 extend FFI::Library
 ffi_lib './test.so'
 attach_function :foo, [], :void # bind our function
end
Bar.foo # let's call it!

(Full code and Makefile is available at https://gist.github.com/2366623)

Running this Ruby code leads to a segmentation fault with the following backtrace:

...
./test.so(+0x297d0) [0xf72017d0]
./test.so(_D3std5array18__T8AppenderTAAyaZ8Appender11newCapacityFkZk+0x33) [0xf7202f6f] /usr/include/d/std/array.d:1984
./test.so(_D3std5array18__T8AppenderTAAyaZ8Appender13ensureAddableMFkZv+0x66) [0xf7202e82] /usr/include/d/std/array.d:1960
./test.so(_D3std5array18__T8AppenderTAAyaZ8Appender12__T3putTAyaZ3putMFAyaZv+0x52) [0xf7203146] /usr/include/d/std/array.d:2007
./test.so(_D3std5array63__T5arrayTS3std9algorithm19__T8splitterTAyaTaZ8splitter6ResultZ5arrayFS3std9algorithm19__T8splitterTAyaTaZ8splitterFAyaaZS3std9algorithm19__T8splitterTAyaTaZ8splitter6Result6ResultZAAya+0x5e) [0xf7202b36] /usr/include/d/std/array.d:66
...

What the hell is going on?! Let’s investigate…

By looking at std.array source code near the lines mentioned in backtrace, and some playing with it (I, for example, inserted printf call before 1984th line to test which expression causes segfault), I managed to make our foo even simpler:

import core.bitop : bsr;

extern (C) void foo() {
 auto dummy = 0L / bsr(2);
}

Now, some simple observations.

  1. If you change 0L to 0 without ‘L’, you get no segfault.
  2. If you replace bsr(2) with its value, i.e. 1, you also get no segfault.
  3. If this construction is used in standalone D application, everything is also OK.
  4. If we don’t use the sophisticated scheme with Runtime.initialize() and Runtime.terminate(), everything also works fine. (Let me remind you that it’s necessary to initialize D runtime in order to be able to use its GC and most library functions.) That is, if you call attach and detach functions manually via FFI, it’s ok.
  5. If you replace / with +, -, or *, also no segfault.

Sounds completely crazy, doesn’t it?

Good news is that our observations contain a workaround: don’t use linking with C object file but use -shared flag of dmd instead, and call D runtime initialization function manually. I believe it should work. And, as a matter of fact, D should support “static this() {…}” as a function to be called at library loading. So basically, this workaround is just replacing one kludge with another.

Advertisements
Categories: programming Tags: ,
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: