Skip to content

Commit

Permalink
Fixed crash when marshalling NimPyObject to py. Refs #211.
Browse files Browse the repository at this point in the history
  • Loading branch information
yglukhov committed Jun 11, 2021
1 parent 3f7ee1c commit 4d117db
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 8 deletions.
35 changes: 27 additions & 8 deletions nimpy.nim
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ type
methods: seq[PyMethodDef]
members: seq[PyMemberDef]
origSize: int
pPyType: ptr PyTypeObject

PyIterRef = ref object
iter: iterator(): PPyObject
Expand Down Expand Up @@ -175,13 +176,29 @@ proc registerIterator(name, doc: cstring, newFunc: Newfunc) =
assert(not curModuleDef.isNil)
curModuleDef[].iterators.add(PyIteratorDesc(name: name, doc: doc, newFunc: newFunc))

proc pyNimObjectToPyObject(o: PyNimObject): PPyObject {.inline.} =
cast[PPyObject](addr o.py_object)
proc ppType(T: typedesc): ptr PyTypeObject =
var p {.global.}: PyTypeObject
addr p

proc newNimObjToPyObj(typ: PyTypeObject, o: PyNimObject): PPyObject =
GC_ref(o)
proc initPyNimObjectWithPyType(o: PyNimObject, typ: PyTypeObject) =
o.py_object.ob_type = typ
assert(o.py_object.ob_type != nil)
o.py_object.ob_refcnt = 1
GC_ref(o)

proc pyNimObjectToPyObject[T: PyNimObject](o: T): PPyObject {.inline.} =
cast[PPyObject](addr o.py_object)

proc marshalPyNimObjectToPy[T: PyNimObject](o: T): PPyObject {.inline.} =
if o.py_object.ob_type.isNil:
let pTyp = ppType(T)
assert(pTyp != nil)
initPyNimObjectWithPyType(o, pTyp[])
GC_ref(o)
pyNimObjectToPyObject(o)

proc newNimObjToPyObj(typ: PyTypeObject, o: PyNimObject): PPyObject =
initPyNimObjectWithPyType(o, typ)
pyNimObjectToPyObject(o)

proc newPyNimObject[T](typ: PyTypeObject, args, kwds: PPyObject): PPyObject {.cdecl.} =
Expand All @@ -195,7 +212,7 @@ proc getTypeIdxInModule(T: typedesc): int {.compileTime.} =
proc addTypedefToModuleDef(md: ptr PyModuleDesc, T: typedesc, idx: int) =
assert(md.types.len == idx)
var v: T
md.types.add(PyTypeDesc(name: $T, newFunc: newPyNimObject[T], origSize: sizeof(v[])))
md.types.add(PyTypeDesc(name: $T, newFunc: newPyNimObject[T], origSize: sizeof(v[]), pPyType: ppType(T)))

template registerTypeMethod(T: typedesc, name, doc: cstring, f: PyCFunctionWithKeywords) =
assert(not curModuleDef.isNil)
Expand Down Expand Up @@ -247,7 +264,7 @@ proc updateStackBottom() {.inline.} =
proc pythonException(e: ref Exception): PPyObject =
let err = pyLib.PyErr_NewException("nimpy" & "." & $(e.name), pyLib.NimPyException, nil)
decRef err
pyLib.PyErr_SetString(err, "Unexpected error encountered: " & getCurrentExceptionMsg())
pyLib.PyErr_SetString(err, "Unexpected error encountered: " & e.msg)

proc iterNext(i: PPyObject): PPyObject {.cdecl.} =
updateStackBottom()
Expand All @@ -273,10 +290,12 @@ proc iterDescrGet(a, b, c: PPyObject): PPyObject {.cdecl.} =
proc typDescrGet(a, b, c: PPyObject): PPyObject {.cdecl.} =
strToPyObject("nim type")

proc initModuleTypes[PyTypeObj](p: PPyObject, m: PyModuleDesc) =
proc initModuleTypes[PyTypeObj](p: PPyObject, m: var PyModuleDesc) =
for i in 0 ..< m.types.len:
let typ = pyAlloc(sizeof(PyTypeObj))
let ty = typ.to(PyTypeObj)
assert(m.types[i].pPyType != nil)
m.types[i].pPyType[] = ty
ty.tp_name = m.types[i].fullName

# Nim objects have an m_type* in front, we're stripping that away for python,
Expand Down Expand Up @@ -727,7 +746,7 @@ proc nimValueToPy[T](v: T): PPyObject {.inline.} =
if v.isNil:
newPyNone()
else:
pyNimObjectToPyObject(v)
marshalPyNimObjectToPy(v)
elif T is ref:
if v.isNil:
newPyNone()
Expand Down
3 changes: 3 additions & 0 deletions tests/nimfrompy.nim
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ iterator testIterator(s: string): int {.exportpy.} =
type TestType = ref object of PyNimObjectExperimental
myField: string

proc newTestType(arg: string): TestType {.exportpy.} =
TestType(myField: arg)

proc setMyField(self: TestType, value: string) {.exportpy.} =
self.myField = value

Expand Down
1 change: 1 addition & 0 deletions tests/tnimfrompy.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
assert(att.getMyField() == 5)
att.setMyFieldFromTt(tt)
assert(att.getMyField() == 1234)
assert(s.newTestType("hi").getMyField() == "hi")

try:
att.setMyFieldFromTt(123)
Expand Down

0 comments on commit 4d117db

Please sign in to comment.