Skip to content

Commit

Permalink
refs #9880 show index and bound in lots of index out of bounds errors
Browse files Browse the repository at this point in the history
  • Loading branch information
timotheecour committed Dec 10, 2018
1 parent 7a66616 commit f3ecc15
Show file tree
Hide file tree
Showing 9 changed files with 64 additions and 23 deletions.
12 changes: 6 additions & 6 deletions compiler/ccgexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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,
Expand All @@ -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}:
Expand Down
2 changes: 2 additions & 0 deletions compiler/cgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
8 changes: 5 additions & 3 deletions compiler/semfold.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -489,19 +491,19 @@ 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):
result.intVal = ord(x.strVal[int(idx)])
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 =
Expand Down
6 changes: 4 additions & 2 deletions lib/pure/collections/sharedstrings.nim
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
type
UncheckedCharArray = UncheckedArray[char]

import system/helpers2

type
Buffer = ptr object
refcount: int
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions lib/pure/subexes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) {.
Expand Down
9 changes: 8 additions & 1 deletion lib/system/chcks.nim
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,20 @@
#

# Implementation of some runtime checks.
import system/helpers2

proc raiseRangeError(val: BiggestInt) {.compilerproc, noinline.} =
when hostOS == "standalone":
sysFatal(RangeError, "value out of range")
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")

Expand All @@ -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:
Expand Down
5 changes: 5 additions & 0 deletions lib/system/helpers2.nim
Original file line number Diff line number Diff line change
@@ -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 & ") "
25 changes: 16 additions & 9 deletions tests/misc/tinvalidarrayaccess.nim
Original file line number Diff line number Diff line change
@@ -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))
16 changes: 16 additions & 0 deletions tests/misc/tinvalidarrayaccess2.nim
Original file line number Diff line number Diff line change
@@ -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()

0 comments on commit f3ecc15

Please sign in to comment.