Skip to content

Commit 537ee5f

Browse files
committed
Implement error handling, move using statements
1 parent 1dd2ee1 commit 537ee5f

File tree

3 files changed

+87
-32
lines changed

3 files changed

+87
-32
lines changed

src/runtime/platform/LibraryLoader.cs

+85-30
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.ComponentModel;
23
using System.Runtime.InteropServices;
34

45
namespace Python.Runtime.Platform
@@ -9,7 +10,7 @@ interface ILibraryLoader
910

1011
IntPtr GetFunction(IntPtr hModule, string procedureName);
1112

12-
bool Free(IntPtr hModule);
13+
void Free(IntPtr hModule);
1314
}
1415

1516
static class LibraryLoader
@@ -25,7 +26,7 @@ public static ILibraryLoader Get(OperatingSystemType os)
2526
case OperatingSystemType.Linux:
2627
return new LinuxLoader();
2728
default:
28-
throw new Exception($"This operating system ({os}) is not supported");
29+
throw new PlatformNotSupportedException($"This operating system ({os}) is not supported");
2930
}
3031
}
3132
}
@@ -37,15 +38,23 @@ class LinuxLoader : ILibraryLoader
3738
private static IntPtr RTLD_DEFAULT = IntPtr.Zero;
3839
private const string NativeDll = "libdl.so";
3940

40-
public IntPtr Load(string fileName)
41+
public IntPtr Load(string dllToLoad)
4142
{
42-
return dlopen($"lib{fileName}.so", RTLD_NOW | RTLD_GLOBAL);
43+
var filename = $"lib{dllToLoad}.so";
44+
ClearError();
45+
var res = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
46+
if (res == IntPtr.Zero)
47+
{
48+
var err = GetError();
49+
throw new DllNotFoundException($"Could not load {filename} with flags RTLD_NOW | RTLD_GLOBAL: {err}");
50+
}
51+
52+
return res;
4353
}
4454

45-
public bool Free(IntPtr handle)
55+
public void Free(IntPtr handle)
4656
{
4757
dlclose(handle);
48-
return true;
4958
}
5059

5160
public IntPtr GetFunction(IntPtr dllHandle, string name)
@@ -56,22 +65,35 @@ public IntPtr GetFunction(IntPtr dllHandle, string name)
5665
dllHandle = RTLD_DEFAULT;
5766
}
5867

59-
// clear previous errors if any
60-
dlerror();
68+
ClearError();
6169
IntPtr res = dlsym(dllHandle, name);
62-
IntPtr errPtr = dlerror();
63-
if (errPtr != IntPtr.Zero)
70+
if (res == IntPtr.Zero)
6471
{
65-
throw new Exception("dlsym: " + Marshal.PtrToStringAnsi(errPtr));
72+
var err = GetError();
73+
throw new MissingMethodException($"Failed to load symbol {name}: {err}");
6674
}
6775
return res;
6876
}
6977

78+
void ClearError()
79+
{
80+
dlerror();
81+
}
82+
83+
string GetError()
84+
{
85+
var res = dlerror();
86+
if (res != IntPtr.Zero)
87+
return Marshal.PtrToStringAnsi(res);
88+
else
89+
return null;
90+
}
91+
7092
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
71-
public static extern IntPtr dlopen(String fileName, int flags);
93+
public static extern IntPtr dlopen(string fileName, int flags);
7294

7395
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
74-
private static extern IntPtr dlsym(IntPtr handle, String symbol);
96+
private static extern IntPtr dlsym(IntPtr handle, string symbol);
7597

7698
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl)]
7799
private static extern int dlclose(IntPtr handle);
@@ -87,15 +109,23 @@ class DarwinLoader : ILibraryLoader
87109
private const string NativeDll = "/usr/lib/libSystem.dylib";
88110
private static IntPtr RTLD_DEFAULT = new IntPtr(-2);
89111

90-
public IntPtr Load(string fileName)
112+
public IntPtr Load(string dllToLoad)
91113
{
92-
return dlopen($"lib{fileName}.dylib", RTLD_NOW | RTLD_GLOBAL);
114+
var filename = $"lib{dllToLoad}.dylib";
115+
ClearError();
116+
var res = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
117+
if (res == IntPtr.Zero)
118+
{
119+
var err = GetError();
120+
throw new DllNotFoundException($"Could not load {filename} with flags RTLD_NOW | RTLD_GLOBAL: {err}");
121+
}
122+
123+
return res;
93124
}
94125

95-
public bool Free(IntPtr handle)
126+
public void Free(IntPtr handle)
96127
{
97128
dlclose(handle);
98-
return true;
99129
}
100130

101131
public IntPtr GetFunction(IntPtr dllHandle, string name)
@@ -106,17 +136,30 @@ public IntPtr GetFunction(IntPtr dllHandle, string name)
106136
dllHandle = RTLD_DEFAULT;
107137
}
108138

109-
// clear previous errors if any
110-
dlerror();
139+
ClearError();
111140
IntPtr res = dlsym(dllHandle, name);
112-
IntPtr errPtr = dlerror();
113-
if (errPtr != IntPtr.Zero)
141+
if (res == IntPtr.Zero)
114142
{
115-
throw new Exception("dlsym: " + Marshal.PtrToStringAnsi(errPtr));
143+
var err = GetError();
144+
throw new MissingMethodException($"Failed to load symbol {name}: {err}");
116145
}
117146
return res;
118147
}
119148

149+
void ClearError()
150+
{
151+
dlerror();
152+
}
153+
154+
string GetError()
155+
{
156+
var res = dlerror();
157+
if (res != IntPtr.Zero)
158+
return Marshal.PtrToStringAnsi(res);
159+
else
160+
return null;
161+
}
162+
120163
[DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
121164
public static extern IntPtr dlopen(String fileName, int flags);
122165

@@ -134,20 +177,32 @@ class WindowsLoader : ILibraryLoader
134177
{
135178
private const string NativeDll = "kernel32.dll";
136179

137-
[DllImport(NativeDll)]
138-
static extern IntPtr LoadLibrary(string dllToLoad);
139180

140-
public IntPtr Load(string dllToLoad) => WindowsLoader.LoadLibrary(dllToLoad);
181+
public IntPtr Load(string dllToLoad)
182+
{
183+
var res = WindowsLoader.LoadLibrary(dllToLoad);
184+
if (res == IntPtr.Zero)
185+
throw new DllNotFoundException($"Could not load {dllToLoad}", new Win32Exception());
186+
return res;
187+
}
188+
189+
public IntPtr GetFunction(IntPtr hModule, string procedureName)
190+
{
191+
var res = WindowsLoader.GetProcAddress(hModule, procedureName);
192+
if (res == IntPtr.Zero)
193+
throw new MissingMethodException($"Failed to load symbol {procedureName}", new Win32Exception());
194+
return res;
195+
}
141196

142-
[DllImport(NativeDll)]
143-
static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
197+
public void Free(IntPtr hModule) => WindowsLoader.FreeLibrary(hModule);
144198

145-
public IntPtr GetFunction(IntPtr hModule, string procedureName) => WindowsLoader.GetProcAddress(hModule, procedureName);
199+
[DllImport(NativeDll, SetLastError = true)]
200+
static extern IntPtr LoadLibrary(string dllToLoad);
146201

202+
[DllImport(NativeDll, SetLastError = true)]
203+
static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
147204

148205
[DllImport(NativeDll)]
149206
static extern bool FreeLibrary(IntPtr hModule);
150-
151-
public bool Free(IntPtr hModule) => WindowsLoader.FreeLibrary(hModule);
152207
}
153208
}

src/runtime/runtime.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
using System.Text;
55
using System.Threading;
66
using System.Collections.Generic;
7+
using Python.Runtime.Platform;
78

89
namespace Python.Runtime
910
{
10-
using Python.Runtime.Platform;
1111

1212
/// <summary>
1313
/// Encapsulates the low-level Python C API. Note that it is

src/runtime/typemanager.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
using System.Collections.Generic;
44
using System.Reflection;
55
using System.Runtime.InteropServices;
6+
using Python.Runtime.Platform;
67

78
namespace Python.Runtime
89
{
9-
using Python.Runtime.Platform;
1010

1111
/// <summary>
1212
/// The TypeManager class is responsible for building binary-compatible

0 commit comments

Comments
 (0)