Skip to content

Commit db8a62d

Browse files
authored
fixes #20285; prevent oid time overflow at year 2038 (#20338)
* Revert "fixes #20285; prevent oid time overflow at year 2038" This reverts commit dfcdb6e. * increase time to 64 bits and clean up * add testcase * inline consts * add a changelog * fixes #20285; prevent oid time overflow at year 2038
1 parent ae3dd75 commit db8a62d

File tree

3 files changed

+26
-26
lines changed

3 files changed

+26
-26
lines changed

changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@
6565
- `strutils.find` now uses and defaults to `last = -1` for whole string searches,
6666
making limiting it to just the first char (`last = 0`) valid.
6767
- `random.rand` now works with `Ordinal`s.
68+
- `std/oids` now uses `int64` to store time internally (before it was int32), the length of
69+
the string form of `Oid` changes from 24 to 32.
6870

6971
[//]: # "Additions:"
7072
- Added ISO 8601 week date utilities in `times`:

lib/pure/oids.nim

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@
99

1010
## Nim OID support. An OID is a global ID that consists of a timestamp,
1111
## a unique counter and a random value. This combination should suffice to
12-
## produce a globally distributed unique ID. This implementation was extracted
13-
## from the MongoDB interface and is thus binary compatible with a MongoDB OID.
12+
## produce a globally distributed unique ID.
1413
##
1514
## This implementation calls `initRand()` for the first call of
1615
## `genOid`.
@@ -20,7 +19,7 @@ from std/private/decode_helpers import handleHexChar
2019

2120
type
2221
Oid* = object ## An OID.
23-
time: int32
22+
time: int64
2423
fuzz: int32
2524
count: int32
2625

@@ -44,37 +43,27 @@ proc parseOid*(str: cstring): Oid =
4443
## Parses an OID.
4544
var bytes = cast[cstring](addr(result.time))
4645
var i = 0
47-
while i < 12:
46+
while i < 16:
4847
bytes[i] = chr((hexbyte(str[2 * i]) shl 4) or hexbyte(str[2 * i + 1]))
4948
inc(i)
5049

51-
template toStringImpl[T: string | cstring](result: var T, oid: Oid) =
52-
## Stringifies `oid`.
50+
proc `$`*(oid: Oid): string =
51+
## Converts an OID to a string.
5352
const hex = "0123456789abcdef"
54-
const N = 24
5553

56-
when T is string:
57-
result.setLen N
54+
result.setLen 32
5855

5956
var o = oid
6057
var bytes = cast[cstring](addr(o))
6158
var i = 0
62-
while i < 12:
59+
while i < 16:
6360
let b = bytes[i].ord
6461
result[2 * i] = hex[(b and 0xF0) shr 4]
6562
result[2 * i + 1] = hex[b and 0xF]
6663
inc(i)
67-
when T is cstring:
68-
result[N] = '\0'
69-
70-
71-
proc `$`*(oid: Oid): string =
72-
## Converts an OID to a string.
73-
toStringImpl(result, oid)
74-
7564

7665
let
77-
t = getTime().toUnix.int32
66+
t = getTime().toUnix
7867

7968
var
8069
seed = initRand(t)
@@ -84,24 +73,24 @@ let fuzz = cast[int32](seed.rand(high(int)))
8473

8574

8675
template genOid(result: var Oid, incr: var int, fuzz: int32) =
87-
var time = getTime().toUnix.int32
76+
var time = getTime().toUnix
8877
var i = cast[int32](atomicInc(incr))
8978

90-
bigEndian32(addr result.time, addr(time))
79+
bigEndian64(addr result.time, addr(time))
9180
result.fuzz = fuzz
9281
bigEndian32(addr result.count, addr(i))
9382

9483
proc genOid*(): Oid =
9584
## Generates a new OID.
9685
runnableExamples:
97-
doAssert ($genOid()).len == 24
86+
doAssert ($genOid()).len == 32
9887
runnableExamples("-r:off"):
99-
echo $genOid() # for example, "5fc7f546ddbbc84800006aaf"
88+
echo $genOid() # for example, "00000000632c452db08c3d19ee9073e5"
10089
genOid(result, incr, fuzz)
10190

10291
proc generatedTime*(oid: Oid): Time =
10392
## Returns the generated timestamp of the OID.
104-
var tmp: int32
93+
var tmp: int64
10594
var dummy = oid.time
106-
bigEndian32(addr(tmp), addr(dummy))
95+
bigEndian64(addr(tmp), addr(dummy))
10796
result = fromUnix(tmp)

tests/stdlib/toids.nim

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1+
discard """
2+
matrix: "--mm:refc; --mm:orc"
3+
"""
4+
15
import std/oids
26

37

48
block: # genOid
59
let x = genOid()
6-
doAssert ($x).len == 24
10+
doAssert ($x).len == 32
11+
12+
block:
13+
let x = genOid()
14+
let y = parseOid(cstring($x))
15+
doAssert x == y

0 commit comments

Comments
 (0)