Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes 9880 #10228

Closed
wants to merge 8 commits into from
4 changes: 2 additions & 2 deletions compiler/semfold.nim
Original file line number Diff line number Diff line change
Expand Up @@ -493,11 +493,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, formatErrorIndexBound(idx, sonsLen(x)+1) & $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, formatErrorIndexBound(idx, x.len+1) & $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):
Expand Down
22 changes: 11 additions & 11 deletions compiler/vm.nim
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const
traceCode = debugEchoCode

import ast except getstr
import system/helpers2

import
strutils, astalgo, msgs, vmdef, vmgen, nimsets, types, passes,
Expand Down Expand Up @@ -432,7 +433,6 @@ proc setLenSeq(c: PCtx; node: PNode; newLen: int; info: TLineInfo) =
node.sons[i] = getNullValue(typ.sons[0], info, c.config)

const
errIndexOutOfBounds = "index out of bounds"
errNilAccess = "attempt to access a nil address"
errOverOrUnderflow = "over- or underflow"
errConstantDivisionByZero = "division by zero"
Expand Down Expand Up @@ -529,19 +529,19 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
# a = b[c]
decodeBC(rkNode)
if regs[rc].intVal > high(int):
stackTrace(c, tos, pc, errIndexOutOfBounds)
stackTrace(c, tos, pc, formatErrorIndexBound(regs[rc].intVal, high(int)))
let idx = regs[rc].intVal.int
let src = regs[rb].node
if src.kind in {nkStrLit..nkTripleStrLit}:
if idx <% src.strVal.len:
regs[ra].node = newNodeI(nkCharLit, c.debug[pc])
regs[ra].node.intVal = src.strVal[idx].ord
else:
stackTrace(c, tos, pc, errIndexOutOfBounds)
stackTrace(c, tos, pc, formatErrorIndexBound(idx, src.strVal.len-1))
elif src.kind notin {nkEmpty..nkFloat128Lit} and idx <% src.len:
regs[ra].node = src.sons[idx]
else:
stackTrace(c, tos, pc, errIndexOutOfBounds)
stackTrace(c, tos, pc, formatErrorIndexBound(idx, src.len-1))
of opcLdStrIdx:
decodeBC(rkInt)
let idx = regs[rc].intVal.int
Expand All @@ -551,7 +551,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
elif idx == s.len and optLaxStrings in c.config.options:
regs[ra].intVal = 0
else:
stackTrace(c, tos, pc, errIndexOutOfBounds)
stackTrace(c, tos, pc, formatErrorIndexBound(idx, s.len-1))
of opcWrArr:
# a[b] = c
decodeBC(rkNode)
Expand All @@ -561,11 +561,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
if idx <% arr.strVal.len:
arr.strVal[idx] = chr(regs[rc].intVal)
else:
stackTrace(c, tos, pc, errIndexOutOfBounds)
stackTrace(c, tos, pc, formatErrorIndexBound(idx, arr.strVal.len-1))
elif idx <% arr.len:
writeField(arr.sons[idx], regs[rc])
else:
stackTrace(c, tos, pc, errIndexOutOfBounds)
stackTrace(c, tos, pc, formatErrorIndexBound(idx, arr.len-1))
of opcLdObj:
# a = b.c
decodeBC(rkNode)
Expand Down Expand Up @@ -596,7 +596,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
if idx <% regs[ra].node.strVal.len:
regs[ra].node.strVal[idx] = chr(regs[rc].intVal)
else:
stackTrace(c, tos, pc, errIndexOutOfBounds)
stackTrace(c, tos, pc, formatErrorIndexBound(idx, regs[ra].node.strVal.len-1))
of opcAddrReg:
decodeB(rkRegisterAddr)
regs[ra].regAddr = addr(regs[rb])
Expand Down Expand Up @@ -1298,15 +1298,15 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
if src.kind notin {nkEmpty..nkNilLit} and idx <% src.len:
regs[ra].node = src.sons[idx]
else:
stackTrace(c, tos, pc, errIndexOutOfBounds)
stackTrace(c, tos, pc, formatErrorIndexBound(idx, src.len-1))
of opcNSetChild:
decodeBC(rkNode)
let idx = regs[rb].intVal.int
var dest = regs[ra].node
if dest.kind notin {nkEmpty..nkNilLit} and idx <% dest.len:
dest.sons[idx] = regs[rc].node
else:
stackTrace(c, tos, pc, errIndexOutOfBounds)
stackTrace(c, tos, pc, formatErrorIndexBound(idx, dest.len-1))
of opcNAdd:
decodeBC(rkNode)
var u = regs[rb].node
Expand Down Expand Up @@ -1711,7 +1711,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
if contains(g.cacheSeqs, destKey) and idx <% g.cacheSeqs[destKey].len:
regs[ra].node = g.cacheSeqs[destKey][idx.int]
else:
stackTrace(c, tos, pc, errIndexOutOfBounds)
stackTrace(c, tos, pc, formatErrorIndexBound(idx, g.cacheSeqs[destKey].len-1))
of opcNctPut:
let g = c.graph
let destKey = regs[ra].node.strVal
Expand Down
10 changes: 6 additions & 4 deletions lib/core/typeinfo.nim
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
include "system/inclrtl.nim"
include "system/hti.nim"

import system/helpers2

{.pop.}

type
Expand Down Expand Up @@ -194,14 +196,14 @@ proc `[]`*(x: Any, i: int): Any =
of tyArray:
var bs = x.rawType.base.size
if i >=% x.rawType.size div bs:
raise newException(IndexError, "index out of bounds")
raise newException(IndexError, formatErrorIndexBound(i, x.rawType.size div bs))
return newAny(x.value +!! i*bs, x.rawType.base)
of tySequence:
var s = cast[ppointer](x.value)[]
if s == nil: raise newException(ValueError, "sequence is nil")
var bs = x.rawType.base.size
if i >=% cast[PGenSeq](s).len:
raise newException(IndexError, "index out of bounds")
raise newException(IndexError, formatErrorIndexBound(i, cast[PGenSeq](s).len-1))
return newAny(s +!! (GenericSeqSize+i*bs), x.rawType.base)
else: assert false

Expand All @@ -211,15 +213,15 @@ proc `[]=`*(x: Any, i: int, y: Any) =
of tyArray:
var bs = x.rawType.base.size
if i >=% x.rawType.size div bs:
raise newException(IndexError, "index out of bounds")
raise newException(IndexError, formatErrorIndexBound(i, x.rawType.size div bs))
assert y.rawType == x.rawType.base
genericAssign(x.value +!! i*bs, y.value, y.rawType)
of tySequence:
var s = cast[ppointer](x.value)[]
if s == nil: raise newException(ValueError, "sequence is nil")
var bs = x.rawType.base.size
if i >=% cast[PGenSeq](s).len:
raise newException(IndexError, "index out of bounds")
raise newException(IndexError, formatErrorIndexBound(i, cast[PGenSeq](s).len-1))
assert y.rawType == x.rawType.base
genericAssign(s +!! (GenericSeqSize+i*bs), y.value, y.rawType)
else: assert false
Expand Down
6 changes: 3 additions & 3 deletions lib/pure/os.nim
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
include "system/inclrtl"

import
strutils, pathnorm
strutils, pathnorm, system/helpers2

const weirdTarget = defined(nimscript) or defined(js)

Expand Down Expand Up @@ -2018,7 +2018,7 @@ elif defined(windows):
ownArgv = parseCmdLine($getCommandLine())
ownParsedArgv = true
if i < ownArgv.len and i >= 0: return TaintedString(ownArgv[i])
raise newException(IndexError, "invalid index")
raise newException(IndexError, formatErrorIndexBound(i, ownArgv.len-1))

elif defined(genode):
proc paramStr*(i: int): TaintedString =
Expand All @@ -2037,7 +2037,7 @@ elif not defined(createNimRtl) and
proc paramStr*(i: int): TaintedString {.tags: [ReadIOEffect].} =
# Docstring in nimdoc block.
if i < cmdCount and i >= 0: return TaintedString($cmdLine[i])
raise newException(IndexError, "invalid index")
raise newException(IndexError, formatErrorIndexBound(i, cmdCount-1))

proc paramCount*(): int {.tags: [ReadIOEffect].} =
# Docstring in nimdoc block.
Expand Down
8 changes: 5 additions & 3 deletions lib/system/jssys.nim
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
# distribution, for details about the copyright.
#

import system/helpers2

proc log*(s: cstring) {.importc: "console.log", varargs, nodecl.}

type
Expand Down Expand Up @@ -157,8 +159,8 @@ proc raiseDivByZero {.exportc: "raiseDivByZero", noreturn, compilerProc.} =
proc raiseRangeError() {.compilerproc, noreturn.} =
raise newException(RangeError, "value out of range")

proc raiseIndexError() {.compilerproc, noreturn.} =
raise newException(IndexError, "index out of bounds")
proc raiseIndexError(i, a, b: int) {.compilerproc, noreturn.} =
raise newException(IndexError, formatErrorIndexBound(int(i), int(a), int(b)))

proc raiseFieldError(f: string) {.compilerproc, noreturn.} =
raise newException(FieldError, f & " is not accessible")
Expand Down Expand Up @@ -626,7 +628,7 @@ proc arrayConstr(len: int, value: JSRef, typ: PNimType): JSRef {.

proc chckIndx(i, a, b: int): int {.compilerproc.} =
if i >= a and i <= b: return i
else: raiseIndexError()
else: raiseIndexError(i, a, b)

proc chckRange(i, a, b: int): int {.compilerproc.} =
if i >= a and i <= b: return i
Expand Down
23 changes: 23 additions & 0 deletions tests/exception/testindexerroroutput.nims
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
mode = ScriptMode.Verbose

case paramStr(3):
of "test1":
#543
block:
let s = "abc"
discard s[len(s)]
of "test2":
#537
block:
var s = "abc"
s[len(s)] = 'd'
of "test3":
#588
block:
let arr = ['a', 'b', 'c']
discard arr[len(arr)]
of "test4":
#588
block:
var arr = ['a', 'b', 'c']
arr[len(arr)] = 'd'
52 changes: 52 additions & 0 deletions tests/exception/tindexerrorformatbounds.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import os
import strutils


const characters = "abcdefghijklmnopqrstuvwxyz"
var s: string

# # chcks.nim:23
# # test formatErrorIndexBound returns correct bounds
block:
s = characters
try:
discard s[0..999]
except IndexError:
let msg = getCurrentExceptionMsg()
let expected = "(i:$#) <= (n:$#)" % [$len(s), $(len(s)-1)]
doAssert msg.contains expected

block:
try:
discard paramStr(999)
except IndexError:
let msg = getCurrentExceptionMsg()
let expected = "(i:999) <= (n:0)"
doAssert msg.contains expected

static:
const nim = getCurrentCompilerExe()

block:
let ret = gorgeEx(nim & " e testindexerroroutput.nims test1")
let expected = "(i:3) <= (n:2)"
doAssert ret.exitCode != 0
doAssert ret.output.contains expected

block:
let ret = gorgeEx(nim & " e testindexerroroutput.nims test2")
let expected = "(i:3) <= (n:2)"
doAssert ret.exitCode != 0
doAssert ret.output.contains expected

block:
let ret = gorgeEx(nim & " e testindexerroroutput.nims test3")
let expected = "(i:3) <= (n:2)"
doAssert ret.exitCode != 0
doAssert ret.output.contains expected

block:
let ret = gorgeEx(nim & " e testindexerroroutput.nims test4")
let expected = "(i:3) <= (n:2)"
doAssert ret.exitCode != 0
doAssert ret.output.contains expected