• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #37666

04 Nov 2023 02:27AM UTC coverage: 87.924% (+0.09%) from 87.831%
#37666

push

local

web-flow
Simplify, 16bit PDP-11 isn't going to be supported (#45763)

PDP_ENDIAN isn't used.

Co-authored-by: Viral B. Shah <ViralBShah@users.noreply.github.com>

74550 of 84789 relevant lines covered (87.92%)

15319904.67 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.21
/base/pointer.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
"""
4
    Ptr{T}
5

6
A memory address referring to data of type `T`.  However, there is no guarantee that the
7
memory is actually valid, or that it actually represents data of the specified type.
8
"""
9
Ptr
10

11
## converting pointers to an appropriate unsigned ##
12

13
"""
14
    C_NULL
15

16
The C null pointer constant, sometimes used when calling external code.
17
"""
18
const C_NULL = bitcast(Ptr{Cvoid}, 0)
19

20
# TODO: deprecate these conversions. C doesn't even allow them.
21

22
# pointer to integer
23
convert(::Type{T}, x::Ptr) where {T<:Integer} = T(UInt(x))::T
204,726✔
24

25
# integer to pointer
26
convert(::Type{Ptr{T}}, x::Union{Int,UInt}) where {T} = Ptr{T}(x)
1,376,096,045✔
27

28
# pointer to pointer
29
convert(::Type{Ptr{T}}, p::Ptr{T}) where {T} = p
182✔
30
convert(::Type{Ptr{T}}, p::Ptr) where {T} = bitcast(Ptr{T}, p)::Ptr{T}
1,246,125,976✔
31

32
# object to pointer (when used with ccall)
33

34
"""
35
    unsafe_convert(T, x)
36

37
Convert `x` to a C argument of type `T`
38
where the input `x` must be the return value of `cconvert(T, ...)`.
39

40
In cases where [`convert`](@ref) would need to take a Julia object
41
and turn it into a `Ptr`, this function should be used to define and perform
42
that conversion.
43

44
Be careful to ensure that a Julia reference to `x` exists as long as the result of this
45
function will be used. Accordingly, the argument `x` to this function should never be an
46
expression, only a variable name or field reference. For example, `x=a.b.c` is acceptable,
47
but `x=[a,b,c]` is not.
48

49
The `unsafe` prefix on this function indicates that using the result of this function after
50
the `x` argument to this function is no longer accessible to the program may cause undefined
51
behavior, including program corruption or segfaults, at any later time.
52

53
See also [`cconvert`](@ref)
54
"""
55
function unsafe_convert end
56

57
# convert strings to String etc. to pass as pointers
58
cconvert(::Type{Ptr{UInt8}}, s::AbstractString) = String(s)
60✔
59
cconvert(::Type{Ptr{Int8}}, s::AbstractString) = String(s)
2✔
60
unsafe_convert(::Type{Ptr{UInt8}}, x::Symbol) = ccall(:jl_symbol_name, Ptr{UInt8}, (Any,), x)
5,619,625✔
61
unsafe_convert(::Type{Ptr{Int8}}, x::Symbol) = ccall(:jl_symbol_name, Ptr{Int8}, (Any,), x)
68,017,858✔
62
unsafe_convert(::Type{Ptr{UInt8}}, s::String) = ccall(:jl_string_ptr, Ptr{UInt8}, (Any,), s)
729,003,401✔
63
unsafe_convert(::Type{Ptr{Int8}}, s::String) = ccall(:jl_string_ptr, Ptr{Int8}, (Any,), s)
3,035,530✔
64

65
cconvert(::Type{<:Ptr}, a::Array) = getfield(a, :ref)
192,782,966✔
66
unsafe_convert(::Type{Ptr{S}}, a::AbstractArray{T}) where {S,T} = convert(Ptr{S}, unsafe_convert(Ptr{T}, a))
×
67
unsafe_convert(::Type{Ptr{T}}, a::AbstractArray{T}) where {T} = error("conversion to pointer not defined for $(typeof(a))")
9✔
68
# TODO: add this deprecation to give a better error:
69
# cconvert(::Type{<:Ptr}, a::AbstractArray) = error("conversion to pointer not defined for $(typeof(a))")
70
# unsafe_convert(::Type{Ptr{T}}, a::AbstractArray{T}) where {T} = error("missing call to cconvert for call to unsafe_convert for AbstractArray")
71

72
cconvert(::Type{<:Ptr}, a::GenericMemory) = a
2,674,875✔
73
unsafe_convert(::Type{Ptr{Cvoid}}, a::GenericMemory{T}) where {T} = getfield(a, :ptr)
1,690,634✔
74
unsafe_convert(::Type{Ptr{T}}, a::GenericMemory) where {T} = convert(Ptr{T}, getfield(a, :ptr))
33,506,524✔
75

76
function unsafe_convert(::Type{Ptr{Cvoid}}, a::GenericMemoryRef{<:Any,T,Core.CPU}) where {T}
2,157,211✔
77
    mem = getfield(a, :mem)
1,844,286✔
78
    offset = getfield(a, :ptr_or_offset)
689,278,998✔
79
    MemT = typeof(mem)
1,844,286✔
80
    arrayelem = datatype_arrayelem(MemT)
1,844,286✔
81
    elsz = datatype_layoutsize(MemT)
1,844,286✔
82
    isboxed = 1; isunion = 2
3,688,572✔
83
    if arrayelem == isunion || elsz == 0
1,844,286✔
84
        offset = UInt(offset) * elsz
1,055,310✔
85
        offset += unsafe_convert(Ptr{Cvoid}, mem)
1,055,310✔
86
    end
87
    return offset
1,844,286✔
88
end
89
unsafe_convert(::Type{Ptr{T}}, a::GenericMemoryRef) where {T} = convert(Ptr{T}, unsafe_convert(Ptr{Cvoid}, a))
189,161,470✔
90

91
# unsafe pointer to array conversions
92
"""
93
    unsafe_wrap(Array, pointer::Ptr{T}, dims; own = false)
94

95
Wrap a Julia `Array` object around the data at the address given by `pointer`,
96
without making a copy.  The pointer element type `T` determines the array
97
element type. `dims` is either an integer (for a 1d array) or a tuple of the array dimensions.
98
`own` optionally specifies whether Julia should take ownership of the memory,
99
calling `free` on the pointer when the array is no longer referenced.
100

101
This function is labeled "unsafe" because it will crash if `pointer` is not
102
a valid memory address to data of the requested length. Unlike [`unsafe_load`](@ref)
103
and [`unsafe_store!`](@ref), the programmer is responsible also for ensuring that the
104
underlying data is not accessed through two arrays of different element type, similar
105
to the strict aliasing rule in C.
106
"""
107
function unsafe_wrap(::Union{Type{Array},Type{Array{T}},Type{Array{T,N}}},
8,844✔
108
                     p::Ptr{T}, dims::NTuple{N,Int}; own::Bool = false) where {T,N}
109
    ccall(:jl_ptr_to_array, Array{T,N}, (Any, Ptr{Cvoid}, Any, Int32),
4,422✔
110
          Array{T,N}, p, dims, own)
111
end
112
function unsafe_wrap(::Union{Type{Array},Type{Array{T}},Type{Array{T,1}}},
105,667✔
113
                     p::Ptr{T}, d::Integer; own::Bool = false) where {T}
114
    ccall(:jl_ptr_to_array_1d, Array{T,1},
53,258✔
115
          (Any, Ptr{Cvoid}, Csize_t, Cint), Array{T,1}, p, d, own)
116
end
117
function unsafe_wrap(::Union{Type{GenericMemory{kind,<:Any,Core.CPU}},Type{GenericMemory{kind,T,Core.CPU}}},
×
118
                     p::Ptr{T}, dims::Tuple{Int}; own::Bool = false) where {kind,T}
119
    ccall(:jl_ptr_to_genericmemory, Ref{GenericMemory{kind,T,Core.CPU}},
×
120
          (Any, Ptr{Cvoid}, Csize_t, Cint), GenericMemory{kind,T,Core.CPU}, p, dim[1], own)
121
end
122
function unsafe_wrap(::Union{Type{GenericMemory{kind,<:Any,Core.CPU}},Type{GenericMemory{kind,T,Core.CPU}}},
×
123
                     p::Ptr{T}, d::Integer; own::Bool = false) where {kind,T}
124
    ccall(:jl_ptr_to_genericmemory, Ref{GenericMemory{kind,T,Core.CPU}},
×
125
          (Any, Ptr{Cvoid}, Csize_t, Cint), GenericMemory{kind,T,Core.CPU}, p, d, own)
126
end
127
unsafe_wrap(Atype::Union{Type{Array},Type{Array{T}},Type{Array{T,N}},Type{GenericMemory{kind,<:Any,Core.CPU}},Type{GenericMemory{kind,T,Core.CPU}}} where {kind},
×
128
            p::Ptr{T}, dims::NTuple{N,<:Integer}; own::Bool = false) where {T,N} =
8,314✔
129
    unsafe_wrap(Atype, p, convert(Tuple{Vararg{Int}}, dims), own = own)
130

131

132
"""
133
    unsafe_load(p::Ptr{T}, i::Integer=1)
134
    unsafe_load(p::Ptr{T}, order::Symbol)
135
    unsafe_load(p::Ptr{T}, i::Integer, order::Symbol)
136

137
Load a value of type `T` from the address of the `i`th element (1-indexed) starting at `p`.
138
This is equivalent to the C expression `p[i-1]`. Optionally, an atomic memory ordering can
139
be provided.
140

141
The `unsafe` prefix on this function indicates that no validation is performed on the
142
pointer `p` to ensure that it is valid. Like C, the programmer is responsible for ensuring
143
that referenced memory is not freed or garbage collected while invoking this function.
144
Incorrect usage may segfault your program or return garbage answers. Unlike C, dereferencing
145
memory region allocated as different type may be valid provided that the types are compatible.
146

147
!!! compat "Julia 1.10"
148
     The `order` argument is available as of Julia 1.10.
149

150
See also: [`atomic`](@ref)
151
"""
152
unsafe_load(p::Ptr, i::Integer=1) = pointerref(p, Int(i), 1)
2,147,483,647✔
153
unsafe_load(p::Ptr, order::Symbol) = atomic_pointerref(p, order)
55✔
154
function unsafe_load(p::Ptr, i::Integer, order::Symbol)
×
155
    unsafe_load(p + (elsize(typeof(p)) * (Int(i) - 1)), order)
×
156
end
157

158
"""
159
    unsafe_store!(p::Ptr{T}, x, i::Integer=1)
160
    unsafe_store!(p::Ptr{T}, x, order::Symbol)
161
    unsafe_store!(p::Ptr{T}, x, i::Integer, order::Symbol)
162

163
Store a value of type `T` to the address of the `i`th element (1-indexed) starting at `p`.
164
This is equivalent to the C expression `p[i-1] = x`. Optionally, an atomic memory ordering
165
can be provided.
166

167
The `unsafe` prefix on this function indicates that no validation is performed on the
168
pointer `p` to ensure that it is valid. Like C, the programmer is responsible for ensuring
169
that referenced memory is not freed or garbage collected while invoking this function.
170
Incorrect usage may segfault your program. Unlike C, storing memory region allocated as
171
different type may be valid provided that that the types are compatible.
172

173
!!! compat "Julia 1.10"
174
     The `order` argument is available as of Julia 1.10.
175

176
See also: [`atomic`](@ref)
177
"""
178
unsafe_store!(p::Ptr{Any}, @nospecialize(x), i::Integer=1) = pointerset(p, x, Int(i), 1)
1✔
179
unsafe_store!(p::Ptr{T}, x, i::Integer=1) where {T} = pointerset(p, convert(T,x), Int(i), 1)
228,352,932✔
180
unsafe_store!(p::Ptr{T}, x, order::Symbol) where {T} = atomic_pointerset(p, x isa T ? x : convert(T,x), order)
13✔
181
function unsafe_store!(p::Ptr, x, i::Integer, order::Symbol)
×
182
    unsafe_store!(p + (elsize(typeof(p)) * (Int(i) - 1)), x, order)
×
183
end
184

185
"""
186
    unsafe_modify!(p::Ptr{T}, op, x, [order::Symbol]) -> Pair
187

188
These atomically perform the operations to get and set a memory address after applying
189
the function `op`. If supported by the hardware (for example, atomic increment), this may be
190
optimized to the appropriate hardware instruction, otherwise its execution will be
191
similar to:
192

193
    y = unsafe_load(p)
194
    z = op(y, x)
195
    unsafe_store!(p, z)
196
    return y => z
197

198
The `unsafe` prefix on this function indicates that no validation is performed on the
199
pointer `p` to ensure that it is valid. Like C, the programmer is responsible for ensuring
200
that referenced memory is not freed or garbage collected while invoking this function.
201
Incorrect usage may segfault your program.
202

203
!!! compat "Julia 1.10"
204
     This function requires at least Julia 1.10.
205

206
See also: [`modifyproperty!`](@ref Base.modifyproperty!), [`atomic`](@ref)
207
"""
208
function unsafe_modify!(p::Ptr, op, x, order::Symbol=:not_atomic)
30✔
209
    return atomic_pointermodify(p, op, x, order)
30✔
210
end
211

212
"""
213
    unsafe_replace!(p::Ptr{T}, expected, desired,
214
                   [success_order::Symbol[, fail_order::Symbol=success_order]]) -> (; old, success::Bool)
215

216
These atomically perform the operations to get and conditionally set a memory address to
217
a given value. If supported by the hardware, this may be optimized to the appropriate
218
hardware instruction, otherwise its execution will be similar to:
219

220
    y = unsafe_load(p, fail_order)
221
    ok = y === expected
222
    if ok
223
        unsafe_store!(p, desired, success_order)
224
    end
225
    return (; old = y, success = ok)
226

227
The `unsafe` prefix on this function indicates that no validation is performed on the
228
pointer `p` to ensure that it is valid. Like C, the programmer is responsible for ensuring
229
that referenced memory is not freed or garbage collected while invoking this function.
230
Incorrect usage may segfault your program.
231

232
!!! compat "Julia 1.10"
233
     This function requires at least Julia 1.10.
234

235
See also: [`replaceproperty!`](@ref Base.replaceproperty!), [`atomic`](@ref)
236
"""
237
function unsafe_replace!(p::Ptr{T}, expected, desired, success_order::Symbol=:not_atomic, fail_order::Symbol=success_order) where {T}
28✔
238
    @inline
28✔
239
    xT = desired isa T ? desired : convert(T, desired)
28✔
240
    return atomic_pointerreplace(p, expected, xT, success_order, fail_order)
28✔
241
end
242
function unsafe_replace!(p::Ptr{Any}, @nospecialize(expected), @nospecialize(desired), success_order::Symbol=:not_atomic, fail_order::Symbol=success_order)
5✔
243
    return atomic_pointerreplace(p, expected, desired, success_order, fail_order)
5✔
244
end
245

246
"""
247
    unsafe_swap!(p::Ptr{T}, x, [order::Symbol])
248

249
These atomically perform the operations to simultaneously get and set a memory address.
250
If supported by the hardware, this may be optimized to the appropriate hardware
251
instruction, otherwise its execution will be similar to:
252

253
    y = unsafe_load(p)
254
    unsafe_store!(p, x)
255
    return y
256

257
The `unsafe` prefix on this function indicates that no validation is performed on the
258
pointer `p` to ensure that it is valid. Like C, the programmer is responsible for ensuring
259
that referenced memory is not freed or garbage collected while invoking this function.
260
Incorrect usage may segfault your program.
261

262
!!! compat "Julia 1.10"
263
     This function requires at least Julia 1.10.
264

265
See also: [`swapproperty!`](@ref Base.swapproperty!), [`atomic`](@ref)
266
"""
267
function unsafe_swap!(p::Ptr{Any}, x, order::Symbol=:not_atomic)
2✔
268
    return atomic_pointerswap(p, x, order)
2✔
269
end
270
function unsafe_swap!(p::Ptr{T}, x, order::Symbol=:not_atomic) where {T}
11✔
271
    @inline
11✔
272
    xT = x isa T ? x : convert(T, x)
11✔
273
    return atomic_pointerswap(p, xT, order)
11✔
274
end
275

276
# convert a raw Ptr to an object reference, and vice-versa
277
"""
278
    unsafe_pointer_to_objref(p::Ptr)
279

280
Convert a `Ptr` to an object reference. Assumes the pointer refers to a valid heap-allocated
281
Julia object. If this is not the case, undefined behavior results, hence this function is
282
considered "unsafe" and should be used with care.
283

284
See also [`pointer_from_objref`](@ref).
285
"""
286
unsafe_pointer_to_objref(x::Ptr) = ccall(:jl_value_ptr, Any, (Ptr{Cvoid},), x)
1,381,554✔
287

288
"""
289
    pointer_from_objref(x)
290

291
Get the memory address of a Julia object as a `Ptr`. The existence of the resulting `Ptr`
292
will not protect the object from garbage collection, so you must ensure that the object
293
remains referenced for the whole time that the `Ptr` will be used.
294

295
This function may not be called on immutable objects, since they do not have
296
stable memory addresses.
297

298
See also [`unsafe_pointer_to_objref`](@ref).
299
"""
300
function pointer_from_objref(@nospecialize(x))
20,085,464✔
301
    @inline
20,084,521✔
302
    ismutable(x) || error("pointer_from_objref cannot be used on immutable objects")
20,085,625✔
303
    ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), x)
1,088,923,641✔
304
end
305

306
## limited pointer arithmetic & comparison ##
307

308
isequal(x::Ptr, y::Ptr) = (x === y)
1✔
309
isless(x::Ptr{T}, y::Ptr{T}) where {T} = x < y
1✔
310

311
==(x::Ptr, y::Ptr) = UInt(x) == UInt(y)
841,404,197✔
312
<(x::Ptr,  y::Ptr) = UInt(x) < UInt(y)
13,820,477✔
313
-(x::Ptr,  y::Ptr) = UInt(x) - UInt(y)
4,326,762✔
314

315
+(x::Ptr, y::Integer) = oftype(x, add_ptr(UInt(x), (y % UInt) % UInt))
858,394,504✔
316
-(x::Ptr, y::Integer) = oftype(x, sub_ptr(UInt(x), (y % UInt) % UInt))
517,888,298✔
317
+(x::Integer, y::Ptr) = y + x
1,055,311✔
318

319
unsigned(x::Ptr) = UInt(x)
×
320
signed(x::Ptr) = Int(x)
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc