[Mono.Unix] Fix crasher in StringToHeap (#5639)
[mono.git] / mcs / class / Mono.Posix / Test / Mono.Unix / UnixMarshalTest.cs
index 9ce933379c900612f9191891206d0e92cea76b14..9b0ce35d9614123b25bf97468dbdb3a68be03bfd 100644 (file)
@@ -8,7 +8,9 @@
 
 using NUnit.Framework;
 using System;
+using System.Collections.Generic;
 using System.IO;
+using System.Runtime.InteropServices;
 using System.Text;
 using Mono.Unix;
 
@@ -26,8 +28,8 @@ namespace MonoTests.Mono.Unix {
                }
        }
 
-       [TestFixture]
-       class UnixMarshalTest {
+       [TestFixture, Category ("NotOnWindows")]
+       public class UnixMarshalTest {
 #if false
                public static void Main ()
                {
@@ -38,6 +40,13 @@ namespace MonoTests.Mono.Unix {
                }
 #endif
 
+               [Test]
+               public void BXC10074 ()
+               {
+                       var result = UnixMarshal.StringToHeap (null, Encoding.ASCII);
+                       Assert.AreEqual (IntPtr.Zero, result, "This used to crash due to a NullReferenceException");
+               }
+
                [Test]
                public void TestStringToHeap ()
                {
@@ -51,21 +60,21 @@ namespace MonoTests.Mono.Unix {
                                bool valid_ascii   = (bool)   data [i+1];
                                bool valid_unicode = (bool)   data [i+2];
 
-                               TestStringToHeap (s, valid_ascii, valid_unicode);
+                               StringToHeap (s, valid_ascii, valid_unicode);
                        }
                }
 
-               private static void TestStringToHeap (string s, bool validAscii, bool validUnicode)
+               private static void StringToHeap (string s, bool validAscii, bool validUnicode)
                {
-                       TestStringToHeap (s, Encoding.ASCII, validAscii);
-                       TestStringToHeap (s, Encoding.UTF7, validUnicode);
-                       TestStringToHeap (s, Encoding.UTF8, validUnicode);
-                       TestStringToHeap (s, Encoding.Unicode, validUnicode);
-                       TestStringToHeap (s, Encoding.BigEndianUnicode, validUnicode);
-                       TestStringToHeap (s, new RandomEncoding (), validUnicode);
+                       StringToHeap (s, Encoding.ASCII, validAscii);
+                       StringToHeap (s, Encoding.UTF7, validUnicode);
+                       StringToHeap (s, Encoding.UTF8, validUnicode);
+                       StringToHeap (s, Encoding.Unicode, validUnicode);
+                       StringToHeap (s, Encoding.BigEndianUnicode, validUnicode);
+                       StringToHeap (s, new RandomEncoding (), validUnicode);
                }
 
-               private static void TestStringToHeap (string s, Encoding e, bool mustBeEqual)
+               private static void StringToHeap (string s, Encoding e, bool mustBeEqual)
                {
                        IntPtr p = UnixMarshal.StringToHeap (s, e);
                        try {
@@ -74,8 +83,80 @@ namespace MonoTests.Mono.Unix {
                                        Assert.AreEqual (s, _s, "#TSTA (" + e.GetType() + ")");
                        }
                        finally {
-                               UnixMarshal.Free (p);
+                               UnixMarshal.FreeHeap (p);
+                       }
+               }
+               
+               [Test]
+               public void TestPtrToString ()
+               {
+                       IntPtr p = UnixMarshal.AllocHeap (1);
+                       Marshal.WriteByte (p, 0);
+                       string s = UnixMarshal.PtrToString (p);
+                       UnixMarshal.FreeHeap (p);
+               }
+
+               [Test]
+               public void TestUtf32PtrToString ()
+               {
+                       var utf32NativeEndianNoBom = new UTF32Encoding(
+                               bigEndian: !BitConverter.IsLittleEndian,
+                               byteOrderMark: false,
+                               throwOnInvalidCharacters: true
+                       );
+
+                       // assemble a buffer that contains:
+                       // 1. eight garbage bytes
+                       // 2. the native-endian UTF-32 string "Hello, World" without BOM
+                       // 3. four 0 bytes (as a C wide string terminator)
+                       // 4. the native-endian UTF-32 string "broken" without BOM
+                       // 5. eight 0 bytes
+                       // 6. four garbage bytes
+                       var buf = new List<byte>();
+                       for (int i = 0; i < 2; ++i) {
+                               buf.Add((byte)0x12);
+                               buf.Add((byte)0x34);
+                               buf.Add((byte)0x56);
+                               buf.Add((byte)0x78);
                        }
+
+                       buf.AddRange(utf32NativeEndianNoBom.GetBytes("Hello, World"));
+
+                       for (int i = 0; i < 4; ++i) {
+                               buf.Add((byte)0x00);
+                       }
+
+                       buf.AddRange(utf32NativeEndianNoBom.GetBytes("broken"));
+
+                       for (int i = 0; i < 8; ++i) {
+                               buf.Add((byte)0x00);
+                       }
+
+                       buf.Add((byte)0x12);
+                       buf.Add((byte)0x34);
+                       buf.Add((byte)0x56);
+                       buf.Add((byte)0x78);
+
+                       // get the array version of this
+                       var bufArr = buf.ToArray();
+
+                       // allocate a buffer that will contain this string
+                       IntPtr bufPtr = UnixMarshal.AllocHeap(bufArr.Length);
+                       string returned;
+                       try
+                       {
+                               // copy it in
+                               Marshal.Copy(bufArr, 0, bufPtr, bufArr.Length);
+
+                               // try getting it back
+                               returned = UnixMarshal.PtrToString(bufPtr + 8, utf32NativeEndianNoBom);
+                       }
+                       finally
+                       {
+                               UnixMarshal.FreeHeap(bufPtr);
+                       }
+
+                       Assert.AreEqual("Hello, World", returned);
                }
        }
 }