Skip to content
Browse files

[Audio] Don't crash when Alc.GetString() returns null

Alc.GetString() could crash if the unmanaged code returned null due to
any kind of failure. This is now fixed and better documented.

Additionally, the array overload for Alc.GetString() will now correctly
forward the ‘device’ parameter to unmanaged code.
  • Loading branch information...
1 parent 19eb72b commit 7afe48c9798aa3e5eb5124ba0a978fdd81985d79 @thefiddler thefiddler committed Jan 12, 2014
Showing with 51 additions and 16 deletions.
  1. +51 −16 Source/OpenTK/Audio/OpenAL/Alc/Alc.cs
View
67 Source/OpenTK/Audio/OpenAL/Alc/Alc.cs
@@ -9,6 +9,7 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security;
@@ -262,7 +263,13 @@ public static IntPtr GetContextsDevice(ContextHandle context)
/// <returns>A string containing the name of the Device.</returns>
public static string GetString(IntPtr device, AlcGetString param)
{
- return Marshal.PtrToStringAnsi(GetStringPrivate(device, param));
+ IntPtr pstr = GetStringPrivate(device, param);
+ string str = String.Empty;
+ if (pstr != IntPtr.Zero)
+ {
+ str = Marshal.PtrToStringAnsi(pstr);
+ }
+ return str;
}
/// <summary>This function returns a List of strings related to the context.</summary>
@@ -277,26 +284,54 @@ public static string GetString(IntPtr device, AlcGetString param)
public static IList<string> GetString(IntPtr device, AlcGetStringList param)
{
List<string> result = new List<string>();
- IntPtr t = GetStringPrivate(IntPtr.Zero, (AlcGetString)param);
- System.Text.StringBuilder sb = new System.Text.StringBuilder();
- byte b;
- int offset = 0;
- do
+
+ // We cannot use Marshal.PtrToStringAnsi(),
+ // because alcGetString is defined to return either a nul-terminated string,
+ // or an array of nul-terminated strings terminated by an extra nul.
+ // Marshal.PtrToStringAnsi() will fail in the latter case (it will only
+ // return the very first string in the array.)
+ // We'll have to marshal this ourselves.
+ IntPtr t = GetStringPrivate(device, (AlcGetString)param);
+ if (t != IntPtr.Zero)
{
- b = Marshal.ReadByte(t, offset++);
- if (b != 0)
- sb.Append((char)b);
- if (b == 0)
+ System.Text.StringBuilder sb = new System.Text.StringBuilder();
+ byte b;
+ int offset = 0;
+ do
{
- result.Add(sb.ToString());
- if (Marshal.ReadByte(t, offset) == 0) // offset already properly increased through ++
- break; // 2x null
+ b = Marshal.ReadByte(t, offset++);
+ if (b != 0)
+ {
+ sb.Append((char)b);
+ }
else
- sb.Remove(0, sb.Length); // 1x null
+ {
+ // One string from the array is complete
+ result.Add(sb.ToString());
+
+ // Check whether the array has finished
+ // Note: offset already been increased through offset++ above
+ if (Marshal.ReadByte(t, offset) == 0)
+ {
+ // 2x consecutive nuls, we've read the whole array
+ break;
+ }
+ else
+ {
+ // Another string is starting, clear the StringBuilder
+ sb.Remove(0, sb.Length);
+ }
+ }
}
- } while (true);
+ while (true);
+ }
+ else
+ {
+ Debug.Print("[Audio] Alc.GetString({0}, {1}) returned null.",
+ device, param);
+ }
- return (IList<string>)result;
+ return result;
}
[DllImport(Alc.Lib, EntryPoint = "alcGetIntegerv", ExactSpelling = true, CallingConvention = Alc.Style, CharSet = CharSet.Ansi), SuppressUnmanagedCodeSecurity()]

0 comments on commit 7afe48c

Please sign in to comment.
Something went wrong with that request. Please try again.