refs #9880 show index and bound in lots of index out of bounds errors

This commit is contained in:
Timothee Cour 2018-12-06 15:42:44 -08:00
commit f3ecc15a94
9 changed files with 64 additions and 23 deletions

View file

@ -867,15 +867,15 @@ proc genArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
# semantic pass has already checked for const index expressions # semantic pass has already checked for const index expressions
if firstOrd(p.config, ty) == 0: 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)): 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))) rdCharLoc(b), intLiteral(lastOrd(p.config, ty)))
else: 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))) rdCharLoc(b), first, intLiteral(lastOrd(p.config, ty)))
else: else:
let idx = getOrdValue(y) let idx = getOrdValue(y)
if idx < firstOrd(p.config, ty) or idx > lastOrd(p.config, ty): 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) d.inheritLocation(a)
putIntoDest(p, d, n, putIntoDest(p, d, n,
ropecg(p.module, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first), a.storage) 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, x, a)
initLocExpr(p, y, b) # emit range check: initLocExpr(p, y, b) # emit range check:
if optBoundsCheck in p.options: 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 ``>``! rdLoc(b), rdLoc(a)) # BUGFIX: ``>=`` and not ``>``!
inheritLocation(d, a) inheritLocation(d, a)
putIntoDest(p, d, n, 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 optBoundsCheck in p.options:
if ty.kind == tyString and (not defined(nimNoZeroTerminator) or optLaxStrings in p.options): if ty.kind == tyString and (not defined(nimNoZeroTerminator) or optLaxStrings in p.options):
linefmt(p, cpsStmts, linefmt(p, cpsStmts,
"if ((NU)($1) > (NU)$2) #raiseIndexError();$n", "if ((NU)($1) > (NU)$2) #raiseIndexError2($1,$2);$n",
rdLoc(b), lenExpr(p, a)) rdLoc(b), lenExpr(p, a))
else: else:
linefmt(p, cpsStmts, 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)) rdLoc(b), lenExpr(p, a))
if d.k == locNone: d.storage = OnHeap if d.k == locNone: d.storage = OnHeap
if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}: if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}:

View file

@ -16,6 +16,8 @@ import
condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases,
lowerings, tables, sets, ndi, lineinfos, pathutils, transf lowerings, tables, sets, ndi, lineinfos, pathutils, transf
import system/helpers2
when not defined(leanCompiler): when not defined(leanCompiler):
import semparallel import semparallel

View file

@ -15,6 +15,8 @@ import
nversion, platform, math, msgs, os, condsyms, idents, renderer, types, nversion, platform, math, msgs, os, condsyms, idents, renderer, types,
commands, magicsys, modulegraphs, strtabs, lineinfos commands, magicsys, modulegraphs, strtabs, lineinfos
import system/helpers2
proc newIntNodeT*(intVal: BiggestInt, n: PNode; g: ModuleGraph): PNode = proc newIntNodeT*(intVal: BiggestInt, n: PNode; g: ModuleGraph): PNode =
case skipTypes(n.typ, abstractVarRange).kind case skipTypes(n.typ, abstractVarRange).kind
of tyInt: of tyInt:
@ -489,11 +491,11 @@ proc foldArrayAccess(m: PSym, n: PNode; g: ModuleGraph): PNode =
result = x.sons[int(idx)] result = x.sons[int(idx)]
if result.kind == nkExprColonExpr: result = result.sons[1] if result.kind == nkExprColonExpr: result = result.sons[1]
else: else:
localError(g.config, n.info, "index out of bounds: " & $n) localError(g.config, n.info, formatErrorIndexBound(idx, sonsLen(x)+1) & $n)
of nkBracket: of nkBracket:
idx = idx - firstOrd(g.config, x.typ) idx = idx - firstOrd(g.config, x.typ)
if idx >= 0 and idx < x.len: result = x.sons[int(idx)] 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: of nkStrLit..nkTripleStrLit:
result = newNodeIT(nkCharLit, x.info, n.typ) result = newNodeIT(nkCharLit, x.info, n.typ)
if idx >= 0 and idx < len(x.strVal): 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: elif idx == len(x.strVal) and optLaxStrings in g.config.options:
discard discard
else: 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 else: discard
proc foldFieldAccess(m: PSym, n: PNode; g: ModuleGraph): PNode = proc foldFieldAccess(m: PSym, n: PNode; g: ModuleGraph): PNode =

View file

@ -12,6 +12,8 @@
type type
UncheckedCharArray = UncheckedArray[char] UncheckedCharArray = UncheckedArray[char]
import system/helpers2
type type
Buffer = ptr object Buffer = ptr object
refcount: int refcount: int
@ -49,11 +51,11 @@ proc len*(s: SharedString): int = s.len
proc `[]`*(s: SharedString; i: Natural): char = proc `[]`*(s: SharedString; i: Natural): char =
if i < s.len: result = s.buffer.data[i+s.first] 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) = proc `[]=`*(s: var SharedString; i: Natural; value: char) =
if i < s.len: s.buffer.data[i+s.first] = value 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 = proc `[]`*(s: SharedString; ab: HSlice[int, int]): SharedString =
#incRef(src.buffer) #incRef(src.buffer)

View file

@ -17,7 +17,7 @@
from strutils import parseInt, cmpIgnoreStyle, Digits from strutils import parseInt, cmpIgnoreStyle, Digits
include "system/inclrtl" include "system/inclrtl"
import system/helpers2
proc findNormalized(x: string, inArray: openarray[string]): int = proc findNormalized(x: string, inArray: openarray[string]): int =
var i = 0 var i = 0
@ -85,7 +85,7 @@ proc getFormatArg(p: var FormatParser, a: openArray[string]): int =
result = parseInt(a[result])-1 result = parseInt(a[result])-1
else: else:
raiseInvalidFormat("'#', '$', number or identifier expected") 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 p.i = i
proc scanDollar(p: var FormatParser, a: openarray[string], s: var string) {. proc scanDollar(p: var FormatParser, a: openarray[string], s: var string) {.

View file

@ -8,6 +8,7 @@
# #
# Implementation of some runtime checks. # Implementation of some runtime checks.
import system/helpers2
proc raiseRangeError(val: BiggestInt) {.compilerproc, noinline.} = proc raiseRangeError(val: BiggestInt) {.compilerproc, noinline.} =
when hostOS == "standalone": when hostOS == "standalone":
@ -15,6 +16,12 @@ proc raiseRangeError(val: BiggestInt) {.compilerproc, noinline.} =
else: else:
sysFatal(RangeError, "value out of range: ", $val) 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.} = proc raiseIndexError() {.compilerproc, noinline.} =
sysFatal(IndexError, "index out of bounds") sysFatal(IndexError, "index out of bounds")
@ -25,7 +32,7 @@ proc chckIndx(i, a, b: int): int =
if i >= a and i <= b: if i >= a and i <= b:
return i return i
else: else:
raiseIndexError() raiseIndexError3(i, a, b)
proc chckRange(i, a, b: int): int = proc chckRange(i, a, b: int): int =
if i >= a and i <= b: if i >= a and i <= b:

5
lib/system/helpers2.nim Normal file
View file

@ -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 & ") "

View file

@ -1,14 +1,21 @@
discard """ discard """
errormsg: "index out of bounds" errormsg: "index out of bounds: (a:0) <= (i:2) <= (b:1) "
line: 11 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] block:
var f: TTestArr type TTestArr = array[0..1, int16]
f[0] = 30 var f: TTestArr
f[1] = 40 f[0] = 30
f[2] = 50 f[1] = 40
f[3] = 60 f[2] = 50
f[3] = 60
echo(repr(f)) echo(repr(f))

View file

@ -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()