Skip to content

Commit

Permalink
fixes #20285; prevent oid time overflow at year 2038 (#20338)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
ringabout committed Sep 22, 2022
1 parent ae3dd75 commit db8a62d
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 26 deletions.
2 changes: 2 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@
- `strutils.find` now uses and defaults to `last = -1` for whole string searches,
making limiting it to just the first char (`last = 0`) valid.
- `random.rand` now works with `Ordinal`s.
- `std/oids` now uses `int64` to store time internally (before it was int32), the length of
the string form of `Oid` changes from 24 to 32.

[//]: # "Additions:"
- Added ISO 8601 week date utilities in `times`:
Expand Down
39 changes: 14 additions & 25 deletions lib/pure/oids.nim
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@

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

type
Oid* = object ## An OID.
time: int32
time: int64
fuzz: int32
count: int32

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

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

when T is string:
result.setLen N
result.setLen 32

var o = oid
var bytes = cast[cstring](addr(o))
var i = 0
while i < 12:
while i < 16:
let b = bytes[i].ord
result[2 * i] = hex[(b and 0xF0) shr 4]
result[2 * i + 1] = hex[b and 0xF]
inc(i)
when T is cstring:
result[N] = '\0'


proc `$`*(oid: Oid): string =
## Converts an OID to a string.
toStringImpl(result, oid)


let
t = getTime().toUnix.int32
t = getTime().toUnix

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


template genOid(result: var Oid, incr: var int, fuzz: int32) =
var time = getTime().toUnix.int32
var time = getTime().toUnix
var i = cast[int32](atomicInc(incr))

bigEndian32(addr result.time, addr(time))
bigEndian64(addr result.time, addr(time))
result.fuzz = fuzz
bigEndian32(addr result.count, addr(i))

proc genOid*(): Oid =
## Generates a new OID.
runnableExamples:
doAssert ($genOid()).len == 24
doAssert ($genOid()).len == 32
runnableExamples("-r:off"):
echo $genOid() # for example, "5fc7f546ddbbc84800006aaf"
echo $genOid() # for example, "00000000632c452db08c3d19ee9073e5"
genOid(result, incr, fuzz)

proc generatedTime*(oid: Oid): Time =
## Returns the generated timestamp of the OID.
var tmp: int32
var tmp: int64
var dummy = oid.time
bigEndian32(addr(tmp), addr(dummy))
bigEndian64(addr(tmp), addr(dummy))
result = fromUnix(tmp)
11 changes: 10 additions & 1 deletion tests/stdlib/toids.nim
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
discard """
matrix: "--mm:refc; --mm:orc"
"""

import std/oids


block: # genOid
let x = genOid()
doAssert ($x).len == 24
doAssert ($x).len == 32

block:
let x = genOid()
let y = parseOid(cstring($x))
doAssert x == y

0 comments on commit db8a62d

Please sign in to comment.