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

MemoryRef bounds errors can be confusing #57184

Open
LilithHafner opened this issue Jan 28, 2025 · 7 comments · May be fixed by #57278
Open

MemoryRef bounds errors can be confusing #57184

LilithHafner opened this issue Jan 28, 2025 · 7 comments · May be fixed by #57278
Labels
arrays [a, r, r, a, y, s] display and printing Aesthetics and correctness of printed representations of objects. error messages Better, more actionable error messages good first issue Indicates a good issue for first-time contributors to Julia help wanted Indicates that a maintainer wants help on an issue or pull request

Comments

@LilithHafner
Copy link
Member

Because of how MemoryRefs can represent views and because the MemoryRef itself is not captured in BoundsErrors, we can get confusing errors like this:

julia> x = Memory{Int}([1,2,3,4])
4-element Memory{Int64}:
 1
 2
 3
 4

julia> copyto!(x, 3, x, 3, 3)
ERROR: BoundsError: attempt to access MemoryRef{Int64} at index [3]
Stacktrace:
 [1] memoryref
   @ ./boot.jl:524 [inlined]
 [2] unsafe_copyto!
   @ ./genericmemory.jl:115 [inlined]
 [3] unsafe_copyto!
   @ ./genericmemory.jl:139 [inlined]
 [4] copyto!(dest::Memory{Int64}, doffs::Int64, src::Memory{Int64}, soffs::Int64, n::Int64)
   @ Base ./genericmemory.jl:175
 [5] top-level scope
   @ REPL[1]:1

This example is confusing because one could think that the memory has length 4 so accessing it at index 3 should be fine. What's happening is that a MemoryRef is constructed at an offset and then indexed out of bounds at index 3 when the new MemoryRef only has two indices.

@LilithHafner LilithHafner added arrays [a, r, r, a, y, s] error messages Better, more actionable error messages labels Jan 28, 2025
@vtjnash
Copy link
Member

vtjnash commented Jan 28, 2025

It is captured, it is just that people decided it wasn't helpful to display the object that errored, and changed it to only print the type as a summary of it (although also that the show of a MemoryRef is not very good):

julia> err.stack[1].exception
BoundsError(MemoryRef{Int64}(Ptr{Nothing}(0x0000000103f3e8b0), [1, 2, 3, 4]), 3)

@LilithHafner
Copy link
Member Author

Oh, delightful! This issue is very actionable with a better special case for displaying bounds errors on MemoryRef objects.

@LilithHafner LilithHafner added good first issue Indicates a good issue for first-time contributors to Julia help wanted Indicates that a maintainer wants help on an issue or pull request labels Jan 28, 2025
@KristofferC
Copy link
Member

with a better special case for displaying bounds errors on MemoryRef objects

Or improve summary ofMemoryRef (like how it is done for String)?

@LilithHafner LilithHafner added the display and printing Aesthetics and correctness of printed representations of objects. label Feb 5, 2025
@Omar-Elrefaei
Copy link
Contributor

I was attempting to take a shot at this, but I'm not sure how to safely figure out how many "remaining" elements in the MemoryRef without doing pointer gymnastics.

I say this because I don't imagine replacing the error like this example will be helpful at all, since it is won't be clear what the problem is.

julia> x = Memory{Int}([1,2,3,4])
julia> copyto!(x, 1, x, 4, 2)
ERROR: BoundsError: attempt to access MemoryRef{Int64} at index [2]

# replace with this
ERROR: BoundsError: attempt to access a 4-element MemoryRef{Int64} at index [2]

# compared with
julia> SubString("1234", 4)[2]
ERROR: BoundsError: attempt to access 1-codeunit SubString{String} at index [2]

and so I was looking into trying to "count" the remaining elements that can be safely accessed such that:

mref = memoryref(x, 3)
remaining_length(mref) == 2

Note that in my example, the error is thrown from a call to memoryref(memoryref(mref, 4), 2) (with mref not x) from /base/genericmemory.jl:115

@oscardssmith
Copy link
Member

The way to do this safely is to use memoryrefoffset combined with the length of the underlying memory

@Omar-Elrefaei Omar-Elrefaei linked a pull request Feb 5, 2025 that will close this issue
@Omar-Elrefaei
Copy link
Contributor

thanks @oscardssmith! its a bummer that this was not discoverable using methodswith(GenericMemoryRef)

maybe it'd be a good idea to leave some "see also" hints in memoryref's docstring?

@oscardssmith
Copy link
Member

seems like a good doc improvement.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
arrays [a, r, r, a, y, s] display and printing Aesthetics and correctness of printed representations of objects. error messages Better, more actionable error messages good first issue Indicates a good issue for first-time contributors to Julia help wanted Indicates that a maintainer wants help on an issue or pull request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants