Add 'checkedEnumAssign' for validating tainted enum inputs

This commit is contained in:
Zahary Karadjov 2020-06-22 18:35:42 +03:00 committed by zah
parent 11aeb996ab
commit 152eb1b58c
2 changed files with 107 additions and 2 deletions

View File

@ -1,3 +1,6 @@
import
macros
template init*(lvalue: var auto) =
mixin init
lvalue = init(type(lvalue))
@ -36,9 +39,9 @@ func declval*(T: type): T {.compileTime.} =
## ```
##
## Please note that `declval` has two advantages over `default`:
##
##
## 1. It can return expressions with proper `var` or `lent` types.
##
##
## 2. It will work for types that lack a valid default value due
## to `not nil` or `requiresInit` requirements.
##
@ -64,3 +67,43 @@ proc baseType*(obj: RootObj): cstring =
proc baseType*(obj: ref RootObj): cstring =
obj[].baseType
when false:
# TODO: Implementing this doesn't seem possible at the moment.
#
# When given enum like:
#
# type WithoutHoles2 = enum
# A2 = 2, B2 = 3, C2 = 4
#
# ...the code below will print:
#
# EnumTy
# Empty
# Sym "A2"
# Sym "B2"
# Sym "C2"
#
macro hasHoles*(T: type[enum]): bool =
let t = getType(T)[1]
echo t.treeRepr
return newLit(true)
func checkedEnumAssign*[E: enum, I: SomeInteger](res: var E, value: I): bool =
## This function can be used to safely assign a tainted integer value (coming
## from untrusted source) to an enum variable. The function will return `true`
## if the integer value is within the acceped values of the enum and `false`
## otherwise.
# TODO: Enums with holes are not supported yet
# static: doAssert(not hasHoles(E))
when I is SomeSignedInt or low(E).int > 0:
if value < I(low(E)):
return false
if value > I(high(E)):
return false
res = E value
return true

View File

@ -70,3 +70,65 @@ suite "Objects":
T6 is DistinctBar
T6 isnot Bar
when false:
# TODO: Not possible yet (see objects.nim)
test "hasHoles":
type
WithoutHoles = enum
A1, B1, C1
WithoutHoles2 = enum
A2 = 2, B2 = 3, C2 = 4
WithHoles = enum
A3, B3 = 2, C3
check:
hasHoles(WithoutHoles2) == false
hasHoles(WithoutHoles) == false
hasHoles(WithHoles) == true
test "checkedEnumAssign":
type
SomeEnum = enum
A1, B1, C1
AnotherEnum = enum
A2 = 2, B2, C2
var
e1 = A1
e2 = A2
check:
checkedEnumAssign(e1, 2)
e1 == C1
check:
not checkedEnumAssign(e1, 5)
e1 == C1
check:
checkedEnumAssign(e1, 0)
e1 == A1
check:
not checkedEnumAssign(e1, -1)
e1 == A1
check:
checkedEnumAssign(e2, 2)
e2 == A2
check:
not checkedEnumAssign(e2, 5)
e2 == A2
check:
checkedEnumAssign(e2, 4)
e2 == C2
check:
not checkedEnumAssign(e2, 1)
e2 == C2