Skip to content

Commit c6c19c1

Browse files
committed
Fix invalid pointer_to_objref call on immutable objects
Makes sure that the pointer lifetime is managed by a mutable object.
1 parent d5de0c5 commit c6c19c1

File tree

2 files changed

+17
-2
lines changed

2 files changed

+17
-2
lines changed

src/gc.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ end
2828

2929
# "embed" a reference to jo in po, using the weak-reference mechanism
3030
function pyembed(po::PyObject, jo::Any)
31+
# If there's a need to support immutable embedding,
32+
# the API needs to be changed to return the pointer.
33+
isimmutable(jo) && ArgumentError("pyembed: immutable argument now allowed")
3134
if weakref_callback_obj.o == C_NULL
3235
weakref_callback_obj.o = pyincref(pymethod(weakref_callback,
3336
"weakref_callback",

src/pytype.jl

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -472,9 +472,21 @@ function pyjlwrap_new(pyT::PyTypeObject, value::Any)
472472
# TODO change to `Ref{PyTypeObject}` when 0.6 is dropped.
473473
o = PyObject(@pycheckn ccall((@pysym :_PyObject_New),
474474
PyPtr, (Any,), pyT))
475-
pycall_gc[o.o] = value
476475
p = convert(Ptr{Ptr{Void}}, o.o)
477-
unsafe_store!(p, ccall(:jl_value_ptr, Ptr{Void}, (Any,), value), 3)
476+
if isimmutable(value)
477+
# It is undefined to call `pointer_from_objref` on immutable objects.
478+
# The compiler is free to return basically anything since the boxing is not
479+
# significant at all.
480+
# Below is a well defined way to get a pointer (`ptr`) and an object that defines
481+
# the lifetime of the pointer `ref`.
482+
ref = Ref{Any}(value)
483+
pycall_gc[o.o] = ref
484+
ptr = unsafe_load(Ptr{Ptr{Void}}(pointer_from_objref(ref)))
485+
else
486+
pycall_gc[o.o] = value
487+
ptr = pointer_from_objref(value)
488+
end
489+
unsafe_store!(p, ptr, 3)
478490
return o
479491
end
480492

0 commit comments

Comments
 (0)