Skip to content

ILCursor.EmitBr(Instruction) and other such methods produce infinite loops when instruction is ILCursor.Next #237

@Hamunii

Description

@Hamunii

Description

ILCursor.EmitBr and such methods which take Instruction as an argument will emit branch instructions that branch to themselves when the instruction passed as an argument equals ILCursor.Next

This happens because these methods use MarkLabel:

public global::MonoMod.Cil.ILCursor EmitBr(Instruction operand) => 
  _Insert(IL.Create(OpCodes.Br, MarkLabel(operand)));

And this overload of MarkLabel has an undocumented dangerous feature (as seen by the existence of this bug report):

/// <summary>
/// Create a new label targetting a specific instruction.
/// </summary>
/// <param name="inst">The instruction to target</param>
/// <returns>The created label</returns>
public ILLabel MarkLabel(Instruction inst)
{
    var label = Context.DefineLabel();
    if (inst == Next) // <---- !!!!!!!!!!!!!
    {
        // !!! Description of method: 
        // Set the target of a label to the current position (<c>label.Target = Next</c>) and moves after it.
        MarkLabel(label);
        return label;
    }
    label.Target = inst;
    return label;
}

Example

static void MyILHook(ILContext il)
{
    ILCursor c = new(il);
    c.EmitBr(c.Next!);
}

The emitted instruction looks like the following:

 Incoming branches: IL_0000;
IL_0000: br IL_0000

Additional thoughts:
Should this feature in the MarkLabel method even exist? Having the method do completely different things depending on some condition seems like a potential disaster. At least it needs to be documented.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions