summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorDominik Picheta <dominikpicheta@gmail.com>2017-11-30 18:43:34 +0000
committerDominik Picheta <dominikpicheta@googlemail.com>2017-11-30 21:34:30 +0000
commit2bb2e6975e397bef1b320cd5dbafb6b3338fdaf0 (patch)
tree79fbb17b92e547eae821be0a58d593336b47ee9a
parent8d6126237226a80ca4c78206c625009ce285c348 (diff)
downloadNim-2bb2e6975e397bef1b320cd5dbafb6b3338fdaf0.tar.gz
Fix infinite recursion when using json.to on ref with cycle.
-rw-r--r--lib/pure/json.nim10
-rw-r--r--tests/stdlib/tjsonmacro.nim4
-rw-r--r--tests/stdlib/tjsonmacro_reject2.nim21
3 files changed, 32 insertions, 3 deletions
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index 1d2f480c4..9e7510e45 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -1651,6 +1651,13 @@ import options
 proc workaroundMacroNone[T](): Option[T] =
   none(T)
 
+proc depth(n: NimNode, current = 0): int =
+  result = 1
+  for child in n:
+    let d = 1 + child.depth(current + 1)
+    if d > result:
+      result = d
+
 proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
   ## Accepts a type description, i.e. "ref Type", "seq[Type]", "Type" etc.
   ##
@@ -1660,6 +1667,9 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
   # echo("--createConsuctor-- \n", treeRepr(typeSym))
   # echo()
 
+  if depth(jsonNode) > 150:
+    error("The `to` macro does not support ref objects with cycles.", jsonNode)
+
   case typeSym.kind
   of nnkBracketExpr:
     var bracketName = ($typeSym[0]).normalize
diff --git a/tests/stdlib/tjsonmacro.nim b/tests/stdlib/tjsonmacro.nim
index 2baa7bed1..e2d8c27cf 100644
--- a/tests/stdlib/tjsonmacro.nim
+++ b/tests/stdlib/tjsonmacro.nim
@@ -354,6 +354,4 @@ when isMainModule:
     let dataDeser = to(dataParsed, Test)
     doAssert dataDeser.name == "FooBar"
     doAssert dataDeser.fallback.kind == JFloat
-    doAssert dataDeser.fallback.getFloat() == 56.42
-
-  # TODO: Cycles lead to infinite loops.
\ No newline at end of file
+    doAssert dataDeser.fallback.getFloat() == 56.42
\ No newline at end of file
diff --git a/tests/stdlib/tjsonmacro_reject2.nim b/tests/stdlib/tjsonmacro_reject2.nim
new file mode 100644
index 000000000..b01153553
--- /dev/null
+++ b/tests/stdlib/tjsonmacro_reject2.nim
@@ -0,0 +1,21 @@
+discard """
+  file: "tjsonmacro_reject2.nim"
+  line: 10
+  errormsg: "The `to` macro does not support ref objects with cycles."
+"""
+import json
+
+type
+  Misdirection = object
+    cycle: Cycle
+
+  Cycle = ref object
+    foo: string
+    cycle: Misdirection
+
+let data = """
+  {"cycle": null}
+"""
+
+let dataParsed = parseJson(data)
+let dataDeser = to(dataParsed, Cycle)
\ No newline at end of file