Browse Source

Add InvalidInstruction to represent invalid IL opcodes in the ILAst instead of crashing.

pull/728/head
Daniel Grunwald 9 years ago
parent
commit
a40f0754c1
  1. 14
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 8
      ICSharpCode.Decompiler/FlowAnalysis/DataFlowVisitor.cs
  3. 18
      ICSharpCode.Decompiler/IL/ILReader.cs
  4. 45
      ICSharpCode.Decompiler/IL/Instructions.cs
  5. 2
      ICSharpCode.Decompiler/IL/Instructions.tt
  6. 6
      ICSharpCode.Decompiler/IL/Instructions/Branch.cs
  7. 6
      ICSharpCode.Decompiler/IL/Instructions/Leave.cs
  8. 20
      ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs

14
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -953,11 +953,23 @@ namespace ICSharpCode.Decompiler.CSharp @@ -953,11 +953,23 @@ namespace ICSharpCode.Decompiler.CSharp
return true;
}
protected internal override TranslatedExpression VisitInvalidInstruction(InvalidInstruction inst)
{
string message = "Invalid IL";
if (inst.ILRange.Start != 0) {
message += $" near IL_{inst.ILRange.Start:x4}";
}
if (!string.IsNullOrEmpty(inst.Message)) {
message += ": " + inst.Message;
}
return ErrorExpression(message);
}
protected override TranslatedExpression Default(ILInstruction inst)
{
return ErrorExpression("OpCode not supported: " + inst.OpCode);
}
static TranslatedExpression ErrorExpression(string message)
{
var e = new ErrorExpression();

8
ICSharpCode.Decompiler/FlowAnalysis/DataFlowVisitor.cs

@ -278,7 +278,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis @@ -278,7 +278,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
DebugStartPoint(inst);
// This method assumes normal control flow and no branches.
if ((inst.DirectFlags & (InstructionFlags.ControlFlow | InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable)) != 0) {
throw new NotImplementedException("RDVisitor is missing implementation for " + inst.GetType().Name);
throw new NotImplementedException(GetType().Name + " is missing implementation for " + inst.GetType().Name);
}
// Since this instruction has normal control flow, we can evaluate our children left-to-right.
@ -438,7 +438,11 @@ namespace ICSharpCode.Decompiler.FlowAnalysis @@ -438,7 +438,11 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
protected internal override void VisitRethrow(Rethrow inst)
{
PropagateStateOnException();
MarkUnreachable();
}
protected internal override void VisitInvalidInstruction(InvalidInstruction inst)
{
MarkUnreachable();
}

18
ICSharpCode.Decompiler/IL/ILReader.cs

@ -242,7 +242,7 @@ namespace ICSharpCode.Decompiler.IL @@ -242,7 +242,7 @@ namespace ICSharpCode.Decompiler.IL
decodedInstruction.ILRange = new Interval(start, reader.Position);
UnpackPush(decodedInstruction).ILRange = decodedInstruction.ILRange;
instructionBuilder.Add(decodedInstruction);
if (decodedInstruction.HasFlag(InstructionFlags.EndPointUnreachable)) {
if ((decodedInstruction.DirectFlags & InstructionFlags.EndPointUnreachable) != 0) {
if (!stackByOffset.TryGetValue(reader.Position, out currentStack)) {
currentStack = ImmutableStack<ILVariable>.Empty;
}
@ -763,7 +763,7 @@ namespace ICSharpCode.Decompiler.IL @@ -763,7 +763,7 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Unbox_Any:
return Push(new UnboxAny(Pop(), ReadAndDecodeTypeReference()));
default:
throw new NotImplementedException(ilOpCode.ToString());
return new InvalidInstruction("Unknown opcode: " + ilOpCode.ToString());
}
}
@ -832,17 +832,19 @@ namespace ICSharpCode.Decompiler.IL @@ -832,17 +832,19 @@ namespace ICSharpCode.Decompiler.IL
return new StLoc(v, inst);
}
LdLoc Peek()
ILInstruction Peek()
{
Debug.Assert(!currentStack.IsEmpty);
// TODO: handle stack underflow?
if (currentStack.IsEmpty) {
return new InvalidInstruction("Stack underflow") { ILRange = new Interval(reader.Position, reader.Position) };
}
return new LdLoc(currentStack.Peek());
}
LdLoc Pop()
ILInstruction Pop()
{
Debug.Assert(!currentStack.IsEmpty);
// TODO: handle stack underflow?
if (currentStack.IsEmpty) {
return new InvalidInstruction("Stack underflow") { ILRange = new Interval(reader.Position, reader.Position) };
}
ILVariable v;
currentStack = currentStack.Pop(out v);
return new LdLoc(v);

45
ICSharpCode.Decompiler/IL/Instructions.cs

@ -29,6 +29,8 @@ namespace ICSharpCode.Decompiler.IL @@ -29,6 +29,8 @@ namespace ICSharpCode.Decompiler.IL
/// </summary>
public enum OpCode
{
/// <summary>Represents invalid IL. Semantically, this instruction is considered to throw some kind of exception.</summary>
InvalidInstruction,
/// <summary>No operation. Takes 0 arguments and returns void.</summary>
Nop,
/// <summary>A container of IL blocks.</summary>
@ -440,6 +442,32 @@ namespace ICSharpCode.Decompiler.IL @@ -440,6 +442,32 @@ namespace ICSharpCode.Decompiler.IL
}
}
/// <summary>Represents invalid IL. Semantically, this instruction is considered to throw some kind of exception.</summary>
public sealed partial class InvalidInstruction : SimpleInstruction
{
public InvalidInstruction() : base(OpCode.InvalidInstruction)
{
}
public override StackType ResultType { get { return StackType.Void; } }
protected override InstructionFlags ComputeFlags()
{
return InstructionFlags.MayThrow | InstructionFlags.EndPointUnreachable;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.MayThrow | InstructionFlags.EndPointUnreachable;
}
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitInvalidInstruction(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitInvalidInstruction(this);
}
}
/// <summary>No operation. Takes 0 arguments and returns void.</summary>
public sealed partial class Nop : SimpleInstruction
{
@ -3068,6 +3096,10 @@ namespace ICSharpCode.Decompiler.IL @@ -3068,6 +3096,10 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Called by Visit*() methods that were not overridden</summary>
protected abstract void Default(ILInstruction inst);
protected internal virtual void VisitInvalidInstruction(InvalidInstruction inst)
{
Default(inst);
}
protected internal virtual void VisitNop(Nop inst)
{
Default(inst);
@ -3366,6 +3398,10 @@ namespace ICSharpCode.Decompiler.IL @@ -3366,6 +3398,10 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Called by Visit*() methods that were not overridden</summary>
protected abstract T Default(ILInstruction inst);
protected internal virtual T VisitInvalidInstruction(InvalidInstruction inst)
{
return Default(inst);
}
protected internal virtual T VisitNop(Nop inst)
{
return Default(inst);
@ -3701,6 +3737,7 @@ namespace ICSharpCode.Decompiler.IL @@ -3701,6 +3737,7 @@ namespace ICSharpCode.Decompiler.IL
partial class InstructionOutputExtensions
{
static readonly string[] originalOpCodeNames = {
"invalid",
"nop",
"ILFunction",
"BlockContainer",
@ -3778,6 +3815,14 @@ namespace ICSharpCode.Decompiler.IL @@ -3778,6 +3815,14 @@ namespace ICSharpCode.Decompiler.IL
partial class ILInstruction
{
public bool MatchInvalidInstruction()
{
var inst = this as InvalidInstruction;
if (inst != null) {
return true;
}
return false;
}
public bool MatchNop()
{
var inst = this as Nop;

2
ICSharpCode.Decompiler/IL/Instructions.tt

@ -36,6 +36,8 @@ @@ -36,6 +36,8 @@
};
OpCode[] opCodes = {
new OpCode("invalid", "Represents invalid IL. Semantically, this instruction is considered to throw some kind of exception.",
CustomClassName("InvalidInstruction"), NoArguments, MayThrow, UnconditionalBranch),
new OpCode("nop", "No operation. Takes 0 arguments and returns void.",
VoidResult, NoArguments),
new OpCode("ILFunction", "A container of IL blocks.",

6
ICSharpCode.Decompiler/IL/Instructions/Branch.cs

@ -55,6 +55,12 @@ namespace ICSharpCode.Decompiler.IL @@ -55,6 +55,12 @@ namespace ICSharpCode.Decompiler.IL
return InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable;
}
}
public int TargetILOffset {
get { return targetBlock != null ? targetBlock.ILRange.Start : targetILOffset; }
}

6
ICSharpCode.Decompiler/IL/Instructions/Leave.cs

@ -52,6 +52,12 @@ namespace ICSharpCode.Decompiler.IL @@ -52,6 +52,12 @@ namespace ICSharpCode.Decompiler.IL
return InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable;
}
}
public BlockContainer TargetContainer {
get { return targetContainer; }
set {

20
ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs

@ -36,4 +36,24 @@ namespace ICSharpCode.Decompiler.IL @@ -36,4 +36,24 @@ namespace ICSharpCode.Decompiler.IL
// the non-custom WriteTo would add useless parentheses
}
}
partial class InvalidInstruction : SimpleInstruction
{
public string Message;
public InvalidInstruction(string message) : this()
{
this.Message = message;
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
if (!string.IsNullOrEmpty(Message)) {
output.Write('(');
output.Write(Message);
output.Write(')');
}
}
}
}

Loading…
Cancel
Save