collapse Table of Contents
  1. POSIX Says The Darndest Things - Jonathan Pryor's web log
    1. POSIX Says The Darndest Things

POSIX Says The Darndest Things - Jonathan Pryor's web log

« Rides | Main | Mono.Fuse 0.4.2 »

POSIX Says The Darndest Things

make check was reported to be failing earlier this week, and Mono.Posix was one of the problem areas:

1) MonoTests.Mono.Unix.UnixGroupTest.ListAllGroups_ToString : #TLAU_TS:
Exception listing local groups: System.IO.FileNotFoundException: Nie ma
takiego pliku ani katalogu ---> Mono.Unix.UnixIOException: Nie ma
takiego pliku ani katalogu [ENOENT].
  at Mono.Unix.UnixMarshal.ThrowExceptionForLastError () [0x00000] in
  at Mono.Unix.UnixGroupInfo.GetLocalGroups () [0x0001c] in
  at MonoTests.Mono.Unix.UnixGroupTest.ListAllGroups_ToString ()
[0x0000a] in
  at MonoTests.Mono.Unix.UnixGroupTest.ListAllGroups_ToString ()
[0x0003c] in
  at <0x00000> <unknown method>
  at (wrapper managed-to-native)
System.Reflection.MonoMethod:InternalInvoke (object,object[])
  at System.Reflection.MonoMethod.Invoke (System.Object obj,
BindingFlags invokeAttr, System.Reflection.Binder binder,
System.Object[] parameters, System.Globalization.CultureInfo culture)
[0x00040] in

Further investigation narrowed things down to Mono_Posix_Syscall_setgrent() in support/grp.c:

Mono_Posix_Syscall_setgrent (void)
	errno = 0;
	setgrent ();
	return errno == 0 ? 0 : -1;

I did this because setgrent(3) can fail, even though it has a void return type; quoting the man page:

Upon error, errno may be set. If one wants to check errno after the call, it should be set to zero before the call.

Seems reasonably straightforward, no? Clear errno, do the function call, and if errno is set, an error occurred.

Except that this isn't true. On Gentoo and Debian, calling setgrent(3) may set errno to ENOENT (no such file or directory), because setgrent(3) tries to open the file /etc/default/nss. Consequently, Mono.Unix.UnixGroupInfo.GetLocalGroups reported an error (as can be seen in the above stack trace).

Further discussion with some Debian maintainers brought forth the following detail: It's only an error if it's a documented error. So even though setgrent(3) set errno, it wasn't an error because ENOENT isn't one of the documented error values for setgrent(3).

"WTF!," says I.

So I dutifully go off and fix it, so that only documented errors result in an error:

Mono_Posix_Syscall_setgrent (void)
	errno = 0;
	do {
		setgrent ();
	} while (errno == EINTR);
	mph_return_if_val_in_list5(errno, EIO, EMFILE, ENFILE, ENOMEM, ERANGE);
	return 0;

...and then I go through the rest of the MonoPosixHelper code looking for other such erroneous use of errno and error reporting. There are several POSIX functions with void return types that are documented as generating no errors, and others are like setgrent(3) where they may generate an error.

It's unfortunate that POSIX has void functions that can trigger an error. It makes binding POSIX more complicated than it should be.

Posted on 29 Jun 2007 | Path: /development/mono/ | Permalink
blog comments powered by Disqus