collapse Table of Contents
  1. When Comparisons Fail - Jonathan Pryor's web log
    1. When Comparisons Fail

When Comparisons Fail - Jonathan Pryor's web log

« openSUSE 10.2 Windows Key Solution | Main | Mono.Fuse 0.4.1 »

When Comparisons Fail

One of the unsung helper programs for Mono.Fuse and Mono.Unix is create-native-map ( man page), which takes an assembly, looks for DllImport-attributed methods, and generates C structure and function prototypes for those methods and related types. This allows e.g. the internal Mono.Posix.dll methods to be kept in sync with their implementation methods in MonoPosixHelper, checked by the compiler to ensure type consistency.

One of the "features" of create-native-map is support for integer overflow checking. For example, if you have a C# type:

[Map ("struct foo")]
struct Foo {
  public int member;
}

then create-native-map will generate the (excerpted) C code (it generates much more):

struct Foo {
  int member;
};

int ToFoo (struct foo *from, struct Foo *to)
{
  _cnm_return_val_if_overflow (int, from->member, -1);
  to->member = from->member;
	return 0;
}

This could be handy, as if the actual type of struct foo::member differed from int, we could tell at runtime if the value of from->member wouldn't fit within to->member. That was the hope, anyway. (Yes, this flexibility is required, as many Unix structures only standardize member name and type, but not necessarily the actual type. For example, struct stat::st_nlink is of type nlink_t, which will vary between platforms, but Mono.Unix.Native.Stat.st_nlink can't change between platforms, it needs to expose an ABI-agnostics interface for portability. Consequently, overflow checking is desirable when doing Statstruct stat conversions, and vice versa, to ensure that nothing is lost.)

The reality is that _cnm_return_val_if_overflow() was horribly buggy and broke if you looked at it wrong (i.e. it worked for me and would fail on many of the build machines running !Linux). Consequently _cnm_return_val_if_overflow() was converted into a no-op unless DEBUG is defined before/during the Mono 1.2.0 release.

Why discuss this now? Because Mono.Fuse 0.4.0 shipped with a broken version of create-native-map, which is the primary reason that it doesn't work with MacFUSE.

But because I'm a glutton-for-punishment/insane, I thought I'd take a look into making overflow checking work again (though it still won't be enabled unless DEBUG is defined). I wrote some tests, got them working on Linux, and tried to run them on Intel Mac OS X. The result: all but one worked. The reason it failed is inexplicable: a failing comparison. G_MININT64 can't be directly compared against 0:

$ cat ovf.c
# include <glib.h>
# include <limits.h>
# include <stdio.h>

int main ()
{
  long long v = G_MININT64;
  printf (" LLONG_MIN < 0? %i\n", (int) (LLONG_MIN < 0));
  printf ("G_MININT64 < 0? %i\n", (int) (G_MININT64 < 0));
  printf ("         v < 0? %i\n", (int) (v < 0));
}

$ gcc -o ovf ovf.c `pkg-config --cflags --libs glib-2.0`
$ ./ovf
 LLONG_MIN < 0? 1
G_MININT64 < 0? 0
         v < 0? 1

Now that's a w-t-f: G_MININT64 < 0 is FALSE. Simply bizarre...

Meanwhile, I should have a Mono.Fuse 0.4.1 release out "soon" to fix these problems, permitting Mono.Fuse to work properly with MacFUSE.

Posted on 12 Apr 2007 | Path: /development/mono/ | Permalink
blog comments powered by Disqus