Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/linker.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSven Boemer <sbomer@gmail.com>2022-08-12 20:09:01 +0300
committerGitHub <noreply@github.com>2022-08-12 20:09:01 +0300
commitd559347987ba45c0dc3389cb96dce1ae20204513 (patch)
tree9fd6b098611a5ac0ef3a2e5a74fdfda8b7948211 /src
parent95ea1842abc8634d1e98d995577c4202ad3fc5c5 (diff)
Fix il corruption (#2966)
This prevents invalid IL in situations where removing the last instruction of a method would result in the last instruction being a conditional branch. There needs to be some IL in the not-taken branch for the IL to be valid, so this fixes the issue by injecting "ldnull; throw" at the end. Co-authored-by: vitek-karas <10670590+vitek-karas@users.noreply.github.com> Co-authored-by: Adam Sitnik <adam.sitnik@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs21
1 files changed, 19 insertions, 2 deletions
diff --git a/src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs b/src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs
index 8e8fda213..d91fb09dd 100644
--- a/src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs
+++ b/src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs
@@ -806,6 +806,9 @@ namespace Mono.Linker.Steps
return changed;
}
+ static bool IsConditionalBranch (OpCode opCode)
+ => opCode.Code is Code.Brfalse or Code.Brfalse_S or Code.Brtrue or Code.Brtrue_S;
+
void RemoveUnreachableInstructions (BitArray reachable)
{
LinkerILProcessor processor = Body.GetLinkerILProcessor ();
@@ -815,8 +818,22 @@ namespace Mono.Linker.Steps
if (reachable[i])
continue;
- processor.RemoveAt (i - removed);
- ++removed;
+ int index = i - removed;
+ // If we intend to remove the last instruction we replaced it with "ret" above (not "nop")
+ // but we can't get rid of it completely because it may happen that the last kept instruction
+ // is a conditional branch - in which case to keep the IL valid, there has to be something after
+ // the conditional branch instruction (the else branch). So if that's the case
+ // inject "ldnull; throw;" at the end - this branch should never be reachable and it's always valid
+ // (ret may need to return a value of the right type if the method has a return value which is complicated
+ // to construct out of nothing).
+ if (index == Body.Instructions.Count - 1 && Body.Instructions[index].OpCode == OpCodes.Ret &&
+ index > 0 && IsConditionalBranch (Body.Instructions[index - 1].OpCode)) {
+ processor.Replace (index, Instruction.Create (OpCodes.Ldnull));
+ processor.InsertAfter (Body.Instructions[index], Instruction.Create (OpCodes.Throw));
+ } else {
+ processor.RemoveAt (index);
+ ++removed;
+ }
}
}