From 7fe7f931887baa2968b081725bb417ebc368dc01 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 3 Aug 2015 10:48:25 -0400 Subject: [PATCH] Posix RTS test fixes and Android compatibility Android's libc (bionic) defines the _GNU_SOURCE macro but fails to adhere to the GNU sematics in (at least) one case - the strerror_r function. The function follows XSI semantics instead of the GNU one which caused our code to segfault on Android. This patch special-cases Android to use the XSI semantics for strerror_r. This un-breaks some POSX real-time singals tests. It also makes provisions for detecting whether the real-time signals are safe to use on the current platform. They are safe for all platforms desktop Mono runs on, but they're not safe on most Android platforms. --- .../Mono.Posix/Mono.Posix_test.dll.sources | 1 + .../Mono.Unix.Native/NativeConvert.cs | 4 ++-- .../Test/Mono.Unix.Android/TestHelper.cs | 12 ++++++++++ .../Mono.Unix.Native/RealTimeSignumTests.cs | 17 ++++++++++++++ .../Test/Mono.Unix/UnixSignalTest.cs | 15 +++++++++++++ support/errno.c | 22 ++++++++++++++++++- 6 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 mcs/class/Mono.Posix/Test/Mono.Unix.Android/TestHelper.cs diff --git a/mcs/class/Mono.Posix/Mono.Posix_test.dll.sources b/mcs/class/Mono.Posix/Mono.Posix_test.dll.sources index 270b0b6aee6..0f84821b52e 100644 --- a/mcs/class/Mono.Posix/Mono.Posix_test.dll.sources +++ b/mcs/class/Mono.Posix/Mono.Posix_test.dll.sources @@ -6,5 +6,6 @@ Mono.Unix/UnixMarshalTest.cs Mono.Unix/UnixPathTest.cs Mono.Unix/UnixSignalTest.cs Mono.Unix/UnixUserTest.cs +Mono.Unix.Android/TestHelper.cs Mono.Unix.Native/RealTimeSignumTests.cs Mono.Unix.Native/StdlibTest.cs diff --git a/mcs/class/Mono.Posix/Mono.Unix.Native/NativeConvert.cs b/mcs/class/Mono.Posix/Mono.Unix.Native/NativeConvert.cs index ffa329f1b5b..4e2613b1279 100644 --- a/mcs/class/Mono.Posix/Mono.Unix.Native/NativeConvert.cs +++ b/mcs/class/Mono.Posix/Mono.Unix.Native/NativeConvert.cs @@ -17,10 +17,10 @@ namespace Mono.Unix.Native { // // Non-generated exports // - +#if !MONODROID [DllImport (LIB, EntryPoint="Mono_Posix_FromRealTimeSignum")] private static extern int FromRealTimeSignum (Int32 offset, out Int32 rval); - +#endif // convert a realtime signal to os signal public static int FromRealTimeSignum (RealTimeSignum sig) { diff --git a/mcs/class/Mono.Posix/Test/Mono.Unix.Android/TestHelper.cs b/mcs/class/Mono.Posix/Test/Mono.Unix.Android/TestHelper.cs new file mode 100644 index 00000000000..a7a56a48c69 --- /dev/null +++ b/mcs/class/Mono.Posix/Test/Mono.Unix.Android/TestHelper.cs @@ -0,0 +1,12 @@ +namespace Mono.Unix.Android +{ + // Another version of this class is used by the Xamarin.Android test suite + // It is here to keep the test code #ifdef free as much as possible + public class TestHelper + { + public static bool CanUseRealTimeSignals () + { + return true; + } + } +} \ No newline at end of file diff --git a/mcs/class/Mono.Posix/Test/Mono.Unix.Native/RealTimeSignumTests.cs b/mcs/class/Mono.Posix/Test/Mono.Unix.Native/RealTimeSignumTests.cs index 4aea4e8ba60..f68fe53b8ce 100644 --- a/mcs/class/Mono.Posix/Test/Mono.Unix.Native/RealTimeSignumTests.cs +++ b/mcs/class/Mono.Posix/Test/Mono.Unix.Native/RealTimeSignumTests.cs @@ -15,6 +15,7 @@ using System; using System.Text; using System.Threading; using Mono.Unix; +using Mono.Unix.Android; using Mono.Unix.Native; namespace MonoTests.Mono.Unix.Native { @@ -27,6 +28,8 @@ namespace MonoTests.Mono.Unix.Native { [ExpectedException (typeof (ArgumentOutOfRangeException))] public void TestRealTimeOutOfRange () { + if (!TestHelper.CanUseRealTimeSignals ()) + return; RealTimeSignum rts = new RealTimeSignum (int.MaxValue); } @@ -34,12 +37,16 @@ namespace MonoTests.Mono.Unix.Native { [ExpectedException (typeof (ArgumentOutOfRangeException))] public void TestRealTimeSignumNegativeOffset () { + if (!TestHelper.CanUseRealTimeSignals ()) + return; RealTimeSignum rts1 = new RealTimeSignum (-1); } [Test] public void TestRTSignalEquality () { + if (!TestHelper.CanUseRealTimeSignals ()) + return; RealTimeSignum rts1 = new RealTimeSignum (0); RealTimeSignum rts2 = new RealTimeSignum (0); Assert.That (rts1 == rts2, Is.True); @@ -49,6 +56,8 @@ namespace MonoTests.Mono.Unix.Native { [Test] public void TestRTSignalInequality () { + if (!TestHelper.CanUseRealTimeSignals ()) + return; RealTimeSignum rts1 = new RealTimeSignum (0); RealTimeSignum rts2 = new RealTimeSignum (1); Assert.That (rts1 == rts2, Is.False); @@ -58,6 +67,8 @@ namespace MonoTests.Mono.Unix.Native { [Test] public void TestRTSignalGetHashCodeEquality () { + if (!TestHelper.CanUseRealTimeSignals ()) + return; RealTimeSignum rts1 = new RealTimeSignum (0); RealTimeSignum rts2 = new RealTimeSignum (0); Assert.That (rts1.GetHashCode (), Is.EqualTo(rts2.GetHashCode ())); @@ -66,6 +77,8 @@ namespace MonoTests.Mono.Unix.Native { [Test] public void TestRTSignalGetHashCodeInequality () { + if (!TestHelper.CanUseRealTimeSignals ()) + return; RealTimeSignum rts1 = new RealTimeSignum (0); RealTimeSignum rts2 = new RealTimeSignum (1); Assert.That (rts1.GetHashCode (), Is.Not.EqualTo(rts2.GetHashCode ())); @@ -74,6 +87,8 @@ namespace MonoTests.Mono.Unix.Native { [Test] public void TestIsRTSignalPropertyForRTSignum () { + if (!TestHelper.CanUseRealTimeSignals ()) + return; UnixSignal signal1 = new UnixSignal(new RealTimeSignum (0)); Assert.That (signal1.IsRealTimeSignal, Is.True); } @@ -81,6 +96,8 @@ namespace MonoTests.Mono.Unix.Native { [Test] public void TestIsRTSignalPropertyForSignum () { + if (!TestHelper.CanUseRealTimeSignals ()) + return; UnixSignal signal1 = new UnixSignal (Signum.SIGSEGV); Assert.That (signal1.IsRealTimeSignal, Is.False); } diff --git a/mcs/class/Mono.Posix/Test/Mono.Unix/UnixSignalTest.cs b/mcs/class/Mono.Posix/Test/Mono.Unix/UnixSignalTest.cs index b7b4e6fc695..f88defeaff5 100644 --- a/mcs/class/Mono.Posix/Test/Mono.Unix/UnixSignalTest.cs +++ b/mcs/class/Mono.Posix/Test/Mono.Unix/UnixSignalTest.cs @@ -15,6 +15,7 @@ using System; using System.Text; using System.Threading; using Mono.Unix; +using Mono.Unix.Android; using Mono.Unix.Native; #if !MONODROID namespace NUnit.Framework.SyntaxHelpers { class Dummy {} } @@ -127,6 +128,8 @@ namespace MonoTests.Mono.Unix { [Category ("NotOnMac")] public void TestRealTimeCstor () { + if (!TestHelper.CanUseRealTimeSignals ()) + return; RealTimeSignum rts = new RealTimeSignum (0); using (UnixSignal s = new UnixSignal (rts)) { @@ -140,6 +143,8 @@ namespace MonoTests.Mono.Unix { [Category ("NotOnMac")] public void TestSignumPropertyThrows () { + if (!TestHelper.CanUseRealTimeSignals ()) + return; UnixSignal signal1 = new UnixSignal (new RealTimeSignum (0)); Signum s = signal1.Signum; } @@ -148,6 +153,8 @@ namespace MonoTests.Mono.Unix { [Category ("NotOnMac")] public void TestRealTimeSignumProperty () { + if (!TestHelper.CanUseRealTimeSignals ()) + return; RealTimeSignum rts = new RealTimeSignum (0); UnixSignal signal1 = new UnixSignal (rts); Assert.That (signal1.RealTimeSignum, Is.EqualTo (rts)); @@ -158,6 +165,8 @@ namespace MonoTests.Mono.Unix { [Category ("NotOnMac")] public void TestRealTimePropertyThrows () { + if (!TestHelper.CanUseRealTimeSignals ()) + return; UnixSignal signal1 = new UnixSignal (Signum.SIGSEGV); RealTimeSignum s = signal1.RealTimeSignum; } @@ -166,6 +175,8 @@ namespace MonoTests.Mono.Unix { [Category ("NotOnMac")] public void TestRaiseRTMINSignal () { + if (!TestHelper.CanUseRealTimeSignals ()) + return; RealTimeSignum rts = new RealTimeSignum (0); using (UnixSignal signal = new UnixSignal (rts)) { @@ -180,6 +191,8 @@ namespace MonoTests.Mono.Unix { [Category ("NotOnMac")] public void TestRaiseRTMINPlusOneSignal () { + if (!TestHelper.CanUseRealTimeSignals ()) + return; /*this number is a guestimate, but it's ok*/ for (int i = 1; i < 10; ++i) { RealTimeSignum rts = new RealTimeSignum (i); @@ -205,6 +218,8 @@ namespace MonoTests.Mono.Unix { [Category ("NotOnMac")] public void TestCanRegisterRTSignalMultipleTimes () { + if (!TestHelper.CanUseRealTimeSignals ()) + return; /*this number is a guestimate, but it's ok*/ for (int i = 1; i < 10; ++i) { RealTimeSignum rts = new RealTimeSignum (i); diff --git a/support/errno.c b/support/errno.c index 26ee7801691..384451da47c 100644 --- a/support/errno.c +++ b/support/errno.c @@ -35,7 +35,7 @@ Mono_Posix_Stdlib_SetLastError (int error_number) * we assume that the XPG version is present. */ -#ifdef _GNU_SOURCE +#ifdef _GNU_SOURCE && !PLATFORM_ANDROID #define mph_min(x,y) ((x) <= (y) ? (x) : (y)) /* If you pass an invalid errno value to glibc 2.3.2's strerror_r, you get @@ -80,7 +80,27 @@ Mono_Posix_Syscall_strerror_r (int errnum, char *buf, mph_size_t n) mph_return_if_size_t_overflow (n); /* first, check for valid errnum */ +#if PLATFORM_ANDROID + /* Android NDK defines _GNU_SOURCE but strerror_r follows the XSI semantics + * not the GNU one. XSI version returns an integer, as opposed to the GNU one + * which returns pointer to the buffer. + */ + if (strerror_r (errnum, ebuf, sizeof(ebuf)) == -1) { + /* XSI strerror_r will return -1 if errno is set, but if we leave the value + * alone it breaks Mono.Posix StdioFileStream tests, so we'll ignore the value + * and set errno as below + */ + errno = EINVAL; + return -1; + } + r = ebuf; +#else r = strerror_r (errnum, ebuf, sizeof(ebuf)); +#endif + if (!r) { + errno = EINVAL; + return -1; + } len = strlen (r); if (r == ebuf || -- 2.25.1