Skip to content

Commit 1502bd0

Browse files
committed
disallow pointer_from_objref on immutable values. fixes #15857
1 parent 1750a83 commit 1502bd0

File tree

6 files changed

+36
-17
lines changed

6 files changed

+36
-17
lines changed

base/pointer.jl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,15 @@ unsafe_pointer_to_objref(x::Ptr) = ccall(:jl_value_ptr, Any, (Ptr{Cvoid},), x)
133133
Get the memory address of a Julia object as a `Ptr`. The existence of the resulting `Ptr`
134134
will not protect the object from garbage collection, so you must ensure that the object
135135
remains referenced for the whole time that the `Ptr` will be used.
136+
137+
This function may not be called on immutable objects, since they do not have
138+
stable memory addresses.
136139
"""
137-
pointer_from_objref(@nospecialize(x)) = ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), x)
140+
function pointer_from_objref(@nospecialize(x))
141+
@_inline_meta
142+
typeof(x).mutable || error("pointer_from_objref cannot be used on immutable objects")
143+
ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), x)
144+
end
138145

139146
eltype(::Type{Ptr{T}}) where {T} = T
140147

base/refpointer.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ Ref(x::Ptr{T}, i::Integer) where {T} = x + (i - 1) * Core.sizeof(T)
6161
function unsafe_convert(P::Type{Ptr{T}}, b::RefValue{T}) where T
6262
if isbits(T) || isbitsunion(T)
6363
return convert(P, pointer_from_objref(b))
64-
elseif _isleaftype(T)
64+
elseif _isleaftype(T) && T.mutable
6565
return convert(P, pointer_from_objref(b.x))
6666
else
6767
# If the slot is not leaf type, it could be either isbits or not.

base/serialize.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ const ser_version = 7 # do not make changes without bumping the version #!
7979
const NTAGS = length(TAGS)
8080

8181
function sertag(@nospecialize(v))
82-
ptr = pointer_from_objref(v)
82+
# NOTE: we use jl_value_ptr directly since we know at least one of the arguments
83+
# in the comparison below is a singleton.
84+
ptr = ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), v)
8385
ptags = convert(Ptr{Ptr{Cvoid}}, pointer(TAGS))
8486
# note: constant ints & reserved slots never returned here
8587
@inbounds for i in 1:(NTAGS-(n_reserved_slots+2*n_int_literals))

base/show.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,12 @@ function show_default(io::IO, @nospecialize(x))
159159
end
160160
else
161161
print(io, "0x")
162-
p = data_pointer_from_objref(x)
163-
for i in (nb - 1):-1:0
164-
print(io, hex(unsafe_load(convert(Ptr{UInt8}, p + i)), 2))
162+
r = Ref(x)
163+
@gc_preserve r begin
164+
p = unsafe_convert(Ptr{Cvoid}, r)
165+
for i in (nb - 1):-1:0
166+
print(io, hex(unsafe_load(convert(Ptr{UInt8}, p + i)), 2))
167+
end
165168
end
166169
end
167170
print(io,')')

base/summarysize.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ end
6565
(ss::SummarySize)(@nospecialize obj) = _summarysize(ss, obj)
6666
# define the general case separately to make sure it is not specialized for every type
6767
@noinline function _summarysize(ss::SummarySize, @nospecialize obj)
68-
key = pointer_from_objref(obj)
68+
# NOTE: this attempts to discover multiple copies of the same immutable value,
69+
# and so is somewhat approximate.
70+
key = ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), obj)
6971
haskey(ss.seen, key) ? (return 0) : (ss.seen[key] = true)
7072
if _nfields(obj) > 0
7173
push!(ss.frontier_x, obj)

test/core.jl

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,7 +1164,10 @@ end
11641164

11651165
@test unsafe_pointer_to_objref(ccall(:jl_call1, Ptr{Cvoid}, (Any,Any),
11661166
x -> x+1, 314158)) == 314159
1167-
@test unsafe_pointer_to_objref(pointer_from_objref(ℯ+pi)) ==+pi
1167+
let x = [1,2,3]
1168+
@test unsafe_pointer_to_objref(pointer_from_objref(x)) == x
1169+
@test unsafe_pointer_to_objref(pointer_from_objref(x)) === x
1170+
end
11681171

11691172
let
11701173
local a, aa
@@ -3467,11 +3470,12 @@ end
34673470
struct HasHasPadding
34683471
x::HasPadding
34693472
end
3470-
hashaspadding = HasHasPadding(HasPadding(true,1))
3471-
hashaspadding2 = HasHasPadding(HasPadding(true,1))
3472-
unsafe_store!(convert(Ptr{UInt8},pointer_from_objref(hashaspadding)), 0x12, 2)
3473-
unsafe_store!(convert(Ptr{UInt8},pointer_from_objref(hashaspadding2)), 0x21, 2)
3474-
@test object_id(hashaspadding) == object_id(hashaspadding2)
3473+
let hashaspadding = Ref(HasHasPadding(HasPadding(true,1))),
3474+
hashaspadding2 = Ref(HasHasPadding(HasPadding(true,1)))
3475+
unsafe_store!(convert(Ptr{UInt8},pointer_from_objref(hashaspadding)), 0x12, 2)
3476+
unsafe_store!(convert(Ptr{UInt8},pointer_from_objref(hashaspadding2)), 0x21, 2)
3477+
@test object_id(hashaspadding[]) == object_id(hashaspadding2[])
3478+
end
34753479

34763480
# issue #12517
34773481
let x = (1,2)
@@ -5638,10 +5642,11 @@ let
56385642
@eval @noinline constant23367(a, b) = (a ? b : $b)
56395643
b2 = Ref(b)[] # copy b via field assignment
56405644
b3 = B23367[b][1] # copy b via array assignment
5641-
@test pointer_from_objref(b) == pointer_from_objref(b)
5642-
@test pointer_from_objref(b) != pointer_from_objref(b2)
5643-
@test pointer_from_objref(b) != pointer_from_objref(b3)
5644-
@test pointer_from_objref(b2) != pointer_from_objref(b3)
5645+
addr(@nospecialize x) = ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), x)
5646+
@test addr(b) == addr(b)
5647+
@test addr(b) != addr(b2)
5648+
@test addr(b) != addr(b3)
5649+
@test addr(b2) != addr(b3)
56455650

56465651
@test b === b2 === b3
56475652
@test compare(b, b2)

0 commit comments

Comments
 (0)