summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <github@jplamondonw.com>2017-03-12 01:31:15 -0500
committerJesse Plamondon-Willard <github@jplamondonw.com>2017-03-12 01:31:15 -0500
commit6d2d90b7681e4e274e92742e98905ec4000486ca (patch)
tree80241918427c710303156d18f369f9b3b92717e6
parentb0fab4a0764d4cd1eb807db88e704aa401e4f716 (diff)
downloadSMAPI-6d2d90b7681e4e274e92742e98905ec4000486ca.tar.gz
SMAPI-6d2d90b7681e4e274e92742e98905ec4000486ca.tar.bz2
SMAPI-6d2d90b7681e4e274e92742e98905ec4000486ca.zip
add logic to detect incompatible mod instructions & reject mod load (#247)
-rw-r--r--src/StardewModdingAPI/Constants.cs8
-rw-r--r--src/StardewModdingAPI/Framework/AssemblyLoader.cs18
-rw-r--r--src/StardewModdingAPI/Framework/IncompatibleInstructionException.cs27
-rw-r--r--src/StardewModdingAPI/Program.cs5
-rw-r--r--src/StardewModdingAPI/StardewModdingAPI.csproj1
5 files changed, 59 insertions, 0 deletions
diff --git a/src/StardewModdingAPI/Constants.cs b/src/StardewModdingAPI/Constants.cs
index 66bf5842..d8149766 100644
--- a/src/StardewModdingAPI/Constants.cs
+++ b/src/StardewModdingAPI/Constants.cs
@@ -135,6 +135,14 @@ namespace StardewModdingAPI
return new PlatformAssemblyMap(targetPlatform, removeAssemblyReferences, targetAssemblies);
}
+ /// <summary>Get finders which match incompatible CIL instructions in mod assemblies.</summary>
+ internal static IEnumerable<IInstructionFinder> GetIncompatibilityFinders()
+ {
+ return new IInstructionFinder[]
+ {
+ };
+ }
+
/// <summary>Get rewriters which fix incompatible CIL instructions in mod assemblies.</summary>
internal static IEnumerable<IInstructionRewriter> GetRewriters()
{
diff --git a/src/StardewModdingAPI/Framework/AssemblyLoader.cs b/src/StardewModdingAPI/Framework/AssemblyLoader.cs
index 8af67772..dfe0d03f 100644
--- a/src/StardewModdingAPI/Framework/AssemblyLoader.cs
+++ b/src/StardewModdingAPI/Framework/AssemblyLoader.cs
@@ -55,6 +55,7 @@ namespace StardewModdingAPI.Framework
/// <summary>Preprocess and load an assembly.</summary>
/// <param name="assemblyPath">The assembly file path.</param>
/// <returns>Returns the rewrite metadata for the preprocessed assembly.</returns>
+ /// <exception cref="IncompatibleInstructionException">An incompatible CIL instruction was found while rewriting the assembly.</exception>
public Assembly Load(string assemblyPath)
{
// get referenced local assemblies
@@ -159,6 +160,7 @@ namespace StardewModdingAPI.Framework
/// <summary>Rewrite the types referenced by an assembly.</summary>
/// <param name="assembly">The assembly to rewrite.</param>
/// <returns>Returns whether the assembly was modified.</returns>
+ /// <exception cref="IncompatibleInstructionException">An incompatible CIL instruction was found while rewriting the assembly.</exception>
private bool RewriteAssembly(AssemblyDefinition assembly)
{
ModuleDefinition module = assembly.MainModule;
@@ -189,6 +191,22 @@ namespace StardewModdingAPI.Framework
this.ChangeTypeScope(type);
}
+ // throw exception if assembly contains incompatible instructions can't be rewritten
+ {
+ IInstructionFinder[] finders = Constants.GetIncompatibilityFinders().ToArray();
+ foreach (MethodDefinition method in this.GetMethods(module))
+ {
+ foreach (Instruction instruction in method.Body.Instructions)
+ {
+ foreach (IInstructionFinder finder in finders)
+ {
+ if (finder.IsMatch(instruction, platformChanged))
+ throw new IncompatibleInstructionException(finder.NounPhrase, $"Found an incompatible CIL instruction ({finder.NounPhrase}) while loading assembly {assembly.Name.Name}.");
+ }
+ }
+ }
+ }
+
// rewrite incompatible instructions
bool anyRewritten = false;
IInstructionRewriter[] rewriters = Constants.GetRewriters().ToArray();
diff --git a/src/StardewModdingAPI/Framework/IncompatibleInstructionException.cs b/src/StardewModdingAPI/Framework/IncompatibleInstructionException.cs
new file mode 100644
index 00000000..affe2cb3
--- /dev/null
+++ b/src/StardewModdingAPI/Framework/IncompatibleInstructionException.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace StardewModdingAPI.Framework
+{
+ /// <summary>An exception raised when an incompatible instruction is found while loading a mod assembly.</summary>
+ internal class IncompatibleInstructionException : Exception
+ {
+ /*********
+ ** Accessors
+ *********/
+ /// <summary>A brief noun phrase which describes the incompatible instruction that was found.</summary>
+ public string NounPhrase { get; }
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// <summary>Construct an instance.</summary>
+ /// <param name="nounPhrase">A brief noun phrase which describes the incompatible instruction that was found.</param>
+ /// <param name="message">A message which describes the error.</param>
+ public IncompatibleInstructionException(string nounPhrase, string message)
+ : base(message)
+ {
+ this.NounPhrase = nounPhrase;
+ }
+ }
+}
diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs
index bf3c86fb..cb8cc2e5 100644
--- a/src/StardewModdingAPI/Program.cs
+++ b/src/StardewModdingAPI/Program.cs
@@ -453,6 +453,11 @@ namespace StardewModdingAPI
{
modAssembly = modAssemblyLoader.Load(assemblyPath);
}
+ catch (IncompatibleInstructionException ex)
+ {
+ this.Monitor.Log($"{skippedPrefix} because it's not compatible with the latest version of the game (detected {ex.NounPhrase}). Please check for a newer version of the mod (you have v{manifest.Version}).", LogLevel.Error);
+ continue;
+ }
catch (Exception ex)
{
this.Monitor.Log($"{skippedPrefix} because its DLL '{manifest.EntryDll}' couldn't be loaded.\n{ex.GetLogSummary()}", LogLevel.Error);
diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj
index ab808948..92726ca0 100644
--- a/src/StardewModdingAPI/StardewModdingAPI.csproj
+++ b/src/StardewModdingAPI/StardewModdingAPI.csproj
@@ -154,6 +154,7 @@
<Compile Include="Framework\Content\ContentEventHelper.cs" />
<Compile Include="Framework\Content\ContentEventHelperForDictionary.cs" />
<Compile Include="Framework\Content\ContentEventHelperForImage.cs" />
+ <Compile Include="Framework\IncompatibleInstructionException.cs" />
<Compile Include="Framework\Logging\ConsoleInterceptionManager.cs" />
<Compile Include="Framework\Logging\InterceptingTextWriter.cs" />
<Compile Include="Framework\CommandHelper.cs" />