• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SamboyCoding / Cpp2IL / 30769998286

02 Aug 2026 10:23PM UTC coverage: 34.169% (-1.8%) from 35.984%
30769998286

push

github

SamboyCoding
Decompiler: Support szarray, virtual calls, address of local, plus clean up ILSpy output by adjusting the IL

2899 of 9930 branches covered (29.19%)

Branch coverage included in aggregate %.

27 of 614 new or added lines in 19 files covered. (4.4%)

9 existing lines in 4 files now uncovered.

5316 of 14112 relevant lines covered (37.67%)

156656.13 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/Cpp2IL.Core/Analysis/InjectedCheckRemover.cs
1
using System.Collections.Generic;
2
using System.Linq;
3
using Cpp2IL.Core.Graphs;
4
using Cpp2IL.Core.ISIL;
5
using Cpp2IL.Core.Model.Contexts;
6

7
namespace Cpp2IL.Core.Analysis;
8

9
// Remove null and bounds checks which are explicit in il2cpp but implicit in IL
10
public static class InjectedCheckRemover
11
{
12
    public static void Run(MethodAnalysisContext method) => Run(method.ControlFlowGraph!);
×
13

14
    public static void Run(ISILControlFlowGraph cfg)
15
    {
16
        var defOf = BuildDefMap(cfg);
×
17
        var removedAny = false;
×
18

19
        foreach (var block in cfg.Blocks)
×
20
        {
21
            if (block.BlockType != BlockType.TwoWay || block.Instructions.Count == 0)
×
22
                continue;
23

24
            var terminator = block.Instructions[^1];
×
25

26
            if (terminator.OpCode != OpCode.ConditionalJump)
×
27
                continue;
28

NEW
29
            if (terminator.Operands[0] is not Block target || GetInjectedThrowType(target) is not { } thrownType)
×
30
                continue;
31

32
            if (terminator.Operands[1] is not LocalVariable condition
×
33
                || !defOf.TryGetValue(condition, out var definition)
×
NEW
34
                || !IsInjectedCheck(definition, thrownType))
×
35
                continue;
36

37
            terminator.OpCode = OpCode.Nop;
×
38
            terminator.SetOperands();
×
39

40
            block.Successors.Remove(target);
×
41
            target.Predecessors.Remove(block);
×
42
            block.CalculateBlockType();
×
43
            removedAny = true;
×
44
        }
45

46
        if (!removedAny)
×
47
            return;
×
48

49
        // delete any throw blocks
NEW
50
        cfg.RemoveUnreachableBlocks();
×
51
        DeadCodeEliminator.Run(cfg);
×
52
    }
×
53

54
    private static bool IsInjectedCheck(Instruction definition, string thrownType) =>
NEW
55
        thrownType switch
×
NEW
56
        {
×
NEW
57
            "System.NullReferenceException" => definition is { OpCode: OpCode.CheckEqual } && definition.Operands[2] is Immediate { Value: 0 },
×
NEW
58
            "System.IndexOutOfRangeException" => definition.OpCode is >= OpCode.CheckEqual and <= OpCode.CheckLessOrEqual,
×
NEW
59
            _ => false
×
NEW
60
        };
×
61

62
    // The full name of the exception if this block does nothing but throw an injected check's exception, else null.
63
    private static string? GetInjectedThrowType(Block block)
64
    {
NEW
65
        string? thrown = null;
×
66

67
        foreach (var instruction in block.Instructions)
×
68
        {
69
            switch (instruction.OpCode)
×
70
            {
71
                case OpCode.Nop or OpCode.Interrupt:
NEW
72
                case OpCode.Return when thrown != null:
×
73
                    continue;
74

NEW
75
                case OpCode.Throw when thrown == null
×
NEW
76
                    && instruction.Operands is [TypeAnalysisContext { FullName: "System.NullReferenceException" or "System.IndexOutOfRangeException" } exception]:
×
NEW
77
                    thrown = exception.FullName;
×
78
                    continue;
×
79

80
                default:
NEW
81
                    return null;
×
82
            }
83
        }
84

NEW
85
        return thrown;
×
86
    }
×
87

88
    private static Dictionary<LocalVariable, Instruction> BuildDefMap(ISILControlFlowGraph cfg)
89
    {
90
        var defs = new Dictionary<LocalVariable, Instruction>();
×
91

92
        foreach (var instruction in cfg.Instructions)
×
93
            if (instruction.Destination is LocalVariable local)
×
94
                defs[local] = instruction;
×
95

96
        return defs;
×
97
    }
98
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc