var p = cast[ptr fuck](L.newuserdata(sizeof(fuck).cint))
You allocate memory which is **not zeroed**. So its content may change
depending on what it was used for beforehand.
echo repr(p)
Now you want a representation of that memory. `p.ud` may have any value here.
If it is not `nil`, `repr` will try to resolve it to give you a representation
of its content. What happens is that after those `echo` s, `p.ud` contains some
garbage and `repr` tries to interpret that as a pointer and follows it,
resulting in a SIGSEGV.
So just move the `echo repr(p)` line after `p.ud = new(test2)`.