Closed
Description
To set the stage, this works fine:
import std/isolation
type Z = ref object
i: int
type A = object
z: Z
func z_to_a(z: Z): A =
result = A(z: z)
let z = Z(i: 3)
let a = isolate(z_to_a(z)) # Error: expression cannot be isolated: z_to_a(z)
Example
On the other hand, these two cases are unsafe:
Returning a subgraph:
import std/isolation
type Z = ref object
i: int
type A = object
z: Z
func a_to_z(a: A): Z =
result = a.z
let a = A(z: Z(i: 3))
let z = isolate(a_to_z(a))
echo repr(z) # [value = ref 0x7fca2c6d9050 --> [i = 3]]
inc a.z.i
echo repr(z) # [value = ref 0x7fca2c6d9050 --> [i = 4]]
Overlapping subgraphs:
import std/isolation
type Z = ref object
i: int
type A = object
z: Z
type B = object
z: Z
func a_to_b(a: A): B =
result = B(z: a.z)
let a = A(z: Z(i: 3))
let b = isolate(a_to_b(a))
echo repr(b) # [value = [z = ref 0x7f8650b6b050 --> [i = 3]]]
inc a.z.i
echo repr(b) # [value = [z = ref 0x7f8650b6b050 --> [i = 4]]]
Current Output
Compiles fine and I expect would produce refcount corruption in a multi threaded environment, exposing the user to memory related crashes.
Expected Output
Refuse to compile with cannot be isolated
.
Possible Solution
I think isolate
should rule out any cases where the input & output types share a common ref
subgraph.
Ideally an isolate_copy
function would always succeed and create fresh copies of every ref
whose count is > 1. In fact maybe the current function should be isolate_nocopy
and the default behaviour should just be to copy the refs when the RC is > 1?
Additional Information
Mentionned in nim-lang/RFCs#244 (comment)
$ nim -v
Nim Compiler Version 1.4.8 [Linux: amd64]