Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with generic copyto! #45125

Open
bkamins opened this issue Apr 30, 2022 · 12 comments
Open

Problem with generic copyto! #45125

bkamins opened this issue Apr 30, 2022 · 12 comments

Comments

@bkamins
Copy link
Member

bkamins commented Apr 30, 2022

The issue is:

julia> x = view(["A", "B"], 1:2)
2-element view(::Vector{String}, 1:2) with eltype String:
 "A"
 "B"

julia> y = Vector{String}(undef, 2)
2-element Vector{String}:
 #undef
 #undef

julia> copyto!(x, y)
ERROR: UndefRefError: access to undefined reference
Stacktrace:
 [1] getindex
   @ .\array.jl:861 [inlined]
 [2] copyto_unaliased!(deststyle::IndexLinear, dest::SubArray{String, 1, Vector{String}, Tuple{UnitRange{Int64}}, true}, srcstyle::IndexLinear, src::Vector{String})
   @ Base .\abstractarray.jl:1018
 [3] copyto!(dest::SubArray{String, 1, Vector{String}, Tuple{UnitRange{Int64}}, true}, src::Vector{String})
   @ Base .\abstractarray.jl:998
 [4] top-level scope
   @ REPL[19]:1

The reason is

dest[i + Δi] = src[i]
(and similar operation below this one) assuming that all elements of source array are defined.

If I understand the intention correctly this is a bug in copyto! as e.g.

julia> x = ["A", "b"]
2-element Vector{String}:
 "A"
 "b"

julia> y = Vector{String}(undef, 2)
2-element Vector{String}:
 #undef
 #undef

julia> copyto!(x, y)
2-element Vector{String}:
 #undef
 #undef

julia> x
2-element Vector{String}:
 #undef
 #undef

works.

@mcabbott
Copy link
Contributor

mcabbott commented May 1, 2022

Since iterate(y) fails, I am surprised that copyto!(x, y) works. It could be that this success is the unintended behaviour, as the lower-level unsafe function doesn't object.

@bkamins
Copy link
Member Author

bkamins commented May 1, 2022

That is why I opened it as an issue not a PR.

However, as you will see in this PR in generic code users could assume that copyto! will work always if types of x and y match (i.e. support the operation).

@KristofferC
Copy link
Member

KristofferC commented May 2, 2022

I would say that

julia> copyto!(x, y)
2-element Vector{String}:
 #undef
 #undef

is the bug. There is (almost) never a case where you can undefine values that have once been defined.

@jakobnissen
Copy link
Contributor

jakobnissen commented May 2, 2022

Since #undef elements is implemented in Julia using null pointers, it will probably be very fast to check for the presence of these in the source array - especially considering that it will then be in cache for the upcoming copy operation.

Perhaps a check could be added in the copy! implementation? E.g. it could be done in the following way to add negligible overhead:

function copy_checked(dst::Array{T}, src::Array{T}) where T
    GC.@preserve src dst begin
        sptr = Ptr{UInt}(pointer(src))
        dptr = Ptr{UInt}(pointer(dst))
        uninit = false
        for i in eachindex(src)
            p = unsafe_load(sptr, i)
            uninit |= iszero(p)
            unsafe_store!(dptr, p, i)
        end
    end
    uninit && error()
    dst
end

@quinnj
Copy link
Member

quinnj commented May 4, 2022

Related: #36564

@bkamins
Copy link
Member Author

bkamins commented Sep 26, 2022

bump - for my purposes I am OK with any behavior as long as it is clear what contract copyto! has with respect to #undef.

@nalimilan nalimilan added the triage This should be discussed on a triage call label Sep 26, 2022
@JeffBezanson
Copy link
Member

I believe this was added for a use case in the compiler. I would prefer the compiler to use some different approach if possible, and roll this back, since it is unnerving for it to be inconsistent like this.

@vtjnash vtjnash removed the triage This should be discussed on a triage call label Sep 29, 2022
@jishnub
Copy link
Contributor

jishnub commented Apr 11, 2024

The OP now works on Julia v1.11.0-beta2:

julia> x = view(["A", "B"], 1:2)
2-element view(::Vector{String}, 1:2) with eltype String:
 "A"
 "B"

julia> y = Vector{String}(undef, 2)
2-element Vector{String}:
 #undef
 #undef

julia> copyto!(x, y)
2-element view(::Vector{String}, 1:2) with eltype String:
 #undef
 #undef

@adienes
Copy link
Contributor

adienes commented Apr 11, 2024

not sure I would use the word "works", as this seems worse behavior than before to me

of course unsafe_copyto! can do whatever it wants, but using copyto! I'd really expect an UndefRefError here

@jishnub
Copy link
Contributor

jishnub commented Apr 11, 2024

This seems to have been a deliberate choice: #51760

@vtjnash
Copy link
Member

vtjnash commented May 7, 2024

Fixed in #51760

@vtjnash vtjnash closed this as completed May 7, 2024
@vtjnash vtjnash reopened this May 14, 2024
@vtjnash
Copy link
Member

vtjnash commented May 14, 2024

Broken by #54332

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants