Skip to content

Commit 8bd3556

Browse files
authored
fix: make sure PyCFunction_NewEx arguments live long enough (#60)
1 parent f1af5b1 commit 8bd3556

File tree

1 file changed

+14
-4
lines changed

1 file changed

+14
-4
lines changed

src/python.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,11 @@ export class Callback {
190190
* C PyObject.
191191
*/
192192
export class PyObject {
193+
/**
194+
* A Python callabale object as Uint8Array
195+
* This is used with `PyCFunction_NewEx` in order to extend its liftime and not allow v8 to release it before its actually used
196+
*/
197+
#pyMethodDef?: Uint8Array;
193198
constructor(public handle: Deno.PointerValue) {}
194199

195200
/**
@@ -447,8 +452,8 @@ export class PyObject {
447452
}
448453
return new PyObject(list);
449454
} else if (v instanceof Callback) {
450-
const struct = new Uint8Array(8 + 8 + 4 + 8);
451-
const view = new DataView(struct.buffer);
455+
const pyMethodDef = new Uint8Array(8 + 8 + 4 + 8);
456+
const view = new DataView(pyMethodDef.buffer);
452457
const LE =
453458
new Uint8Array(new Uint32Array([0x12345678]).buffer)[0] !== 0x7;
454459
const nameBuf = new TextEncoder().encode(
@@ -471,11 +476,16 @@ export class PyObject {
471476
LE,
472477
);
473478
const fn = py.PyCFunction_NewEx(
474-
struct,
479+
pyMethodDef,
475480
PyObject.from(null).handle,
476481
null,
477482
);
478-
return new PyObject(fn);
483+
484+
// NOTE: we need to extend `pyMethodDef` lifetime
485+
// Otherwise V8 can release it before the callback is called
486+
const pyObject = new PyObject(fn);
487+
pyObject.#pyMethodDef = pyMethodDef;
488+
return pyObject;
479489
} else if (v instanceof PyObject) {
480490
return v;
481491
} else if (v instanceof Set) {

0 commit comments

Comments
 (0)