diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 59ef05f9c583..6b3b9b63f1bd 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -867,15 +867,15 @@ proc genArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) = # semantic pass has already checked for const index expressions if firstOrd(p.config, ty) == 0: if (firstOrd(p.config, b.t) < firstOrd(p.config, ty)) or (lastOrd(p.config, b.t) > lastOrd(p.config, ty)): - linefmt(p, cpsStmts, "if ((NU)($1) > (NU)($2)) #raiseIndexError();$n", + linefmt(p, cpsStmts, "if ((NU)($1) > (NU)($2)) #raiseIndexError2($1, $2);$n", rdCharLoc(b), intLiteral(lastOrd(p.config, ty))) else: - linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseIndexError();$n", + linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseIndexError3($1, $2, $3);$n", rdCharLoc(b), first, intLiteral(lastOrd(p.config, ty))) else: let idx = getOrdValue(y) if idx < firstOrd(p.config, ty) or idx > lastOrd(p.config, ty): - localError(p.config, x.info, "index out of bounds") + localError(p.config, x.info, formatErrorIndexBound(idx, firstOrd(p.config, ty), lastOrd(p.config, ty))) d.inheritLocation(a) putIntoDest(p, d, n, ropecg(p.module, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first), a.storage) @@ -915,7 +915,7 @@ proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) = initLocExpr(p, x, a) initLocExpr(p, y, b) # emit range check: if optBoundsCheck in p.options: - linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)) #raiseIndexError();$n", + linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)) #raiseIndexError2($1,$2Len_0-1);$n", rdLoc(b), rdLoc(a)) # BUGFIX: ``>=`` and not ``>``! inheritLocation(d, a) putIntoDest(p, d, n, @@ -931,11 +931,11 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) = if optBoundsCheck in p.options: if ty.kind == tyString and (not defined(nimNoZeroTerminator) or optLaxStrings in p.options): linefmt(p, cpsStmts, - "if ((NU)($1) > (NU)$2) #raiseIndexError();$n", + "if ((NU)($1) > (NU)$2) #raiseIndexError2($1,$2);$n", rdLoc(b), lenExpr(p, a)) else: linefmt(p, cpsStmts, - "if ((NU)($1) >= (NU)$2) #raiseIndexError();$n", + "if ((NU)($1) >= (NU)$2) #raiseIndexError2($1,$2-1);$n", rdLoc(b), lenExpr(p, a)) if d.k == locNone: d.storage = OnHeap if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}: diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 3545edc88c2a..457a6e176e61 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -16,6 +16,8 @@ import condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, lowerings, tables, sets, ndi, lineinfos, pathutils, transf +import system/helpers2 + when not defined(leanCompiler): import semparallel diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 5ec7022576e5..305ed9bcf9ec 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -15,6 +15,8 @@ import nversion, platform, math, msgs, os, condsyms, idents, renderer, types, commands, magicsys, modulegraphs, strtabs, lineinfos +import system/helpers2 + proc newIntNodeT*(intVal: BiggestInt, n: PNode; g: ModuleGraph): PNode = case skipTypes(n.typ, abstractVarRange).kind of tyInt: @@ -489,11 +491,11 @@ proc foldArrayAccess(m: PSym, n: PNode; g: ModuleGraph): PNode = result = x.sons[int(idx)] if result.kind == nkExprColonExpr: result = result.sons[1] else: - localError(g.config, n.info, "index out of bounds: " & $n) + localError(g.config, n.info, formatErrorIndexBound(idx, sonsLen(x)+1) & $n) of nkBracket: idx = idx - firstOrd(g.config, x.typ) if idx >= 0 and idx < x.len: result = x.sons[int(idx)] - else: localError(g.config, n.info, "index out of bounds: " & $n) + else: localError(g.config, n.info, formatErrorIndexBound(idx, x.len+1) & $n) of nkStrLit..nkTripleStrLit: result = newNodeIT(nkCharLit, x.info, n.typ) if idx >= 0 and idx < len(x.strVal): @@ -501,7 +503,7 @@ proc foldArrayAccess(m: PSym, n: PNode; g: ModuleGraph): PNode = elif idx == len(x.strVal) and optLaxStrings in g.config.options: discard else: - localError(g.config, n.info, "index out of bounds: " & $n) + localError(g.config, n.info, formatErrorIndexBound(idx, len(x.strVal)-1) & $n) else: discard proc foldFieldAccess(m: PSym, n: PNode; g: ModuleGraph): PNode = diff --git a/lib/pure/collections/sharedstrings.nim b/lib/pure/collections/sharedstrings.nim index 7e9de4b73e05..b283cd4b10e5 100644 --- a/lib/pure/collections/sharedstrings.nim +++ b/lib/pure/collections/sharedstrings.nim @@ -12,6 +12,8 @@ type UncheckedCharArray = UncheckedArray[char] +import system/helpers2 + type Buffer = ptr object refcount: int @@ -49,11 +51,11 @@ proc len*(s: SharedString): int = s.len proc `[]`*(s: SharedString; i: Natural): char = if i < s.len: result = s.buffer.data[i+s.first] - else: raise newException(IndexError, "index out of bounds") + else: raise newException(IndexError, formatErrorIndexBound(i, s.len-1)) proc `[]=`*(s: var SharedString; i: Natural; value: char) = if i < s.len: s.buffer.data[i+s.first] = value - else: raise newException(IndexError, "index out of bounds") + else: raise newException(IndexError, formatErrorIndexBound(i, s.len-1)) proc `[]`*(s: SharedString; ab: HSlice[int, int]): SharedString = #incRef(src.buffer) diff --git a/lib/pure/subexes.nim b/lib/pure/subexes.nim index d103af710ed8..638e71f04d48 100644 --- a/lib/pure/subexes.nim +++ b/lib/pure/subexes.nim @@ -17,7 +17,7 @@ from strutils import parseInt, cmpIgnoreStyle, Digits include "system/inclrtl" - +import system/helpers2 proc findNormalized(x: string, inArray: openarray[string]): int = var i = 0 @@ -85,7 +85,7 @@ proc getFormatArg(p: var FormatParser, a: openArray[string]): int = result = parseInt(a[result])-1 else: raiseInvalidFormat("'#', '$', number or identifier expected") - if result >=% a.len: raiseInvalidFormat("index out of bounds: " & $result) + if result >=% a.len: raiseInvalidFormat(formatErrorIndexBound(result, a.len)) p.i = i proc scanDollar(p: var FormatParser, a: openarray[string], s: var string) {. diff --git a/lib/system/chcks.nim b/lib/system/chcks.nim index d3651f659012..6f4e8ce377da 100644 --- a/lib/system/chcks.nim +++ b/lib/system/chcks.nim @@ -8,6 +8,7 @@ # # Implementation of some runtime checks. +import system/helpers2 proc raiseRangeError(val: BiggestInt) {.compilerproc, noinline.} = when hostOS == "standalone": @@ -15,6 +16,12 @@ proc raiseRangeError(val: BiggestInt) {.compilerproc, noinline.} = else: sysFatal(RangeError, "value out of range: ", $val) +proc raiseIndexError3(i, a, b: int) {.compilerproc, noinline.} = + sysFatal(IndexError, formatErrorIndexBound(i, a, b)) + +proc raiseIndexError2(i, n: int) {.compilerproc, noinline.} = + sysFatal(IndexError, formatErrorIndexBound(i, n)) + proc raiseIndexError() {.compilerproc, noinline.} = sysFatal(IndexError, "index out of bounds") @@ -25,7 +32,7 @@ proc chckIndx(i, a, b: int): int = if i >= a and i <= b: return i else: - raiseIndexError() + raiseIndexError3(i, a, b) proc chckRange(i, a, b: int): int = if i >= a and i <= b: diff --git a/lib/system/helpers2.nim b/lib/system/helpers2.nim new file mode 100644 index 000000000000..1c9e7c068d21 --- /dev/null +++ b/lib/system/helpers2.nim @@ -0,0 +1,5 @@ +template formatErrorIndexBound*[T](i, a, b: T): string = + "index out of bounds: (a:" & $a & ") <= (i:" & $i & ") <= (b:" & $b & ") " + +template formatErrorIndexBound*[T](i, n: T): string = + "index out of bounds: (i:" & $i & ") <= (n:" & $n & ") " diff --git a/tests/misc/tinvalidarrayaccess.nim b/tests/misc/tinvalidarrayaccess.nim index 03105b41b9fb..57ad38b85e67 100644 --- a/tests/misc/tinvalidarrayaccess.nim +++ b/tests/misc/tinvalidarrayaccess.nim @@ -1,14 +1,21 @@ discard """ - errormsg: "index out of bounds" - line: 11 + errormsg: "index out of bounds: (a:0) <= (i:2) <= (b:1) " + line: 18 """ +block: + try: + let a = @[1,2] + echo a[3] + except Exception as e: + doAssert e.msg == "index out of bounds: (i:3) <= (n:1) " -type TTestArr = array[0..1, int16] -var f: TTestArr -f[0] = 30 -f[1] = 40 -f[2] = 50 -f[3] = 60 +block: + type TTestArr = array[0..1, int16] + var f: TTestArr + f[0] = 30 + f[1] = 40 + f[2] = 50 + f[3] = 60 -echo(repr(f)) + echo(repr(f)) diff --git a/tests/misc/tinvalidarrayaccess2.nim b/tests/misc/tinvalidarrayaccess2.nim new file mode 100644 index 000000000000..86d34945773c --- /dev/null +++ b/tests/misc/tinvalidarrayaccess2.nim @@ -0,0 +1,16 @@ +discard """ + errormsg: "index out of bounds: (a:0) <= (i:3) <= (b:1) " + line: 9 +""" + +# Note: merge in tinvalidarrayaccess.nim pending https://github.com/nim-lang/Nim/issues/9906 + +let a = [1,2] +echo a[3] + +when false: + # TOOD: this case is not yet handled, giving: "index out of bounds" + proc fun()= + let a = @[1,2] + echo a[3] + static: fun()