[Mono.Unix] Fix crasher in StringToHeap (#5639)
[mono.git] / mcs / class / Mono.Posix / Mono.Unix / UnixMarshal.cs
index e2ba56f5e56e6513a8b24eebf88aa2ffbe2067aa..7d39fd4c43ffad92bcf2f284a542482b63f0c4eb 100644 (file)
@@ -4,7 +4,7 @@
 // Authors:
 //   Jonathan Pryor (jonpryor@vt.edu)
 //
-// (C) 2004-2005 Jonathan Pryor
+// (C) 2004-2006 Jonathan Pryor
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -94,24 +94,12 @@ namespace Mono.Unix {
        {
                private UnixMarshal () {}
 
-               [Obsolete ("Use GetErrorDescription (Mono.Unix.Native.Errno)", true)]
-               public static string GetErrorDescription (Error errno)
-               {
-                       return ErrorMarshal.Translate ((Native.Errno) (int) errno);
-               }
-
                [CLSCompliant (false)]
                public static string GetErrorDescription (Native.Errno errno)
                {
                        return ErrorMarshal.Translate (errno);
                }
 
-               [Obsolete ("Use AllocHeap(long)", true)]
-               public static IntPtr Alloc (long size)
-               {
-                       return AllocHeap (size);
-               }
-
                public static IntPtr AllocHeap (long size)
                {
                        if (size < 0)
@@ -119,12 +107,6 @@ namespace Mono.Unix {
                        return Native.Stdlib.malloc ((ulong) size);
                }
 
-               [Obsolete ("Use ReAllocHeap(long)", true)]
-               public static IntPtr ReAlloc (IntPtr ptr, long size)
-               {
-                       return ReAllocHeap (ptr, size);
-               }
-
                public static IntPtr ReAllocHeap (IntPtr ptr, long size)
                {
                        if (size < 0)
@@ -132,12 +114,6 @@ namespace Mono.Unix {
                        return Native.Stdlib.realloc (ptr, (ulong) size);
                }
 
-               [Obsolete ("Use FreeHeap(IntPtr)", true)]
-               public static void Free (IntPtr ptr)
-               {
-                       FreeHeap (ptr);
-               }
-
                public static void FreeHeap (IntPtr ptr)
                {
                        Native.Stdlib.free (ptr);
@@ -164,6 +140,9 @@ namespace Mono.Unix {
                        if (p == IntPtr.Zero)
                                return null;
 
+                       if (encoding == null)
+                               throw new ArgumentNullException ("encoding");
+
                        int len = GetStringByteLength (p, encoding);
 
                        // Due to variable-length encoding schemes, GetStringByteLength() may
@@ -197,6 +176,10 @@ namespace Mono.Unix {
                        else if (typeof(UnicodeEncoding).IsAssignableFrom (encodingType)) {
                                len = GetInt16BufferLength (p);
                        }
+                       // Encodings that will always end with a 0x00000000 32-bit word
+                       else if (typeof(UTF32Encoding).IsAssignableFrom (encodingType)) {
+                               len = GetInt32BufferLength (p);
+                       }
                        // Some non-public encoding, such as Latin1 or a DBCS charset.
                        // Look for a sequence of encoding.GetMaxByteCount() bytes that are all
                        // 0, which should be the terminating null.
@@ -305,6 +288,8 @@ namespace Mono.Unix {
                {
                        if (count < 0)
                                throw new ArgumentOutOfRangeException ("count", "< 0");
+                       if (encoding == null)
+                               throw new ArgumentNullException ("encoding");
                        if (stringArray == IntPtr.Zero)
                                return new string[count];
 
@@ -317,12 +302,6 @@ namespace Mono.Unix {
                        return members;
                }
 
-               [Obsolete ("Use StringToHeap(string)", true)]
-               public static IntPtr StringToAlloc (string s)
-               {
-                       return StringToHeap (s, UnixEncoding.Instance);
-               }
-
                public static IntPtr StringToHeap (string s)
                {
                        return StringToHeap (s, UnixEncoding.Instance);
@@ -330,6 +309,9 @@ namespace Mono.Unix {
 
                public static IntPtr StringToHeap (string s, Encoding encoding)
                {
+                       if (s == null)
+                               return IntPtr.Zero;
+
                        return StringToHeap (s, 0, s.Length, encoding);
                }
 
@@ -340,27 +322,48 @@ namespace Mono.Unix {
 
                public static IntPtr StringToHeap (string s, int index, int count, Encoding encoding)
                {
-                       int min_byte_count = encoding.GetMaxByteCount(1);
-                       char[] copy = s.ToCharArray (index, count);
-                       byte[] marshal = new byte [encoding.GetByteCount (copy) + min_byte_count];
+                       if (s == null)
+                               return IntPtr.Zero;
 
-                       int bytes_copied = encoding.GetBytes (copy, 0, copy.Length, marshal, 0);
+                       if (encoding == null)
+                               throw new ArgumentNullException ("encoding");
 
-                       if (bytes_copied != (marshal.Length-min_byte_count))
-                               throw new NotSupportedException ("encoding.GetBytes() doesn't equal encoding.GetByteCount()!");
+                       if (index < 0 || count < 0)
+                               throw new ArgumentOutOfRangeException ((index < 0 ? "index" : "count"),
+                                        "Non - negative number required.");
 
-                       IntPtr mem = AllocHeap (marshal.Length);
-                       if (mem == IntPtr.Zero)
-                               throw new OutOfMemoryException ();
+                       if (s.Length - index < count)
+                               throw new ArgumentOutOfRangeException ("s", "Index and count must refer to a location within the string.");
 
-                       bool copied = false;
-                       try {
-                               Marshal.Copy (marshal, 0, mem, marshal.Length);
-                               copied = true;
-                       }
-                       finally {
-                               if (!copied)
-                                       FreeHeap (mem);
+                       int null_terminator_count = encoding.GetMaxByteCount (1);
+                       int length_without_null = encoding.GetByteCount (s);
+                       int marshalLength = checked (length_without_null + null_terminator_count);
+
+                       IntPtr mem = AllocHeap (marshalLength);
+                       if (mem == IntPtr.Zero)
+                               throw new UnixIOException (Native.Errno.ENOMEM);
+
+                       unsafe {
+                               fixed (char* p = s) {
+                                       byte* marshal = (byte*)mem;
+                                       int bytes_copied;
+
+                                       try {
+                                               bytes_copied = encoding.GetBytes (p + index, count, marshal, marshalLength);
+                                       } catch {
+                                               FreeHeap (mem);
+                                               throw;
+                                       }
+
+                                       if (bytes_copied != length_without_null) {
+                                               FreeHeap (mem);
+                                               throw new NotSupportedException ("encoding.GetBytes() doesn't equal encoding.GetByteCount()!");
+                                       }
+
+                                       marshal += length_without_null;
+                                       for (int i = 0; i < null_terminator_count; ++i)
+                                               marshal[i] = 0;
+                               }
                        }
 
                        return mem;
@@ -373,15 +376,6 @@ namespace Mono.Unix {
                        return false;
                }
 
-               [Obsolete ("Use ShouldRetrySyscall (int, out Mono.Unix.Native.Errno", true)]
-               public static bool ShouldRetrySyscall (int r, out Error errno)
-               {
-                       errno = (Error) 0;
-                       if (r == -1 && (errno = Stdlib.GetLastError ()) == Error.EINTR)
-                               return true;
-                       return false;
-               }
-
                [CLSCompliant (false)]
                public static bool ShouldRetrySyscall (int r, out Native.Errno errno)
                {
@@ -428,47 +422,41 @@ namespace Mono.Unix {
                        return false;
                }
 
-               [Obsolete ("Use CreateExceptionForError (Mono.Unix.Native.Errno)", true)]
-               internal static Exception CreateExceptionForError (Error errno)
-               {
-                       string message = GetErrorDescription (errno);
-                       UnixIOException p = new UnixIOException (errno);
-                       switch (errno) {
-                               case Error.EFAULT:        return new NullReferenceException (message, p);
-                               case Error.EINVAL:        return new ArgumentException (message, p);
-                               case Error.EIO:
-                                 case Error.ENOSPC:
-                                 case Error.EROFS:
-                                 case Error.ESPIPE:
-                                       return new IOException (message, p);
-                               case Error.ENAMETOOLONG:  return new PathTooLongException (message, p);
-                               case Error.ENOENT:        return new FileNotFoundException (message, p);
-                               case Error.ENOEXEC:       return new InvalidProgramException (message, p);
-                               case Error.EOVERFLOW:     return new OverflowException (message, p);
-                               case Error.ERANGE:        return new ArgumentOutOfRangeException (message);
-                               default: /* ignore */     break;
-                       }
-                       return p;
-               }
-
                internal static Exception CreateExceptionForError (Native.Errno errno)
                {
                        string message = GetErrorDescription (errno);
                        UnixIOException p = new UnixIOException (errno);
+
+                       // Ordering: Order alphabetically by exception first (right column),
+                       // then order alphabetically by Errno value (left column) for the given
+                       // exception.
                        switch (errno) {
-                               case Native.Errno.EFAULT:        return new NullReferenceException (message, p);
+                               case Native.Errno.EBADF:
                                case Native.Errno.EINVAL:        return new ArgumentException (message, p);
-                               case Native.Errno.EBADF:         return new ArgumentException (message, p);
-                               case Native.Errno.EIO:
-                                 case Native.Errno.ENOSPC:
-                                 case Native.Errno.EROFS:
-                                 case Native.Errno.ESPIPE:
-                                       return new IOException (message, p);
-                               case Native.Errno.ENAMETOOLONG:  return new PathTooLongException (message, p);
+
+                               case Native.Errno.ERANGE:        return new ArgumentOutOfRangeException (message);
+                               case Native.Errno.ENOTDIR:       return new DirectoryNotFoundException (message, p);
                                case Native.Errno.ENOENT:        return new FileNotFoundException (message, p);
+
+                               case Native.Errno.EOPNOTSUPP:
+                               case Native.Errno.EPERM:         return new InvalidOperationException (message, p);
+
                                case Native.Errno.ENOEXEC:       return new InvalidProgramException (message, p);
+
+                               case Native.Errno.EIO:
+                               case Native.Errno.ENOSPC:
+                               case Native.Errno.ENOTEMPTY:
+                               case Native.Errno.ENXIO:
+                               case Native.Errno.EROFS:
+                               case Native.Errno.ESPIPE:        return new IOException (message, p);
+
+                               case Native.Errno.EFAULT:        return new NullReferenceException (message, p);
                                case Native.Errno.EOVERFLOW:     return new OverflowException (message, p);
-                               case Native.Errno.ERANGE:        return new ArgumentOutOfRangeException (message);
+                               case Native.Errno.ENAMETOOLONG:  return new PathTooLongException (message, p);
+
+                               case Native.Errno.EACCES:
+                               case Native.Errno.EISDIR:        return new UnauthorizedAccessException (message, p);
+
                                default: /* ignore */     break;
                        }
                        return p;
@@ -479,12 +467,6 @@ namespace Mono.Unix {
                        return CreateExceptionForError (Native.Stdlib.GetLastError());
                }
 
-               [Obsolete ("Use ThrowExceptionForError (Mono.Unix.Native.Errno)", true)]
-               public static void ThrowExceptionForError (Error errno)
-               {
-                       throw CreateExceptionForError (errno);
-               }
-
                [CLSCompliant (false)]
                public static void ThrowExceptionForError (Native.Errno errno)
                {
@@ -496,13 +478,6 @@ namespace Mono.Unix {
                        throw CreateExceptionForLastError ();
                }
 
-               [Obsolete ("Use ThrowExceptionForErrorIf (int, Mono.Unix.Native.Errno)", true)]
-               public static void ThrowExceptionForErrorIf (int retval, Error errno)
-               {
-                       if (retval == -1)
-                               ThrowExceptionForError (errno);
-               }
-
                [CLSCompliant (false)]
                public static void ThrowExceptionForErrorIf (int retval, Native.Errno errno)
                {