|
8 | 8 | using System.Linq; |
9 | 9 | using Terraria; |
10 | 10 | using TerrariaApi.Reporting; |
| 11 | +using System.Reflection.PortableExecutable; |
| 12 | +using System.Runtime.InteropServices; |
11 | 13 |
|
12 | 14 | namespace TerrariaApi.Server |
13 | 15 | { |
@@ -265,6 +267,33 @@ internal static void HandleCommandLine(string[] parms) |
265 | 267 | } |
266 | 268 | } |
267 | 269 |
|
| 270 | + /// <summary> |
| 271 | + /// Tests to see if a plugin is using an incompatible architecture |
| 272 | + /// </summary> |
| 273 | + /// <param name="file">File info of the plugin</param> |
| 274 | + /// <param name="data">File contents</param> |
| 275 | + static void TryCheckArchitecture(FileInfo file, byte[] data) |
| 276 | + { |
| 277 | + using var ms = new MemoryStream(data); |
| 278 | + using var pe = new PEReader(ms); |
| 279 | + if (pe.HasMetadata) |
| 280 | + { |
| 281 | + var currentArch = RuntimeInformation.ProcessArchitecture; |
| 282 | + var laa = (pe.PEHeaders.CoffHeader.Characteristics & Characteristics.LargeAddressAware) != 0; |
| 283 | + Architecture? asmArch = pe.PEHeaders.CoffHeader.Machine switch |
| 284 | + { |
| 285 | + Machine.IA64 => Architecture.X64, |
| 286 | + Machine.Arm64 => Architecture.Arm64, |
| 287 | + Machine.Amd64 => Architecture.X64, |
| 288 | + Machine.I386 => laa ? Architecture.X64 : Architecture.X86, |
| 289 | + Machine.Arm => Architecture.Arm, |
| 290 | + _ => null, |
| 291 | + }; |
| 292 | + if (asmArch is not null && currentArch != asmArch) |
| 293 | + LogWriter.ServerWriteLine($"{file.Name} was built for {asmArch} but expected it to be compatible with {currentArch}.", TraceLevel.Error); |
| 294 | + } |
| 295 | + } |
| 296 | + |
268 | 297 | internal static void LoadPlugins() |
269 | 298 | { |
270 | 299 | string ignoredPluginsFilePath = Path.Combine(ServerPluginsDirectoryPath, "ignoredplugins.txt"); |
@@ -297,16 +326,23 @@ internal static void LoadPlugins() |
297 | 326 | // load it again, but we do still have to verify it and create plugin instances. |
298 | 327 | if (!loadedAssemblies.TryGetValue(fileNameWithoutExtension, out assembly)) |
299 | 328 | { |
| 329 | + byte[] pe = null; |
300 | 330 | try |
301 | 331 | { |
302 | 332 | var pdb = Path.ChangeExtension(fileInfo.FullName, ".pdb"); |
303 | 333 | var symbols = File.Exists(pdb) ? File.ReadAllBytes(pdb) : null; |
304 | | - assembly = Assembly.Load(File.ReadAllBytes(fileInfo.FullName), symbols); |
| 334 | + assembly = Assembly.Load(pe = File.ReadAllBytes(fileInfo.FullName), symbols); |
305 | 335 | } |
306 | 336 | catch (BadImageFormatException) |
307 | 337 | { |
308 | 338 | continue; |
309 | 339 | } |
| 340 | + catch(FileLoadException) |
| 341 | + { |
| 342 | + if (pe is not null) |
| 343 | + TryCheckArchitecture(fileInfo, pe); |
| 344 | + throw; // don't consume the exception, only care about testing arch here |
| 345 | + } |
310 | 346 | loadedAssemblies.Add(fileNameWithoutExtension, assembly); |
311 | 347 | } |
312 | 348 |
|
|
0 commit comments