Skip to content

Commit f6c4432

Browse files
authored
Merge pull request #85 from BepInEx/codematcher-pos-checks
Add some sanity checks to make exception messages more useful.
2 parents cd83a20 + 2d88dc8 commit f6c4432

File tree

1 file changed

+44
-18
lines changed

1 file changed

+44
-18
lines changed

Harmony/Tools/CodeMatcher/CodeMatcher.cs

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ private void SetOutOfBounds(int direction)
3434
Pos = direction > 0 ? Length : -1;
3535
}
3636

37+
private int PosOrThrow()
38+
{
39+
if (IsInvalid) throw new InvalidOperationException("Current position is out of bounds");
40+
return Pos;
41+
}
42+
3743
/// <summary>Gets the number of code instructions in this matcher</summary>
3844
/// <value>The count</value>
3945
///
@@ -52,27 +58,27 @@ private void SetOutOfBounds(int direction)
5258
/// <summary>Gets the remaining code instructions</summary>
5359
/// <value>The remaining count</value>
5460
///
55-
public int Remaining => Length - Math.Max(0, Pos);
61+
public int Remaining => Length - PosOrThrow();
5662

5763
/// <summary>Gets the opcode at the current position</summary>
5864
/// <value>The opcode</value>
5965
///
60-
public ref OpCode Opcode => ref codes[Pos].opcode;
66+
public ref OpCode Opcode => ref codes[PosOrThrow()].opcode;
6167

6268
/// <summary>Gets the operand at the current position</summary>
6369
/// <value>The operand</value>
6470
///
65-
public ref object Operand => ref codes[Pos].operand;
71+
public ref object Operand => ref codes[PosOrThrow()].operand;
6672

6773
/// <summary>Gets the labels at the current position</summary>
6874
/// <value>The labels</value>
6975
///
70-
public ref List<Label> Labels => ref codes[Pos].labels;
76+
public ref List<Label> Labels => ref codes[PosOrThrow()].labels;
7177

7278
/// <summary>Gets the exception blocks at the current position</summary>
7379
/// <value>The blocks</value>
7480
///
75-
public ref List<ExceptionBlock> Blocks => ref codes[Pos].blocks;
81+
public ref List<ExceptionBlock> Blocks => ref codes[PosOrThrow()].blocks;
7682

7783
/// <summary>Creates an empty code matcher</summary>
7884
public CodeMatcher()
@@ -85,6 +91,7 @@ public CodeMatcher()
8591
///
8692
public CodeMatcher(IEnumerable<CodeInstruction> instructions, ILGenerator generator = null)
8793
{
94+
if (instructions == null) throw new ArgumentNullException(nameof(instructions));
8895
this.generator = generator;
8996
codes = instructions.Select(c => new CodeInstruction(c)).ToList();
9097
}
@@ -103,15 +110,18 @@ public CodeMatcher Clone()
103110
/// <summary>Gets instructions at the current position</summary>
104111
/// <value>The instruction</value>
105112
///
106-
public CodeInstruction Instruction => codes[Pos];
113+
public CodeInstruction Instruction => codes[PosOrThrow()];
107114

108115
/// <summary>Gets instructions at the current position with offset</summary>
109116
/// <param name="offset">The offset</param>
110117
/// <returns>The instruction</returns>
111118
///
112119
public CodeInstruction InstructionAt(int offset)
113120
{
114-
return codes[Pos + offset];
121+
var pos = PosOrThrow();
122+
var newPos = pos + offset;
123+
if (newPos < 0 || newPos >= Length) throw new ArgumentOutOfRangeException(nameof(offset), "offset causes position to go out of bounds");
124+
return codes[newPos];
115125
}
116126

117127
/// <summary>Gets all instructions</summary>
@@ -136,7 +146,7 @@ public IEnumerable<CodeInstruction> InstructionEnumeration()
136146
///
137147
public List<CodeInstruction> Instructions(int count)
138148
{
139-
return codes.GetRange(Pos, count).Select(c => new CodeInstruction(c)).ToList();
149+
return codes.GetRange(PosOrThrow(), count).Select(c => new CodeInstruction(c)).ToList();
140150
}
141151

142152
/// <summary>Gets all instructions within a range</summary>
@@ -163,7 +173,12 @@ public List<CodeInstruction> InstructionsInRange(int start, int end)
163173
///
164174
public List<CodeInstruction> InstructionsWithOffsets(int startOffset, int endOffset)
165175
{
166-
return InstructionsInRange(Pos + startOffset, Pos + endOffset);
176+
var pos = PosOrThrow();
177+
var startPos = pos + startOffset;
178+
if (startPos < 0 || startPos >= Length) throw new ArgumentOutOfRangeException(nameof(startOffset), "startOffset causes position to go out of bounds");
179+
var endPos = pos + endOffset;
180+
if (endPos < 0 || endPos >= Length) throw new ArgumentOutOfRangeException(nameof(endOffset), "endOffset causes position to go out of bounds");
181+
return InstructionsInRange(startPos, endPos);
167182
}
168183

169184
/// <summary>Gets a list of all distinct labels</summary>
@@ -276,7 +291,7 @@ public CodeMatcher ThrowIfFalse(string explanation, Func<CodeMatcher, bool> stat
276291
///
277292
public CodeMatcher SetInstruction(CodeInstruction instruction)
278293
{
279-
codes[Pos] = instruction;
294+
codes[PosOrThrow()] = instruction;
280295
return this;
281296
}
282297

@@ -388,6 +403,7 @@ public CodeMatcher AddLabels(IEnumerable<Label> labels)
388403
///
389404
public CodeMatcher AddLabelsAt(int position, IEnumerable<Label> labels)
390405
{
406+
if (position < 0 || position >= Length) throw new ArgumentOutOfRangeException(nameof(position), "position is out of bounds");
391407
codes[position].labels.AddRange(labels);
392408
return this;
393409
}
@@ -410,7 +426,10 @@ public CodeMatcher SetJumpTo(OpCode opcode, int destination, out Label label)
410426
///
411427
public CodeMatcher Insert(params CodeInstruction[] instructions)
412428
{
413-
codes.InsertRange(Pos, instructions);
429+
if (Pos == Length)
430+
codes.AddRange(instructions);
431+
else
432+
codes.InsertRange(PosOrThrow(), instructions);
414433
return this;
415434
}
416435

@@ -420,7 +439,10 @@ public CodeMatcher Insert(params CodeInstruction[] instructions)
420439
///
421440
public CodeMatcher Insert(IEnumerable<CodeInstruction> instructions)
422441
{
423-
codes.InsertRange(Pos, instructions);
442+
if (Pos == Length)
443+
codes.AddRange(instructions);
444+
else
445+
codes.InsertRange(PosOrThrow(), instructions);
424446
return this;
425447
}
426448

@@ -431,8 +453,9 @@ public CodeMatcher Insert(IEnumerable<CodeInstruction> instructions)
431453
///
432454
public CodeMatcher InsertBranch(OpCode opcode, int destination)
433455
{
456+
var pos = PosOrThrow();
434457
_ = CreateLabelAt(destination, out var label);
435-
codes.Insert(Pos, new CodeInstruction(opcode, label));
458+
codes.Insert(pos, new CodeInstruction(opcode, label));
436459
return this;
437460
}
438461

@@ -479,7 +502,7 @@ public CodeMatcher InsertBranchAndAdvance(OpCode opcode, int destination)
479502
///
480503
public CodeMatcher RemoveInstruction()
481504
{
482-
codes.RemoveAt(Pos);
505+
codes.RemoveAt(PosOrThrow());
483506
return this;
484507
}
485508

@@ -489,7 +512,7 @@ public CodeMatcher RemoveInstruction()
489512
///
490513
public CodeMatcher RemoveInstructions(int count)
491514
{
492-
codes.RemoveRange(Pos, count);
515+
codes.RemoveRange(PosOrThrow(), count);
493516
return this;
494517
}
495518

@@ -500,6 +523,9 @@ public CodeMatcher RemoveInstructions(int count)
500523
///
501524
public CodeMatcher RemoveInstructionsInRange(int start, int end)
502525
{
526+
if (start < 0 || start >= Length) throw new ArgumentOutOfRangeException(nameof(start), "start is out of bounds");
527+
if (end < 0 || end >= Length) throw new ArgumentOutOfRangeException(nameof(end), "end is out of bounds");
528+
503529
if (start > end)
504530
{
505531
(start, end) = (end, start);
@@ -578,7 +604,7 @@ public CodeMatcher SearchBackwards(Func<CodeInstruction, bool> predicate)
578604

579605
private CodeMatcher Search(Func<CodeInstruction, bool> predicate, int direction)
580606
{
581-
FixStart();
607+
FixStart(); //todo: Should invalid position throw instead? Breaking change
582608
while (IsValid && predicate(Instruction) == false)
583609
Pos += direction;
584610
lastError = IsInvalid ? $"Cannot find {predicate}" : null;
@@ -642,9 +668,9 @@ public CodeMatcher MatchEndBackwards(params CodeMatch[] matches)
642668

643669
private CodeMatcher Match(CodeMatch[] matches, int direction, bool useEnd)
644670
{
645-
lastMatchCall = delegate()
671+
lastMatchCall = delegate ()
646672
{
647-
FixStart();
673+
FixStart(); //todo: Should invalid position throw instead? Breaking change
648674
while (IsValid)
649675
{
650676
if (MatchSequence(Pos, matches))

0 commit comments

Comments
 (0)