Skip to content

Commit 8b9972c

Browse files
authored
orc: fix overflow checking regression (#25089)
Raising exceptions halfway through a memory allocation is undefined behavior since exceptions themselves require multiple allocations and the allocator functions are not reentrant. It is of course also expensive performance-wise to introduce lots of exception-raising code everywhere since it breaks many optimisations and bloats the code. Finally, performing pointer arithmetic with signed integers is incorrect for example on on a 32-bit systems that allows up to 3gb of address space for applications (large address extensions) and unnecessary elsewhere - broadly, stuff inside the memory allocator is generated by the compiler or controlled by the standard library meaning that applications should not be forced to pay this price. If we wanted to check for overflow, the right way would be in the initial allocation location where both the size and count of objects is known. The code is updated to use the same arithmetic operator style as for refc with unchecked operations rather than disabling overflow checking wholesale in the allocator module - there are reasons for both, but going with the existing flow seems like an easier place to start.
1 parent cdb750c commit 8b9972c

File tree

14 files changed

+93
-123
lines changed

14 files changed

+93
-123
lines changed

lib/core/typeinfo.nim

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -134,19 +134,17 @@ else:
134134
proc zeroNewElements(len: int; p: pointer; addlen, elemSize, elemAlign: int) {.
135135
importCompilerProc.}
136136

137-
template `+!!`(a, b): untyped = cast[pointer](cast[int](a) + b)
137+
include system/ptrarith
138138

139139
proc getDiscriminant(aa: pointer, n: ptr TNimNode): int =
140140
assert(n.kind == nkCase)
141-
var d: int
142-
let a = cast[int](aa)
141+
let a = aa +! n.offset
143142
case n.typ.size
144-
of 1: d = int(cast[ptr uint8](a +% n.offset)[])
145-
of 2: d = int(cast[ptr uint16](a +% n.offset)[])
146-
of 4: d = int(cast[ptr uint32](a +% n.offset)[])
147-
of 8: d = int(cast[ptr uint64](a +% n.offset)[])
143+
of 1: int(cast[ptr uint8](a)[])
144+
of 2: int(cast[ptr uint16](a)[])
145+
of 4: int(cast[ptr uint32](a)[])
146+
of 8: cast[int](cast[ptr uint64](a)[])
148147
else: raiseAssert "unreachable"
149-
return d
150148

151149
proc selectBranch(aa: pointer, n: ptr TNimNode): ptr TNimNode =
152150
let discr = getDiscriminant(aa, n)
@@ -240,17 +238,14 @@ proc skipRange(x: PNimType): PNimType {.inline.} =
240238
result = x
241239
if result.kind == tyRange: result = result.base
242240

243-
proc align(address, alignment: int): int =
244-
result = (address + (alignment - 1)) and not (alignment - 1)
245-
246241
proc `[]`*(x: Any, i: int): Any =
247242
## Accessor for an any `x` that represents an array or a sequence.
248243
case x.rawType.kind
249244
of tyArray:
250245
let bs = x.rawType.base.size
251246
if i >=% x.rawType.size div bs:
252247
raise newException(IndexDefect, formatErrorIndexBound(i, x.rawType.size div bs))
253-
return newAny(x.value +!! i*bs, x.rawType.base)
248+
return newAny(x.value +! i*bs, x.rawType.base)
254249
of tySequence:
255250
when defined(gcDestructors):
256251
var s = cast[ptr NimSeqV2Reimpl](x.value)
@@ -259,14 +254,14 @@ proc `[]`*(x: Any, i: int): Any =
259254
let bs = x.rawType.base.size
260255
let ba = x.rawType.base.align
261256
let headerSize = align(sizeof(int), ba)
262-
return newAny(s.p +!! (headerSize+i*bs), x.rawType.base)
257+
return newAny(s.p +! (headerSize+i*bs), x.rawType.base)
263258
else:
264259
var s = cast[ppointer](x.value)[]
265260
if s == nil: raise newException(ValueError, "sequence is nil")
266261
let bs = x.rawType.base.size
267262
if i >=% cast[PGenSeq](s).len:
268263
raise newException(IndexDefect, formatErrorIndexBound(i, cast[PGenSeq](s).len-1))
269-
return newAny(s +!! (align(GenericSeqSize, x.rawType.base.align)+i*bs), x.rawType.base)
264+
return newAny(s +! (align(GenericSeqSize, x.rawType.base.align)+i*bs), x.rawType.base)
270265
else: raiseAssert "unreachable"
271266

272267
proc `[]=`*(x: Any, i: int, y: Any) =
@@ -277,7 +272,7 @@ proc `[]=`*(x: Any, i: int, y: Any) =
277272
if i >=% x.rawType.size div bs:
278273
raise newException(IndexDefect, formatErrorIndexBound(i, x.rawType.size div bs))
279274
assert y.rawType == x.rawType.base
280-
genericAssign(x.value +!! i*bs, y.value, y.rawType)
275+
genericAssign(x.value +! i*bs, y.value, y.rawType)
281276
of tySequence:
282277
when defined(gcDestructors):
283278
var s = cast[ptr NimSeqV2Reimpl](x.value)
@@ -287,15 +282,15 @@ proc `[]=`*(x: Any, i: int, y: Any) =
287282
let ba = x.rawType.base.align
288283
let headerSize = align(sizeof(int), ba)
289284
assert y.rawType == x.rawType.base
290-
genericAssign(s.p +!! (headerSize+i*bs), y.value, y.rawType)
285+
genericAssign(s.p +! (headerSize+i*bs), y.value, y.rawType)
291286
else:
292287
var s = cast[ppointer](x.value)[]
293288
if s == nil: raise newException(ValueError, "sequence is nil")
294289
var bs = x.rawType.base.size
295290
if i >=% cast[PGenSeq](s).len:
296291
raise newException(IndexDefect, formatErrorIndexBound(i, cast[PGenSeq](s).len-1))
297292
assert y.rawType == x.rawType.base
298-
genericAssign(s +!! (align(GenericSeqSize, x.rawType.base.align)+i*bs), y.value, y.rawType)
293+
genericAssign(s +! (align(GenericSeqSize, x.rawType.base.align)+i*bs), y.value, y.rawType)
299294
else: raiseAssert "unreachable"
300295

301296
proc len*(x: Any): int =
@@ -352,13 +347,13 @@ proc fieldsAux(p: pointer, n: ptr TNimNode,
352347
case n.kind
353348
of nkNone: assert(false)
354349
of nkSlot:
355-
ret.add((n.name, newAny(p +!! n.offset, n.typ)))
350+
ret.add((n.name, newAny(p +! n.offset, n.typ)))
356351
assert ret[ret.len()-1][0] != nil
357352
of nkList:
358353
for i in 0..n.len-1: fieldsAux(p, n.sons[i], ret)
359354
of nkCase:
360355
var m = selectBranch(p, n)
361-
ret.add((n.name, newAny(p +!! n.offset, n.typ)))
356+
ret.add((n.name, newAny(p +! n.offset, n.typ)))
362357
if m != nil: fieldsAux(p, m, ret)
363358

364359
iterator fields*(x: Any): tuple[name: string, any: Any] =
@@ -409,7 +404,7 @@ proc `[]=`*(x: Any, fieldName: string, value: Any) =
409404
let n = getFieldNode(x.value, t.node, fieldName)
410405
if n != nil:
411406
assert n.typ == value.rawType
412-
genericAssign(x.value +!! n.offset, value.value, value.rawType)
407+
genericAssign(x.value +! n.offset, value.value, value.rawType)
413408
else:
414409
raise newException(ValueError, "invalid field name: " & fieldName)
415410

@@ -422,7 +417,7 @@ proc `[]`*(x: Any, fieldName: string): Any =
422417
assert x.rawType.kind in {tyTuple, tyObject}
423418
let n = getFieldNode(x.value, t.node, fieldName)
424419
if n != nil:
425-
result = Any(value: x.value +!! n.offset)
420+
result = Any(value: x.value +! n.offset)
426421
result.rawType = n.typ
427422
elif x.rawType.kind == tyObject and x.rawType.base != nil:
428423
return `[]`(newAny(x.value, x.rawType.base), fieldName)

lib/std/private/dragonbox.nim

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,15 +1043,6 @@ proc toDecimal64*(ieeeSignificand: uint64; ieeeExponent: uint64): FloatingDecima
10431043
# ToChars
10441044
# ==================================================================================================
10451045

1046-
when false:
1047-
template `+!`(x: cstring; offset: int): cstring = cast[cstring](cast[uint](x) + uint(offset))
1048-
1049-
template dec(x: cstring; offset=1) = x = cast[cstring](cast[uint](x) - uint(offset))
1050-
template inc(x: cstring; offset=1) = x = cast[cstring](cast[uint](x) + uint(offset))
1051-
1052-
proc memset(x: cstring; ch: char; L: int) {.importc, nodecl.}
1053-
proc memmove(a, b: cstring; L: int) {.importc, nodecl.}
1054-
10551046
proc utoa8DigitsSkipTrailingZeros*(buf: var openArray[char]; pos: int; digits: uint32): int {.inline.} =
10561047
dragonbox_Assert(digits >= 1)
10571048
dragonbox_Assert(digits <= 99999999'u32)

lib/system.nim

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,12 +1132,7 @@ import std/private/since
11321132
import system/ctypes
11331133
export ctypes
11341134

1135-
proc align(address, alignment: int): int =
1136-
if alignment == 0: # Actually, this is illegal. This branch exists to actively
1137-
# hide problems.
1138-
result = address
1139-
else:
1140-
result = (address + (alignment - 1)) and not (alignment - 1)
1135+
include system/ptrarith
11411136

11421137
include system/rawquits
11431138
when defined(genode):

lib/system/arc.nim

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,9 @@ when defined(gcAtomicArc) and hasThreadSupport:
8383
atomicLoadN(x.rc.addr, ATOMIC_ACQUIRE) shr rcShift
8484
else:
8585
template decrement(cell: Cell): untyped =
86-
dec(cell.rc, rcIncrement)
86+
cell.rc = cell.rc -% rcIncrement
8787
template increment(cell: Cell): untyped =
88-
inc(cell.rc, rcIncrement)
88+
cell.rc = cell.rc +% rcIncrement
8989
template count(x: Cell): untyped =
9090
x.rc shr rcShift
9191

@@ -94,7 +94,7 @@ when not defined(nimHasQuirky):
9494

9595
proc nimNewObj(size, alignment: int): pointer {.compilerRtl.} =
9696
let hdrSize = align(sizeof(RefHeader), alignment)
97-
let s = size + hdrSize
97+
let s = size +% hdrSize
9898
when defined(nimscript):
9999
discard
100100
else:

lib/system/cellseqs_v1.nim

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ proc contains(s: CellSeq, c: PCell): bool {.inline.} =
2222
return false
2323

2424
proc resize(s: var CellSeq) =
25-
s.cap = s.cap div 2 + s.cap
26-
let d = cast[PCellArray](alloc(s.cap * sizeof(PCell)))
27-
copyMem(d, s.d, s.len * sizeof(PCell))
25+
s.cap = s.cap div 2 +% s.cap
26+
let d = cast[PCellArray](alloc(cast[Natural](s.cap *% sizeof(PCell))))
27+
copyMem(d, s.d, s.len *% sizeof(PCell))
2828
dealloc(s.d)
2929
s.d = d
3030

@@ -37,7 +37,7 @@ proc add(s: var CellSeq, c: PCell) {.inline.} =
3737
proc init(s: var CellSeq, cap: int = 1024) =
3838
s.len = 0
3939
s.cap = cap
40-
s.d = cast[PCellArray](alloc0(cap * sizeof(PCell)))
40+
s.d = cast[PCellArray](alloc0(cast[Natural](cap *% sizeof(PCell))))
4141

4242
proc deinit(s: var CellSeq) =
4343
dealloc(s.d)

lib/system/cellseqs_v2.nim

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,26 @@ type
1717
d: CellArray[T]
1818

1919
proc resize[T](s: var CellSeq[T]) =
20-
s.cap = s.cap div 2 + s.cap
21-
var newSize = s.cap * sizeof(CellTuple[T])
20+
s.cap = s.cap div 2 +% s.cap
21+
let newSize = s.cap *% sizeof(CellTuple[T])
2222
when compileOption("threads"):
23-
s.d = cast[CellArray[T]](reallocShared(s.d, newSize))
23+
s.d = cast[CellArray[T]](reallocShared(s.d, cast[Natural](newSize)))
2424
else:
25-
s.d = cast[CellArray[T]](realloc(s.d, newSize))
25+
s.d = cast[CellArray[T]](realloc(s.d, cast[Natural](newSize)))
2626

2727
proc add[T](s: var CellSeq[T], c: T, t: PNimTypeV2) {.inline.} =
2828
if s.len >= s.cap:
2929
s.resize()
3030
s.d[s.len] = (c, t)
31-
inc(s.len)
31+
s.len = s.len +% 1
3232

3333
proc init[T](s: var CellSeq[T], cap: int = 1024) =
3434
s.len = 0
3535
s.cap = cap
3636
when compileOption("threads"):
37-
s.d = cast[CellArray[T]](allocShared(uint(s.cap * sizeof(CellTuple[T]))))
37+
s.d = cast[CellArray[T]](allocShared(cast[Natural](s.cap *% sizeof(CellTuple[T]))))
3838
else:
39-
s.d = cast[CellArray[T]](alloc(s.cap * sizeof(CellTuple[T])))
39+
s.d = cast[CellArray[T]](alloc(cast[Natural](s.cap *% sizeof(CellTuple[T]))))
4040

4141
proc deinit[T](s: var CellSeq[T]) =
4242
if s.d != nil:
@@ -49,5 +49,6 @@ proc deinit[T](s: var CellSeq[T]) =
4949
s.cap = 0
5050

5151
proc pop[T](s: var CellSeq[T]): (T, PNimTypeV2) =
52-
result = s.d[s.len-1]
53-
dec s.len
52+
let last = s.len -% 1
53+
s.len = last
54+
s.d[last]

lib/system/channels_builtin.nim

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,6 @@ proc deinitRawChannel(p: pointer) =
180180
deinitSysCond(c.cond)
181181

182182
when not usesDestructors:
183-
184183
proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
185184
mode: LoadStoreMode) {.benign.}
186185

@@ -203,9 +202,6 @@ when not usesDestructors:
203202

204203
proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
205204
mode: LoadStoreMode) =
206-
template `+!`(p: pointer; x: int): pointer =
207-
cast[pointer](cast[int](p) +% x)
208-
209205
var
210206
d = cast[int](dest)
211207
s = cast[int](src)

lib/system/gc.nim

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,11 +173,11 @@ proc addZCT(s: var CellSeq, c: PCell) {.noinline.} =
173173

174174
proc cellToUsr(cell: PCell): pointer {.inline.} =
175175
# convert object (=pointer to refcount) to pointer to userdata
176-
result = cast[pointer](cast[int](cell)+%ByteAddress(sizeof(Cell)))
176+
cell +! sizeof(Cell)
177177

178178
proc usrToCell(usr: pointer): PCell {.inline.} =
179179
# convert pointer to userdata to object (=pointer to refcount)
180-
result = cast[PCell](cast[int](usr)-%ByteAddress(sizeof(Cell)))
180+
cast[PCell](usr -! sizeof(Cell))
181181

182182
proc extGetCellType(c: pointer): PNimType {.compilerproc.} =
183183
# used for code generation concerning debugging

lib/system/gc_ms.nim

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,11 @@ template gcAssert(cond: bool, msg: string) =
9494

9595
proc cellToUsr(cell: PCell): pointer {.inline.} =
9696
# convert object (=pointer to refcount) to pointer to userdata
97-
result = cast[pointer](cast[int](cell)+%ByteAddress(sizeof(Cell)))
97+
cell +! sizeof(Cell)
9898

9999
proc usrToCell(usr: pointer): PCell {.inline.} =
100100
# convert pointer to userdata to object (=pointer to refcount)
101-
result = cast[PCell](cast[int](usr)-%ByteAddress(sizeof(Cell)))
101+
cast[PCell](usr -! sizeof(Cell))
102102

103103
proc extGetCellType(c: pointer): PNimType {.compilerproc.} =
104104
# used for code generation concerning debugging

lib/system/gc_regions.nim

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -101,16 +101,10 @@ template withRegion*(r: var MemRegion; body: untyped) =
101101
tlRegion = oldRegion
102102

103103
template inc(p: pointer, s: int) =
104-
p = cast[pointer](cast[int](p) +% s)
104+
p = p +! s
105105

106106
template dec(p: pointer, s: int) =
107-
p = cast[pointer](cast[int](p) -% s)
108-
109-
template `+!`(p: pointer, s: int): pointer =
110-
cast[pointer](cast[int](p) +% s)
111-
112-
template `-!`(p: pointer, s: int): pointer =
113-
cast[pointer](cast[int](p) -% s)
107+
p = p -! s
114108

115109
const nimMinHeapPages {.intdefine.} = 4
116110

0 commit comments

Comments
 (0)