-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
Darwin/ARM64: Fix throwing of synchronous memory exceptions #36625
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
Conversation
|
Oh, also added a test for this code path, since I don't think we had one. |
| #ifdef _CPU_X86_64_ | ||
| // push (null) $RIP onto the stack | ||
| rsp -= sizeof(void*); | ||
| *(void**)rsp = NULL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The corresponding aarch64 operation is setting lr to zero.
Line 135 in a23a4ff
| ctx->uc_mcontext.regs[29] = 0; // Clear link register (x29) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And is
Line 162 in a23a4ff
| ucontext64_t *ctx = (ucontext64_t*)_ctx; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, I was wondering if we should set lr to NULL, but I haven't looked at the unwinder yet. I guess it can't really hurt.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah it shoudn't hurt. And I think at least in one case I've seen it helps the unwinder (either ours or gdb) terminates the stack trace. (on linux...)
| # Test that read fault on a prot-none region does not incorrectly give | ||
| # ReadOnlyMemoryEror, but rather crashes the program | ||
| const MAP_ANONYMOUS_PRIVATE = Sys.isbsd() ? 0x1002 : 0x22 | ||
| let script = :(let ptr = Ptr{Cint}(ccall(:jl_mmap, Ptr{Cvoid}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we actually guarantee this everywhere else?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think we have this logic on every platform.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It throws readonlymmoryerror on linux for example. I don't really see why it's that important to differentiate reading PROT_NONE from writing PROT_READ. The linux one only check for permission violation and would tread violation of read/write/execution the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I imaging what you could do is to unmap the page before issueing the unsafe_load. Assuming the code is compiled it should make sure you are loading from a hole in the mapping and that should be a crash.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I imaging what you could do is to unmap the page before issueing the
unsafe_load. Assuming the code is compiled it should make sure you are loading from a hole in the mapping and that should be a crash.
That doesn't exercise this code path. We explicitly check that the mapping exists first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we may just want to fix the linux behavior here to bring it in line with mac/windows. I don't see a good reason to throw ReadOnlyMemoryError here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... Sure, that's fine. It's technically breaking but it was an error before anyway...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or it's a bug fix and brings linux in line with the other platforms ;).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Breaking" for ppl (like me) who hardly ever use julia anywhere other than linux... Not that I've ever cought any read only memory error when reading things anyway.............
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do agree the name of the exception is very suggestive of what it should do...
yuyichao
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either the test or the implementation needs to be updated.
| # Test that read fault on a prot-none region does not incorrectly give | ||
| # ReadOnlyMemoryEror, but rather crashes the program | ||
| const MAP_ANONYMOUS_PRIVATE = Sys.isbsd() ? 0x1002 : 0x22 | ||
| let script = :(let ptr = Ptr{Cint}(ccall(:jl_mmap, Ptr{Cvoid}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It throws readonlymmoryerror on linux for example. I don't really see why it's that important to differentiate reading PROT_NONE from writing PROT_READ. The linux one only check for permission violation and would tread violation of read/write/execution the same.
This replaces #36625. Essentially the question is what should reading from PROT_NONE memory do. At the moment we throw ReadOnlyMemoryError on Linux and pass through the segfault on Windows/Mac. It's not super clear what the right answer is, though it would be nice to be consistent. After some discussion, it seemed that not throwing ReadOnlyMemoryError on Linux was probably the better consistency direction for two reasons: 1. Getting a ReadOnlyMemoryError is confusing if the failing operation is a read. We could of course rename the error, but that would be a bigger breaking change. 2. The purpose of this exception is to protect people who accidentally try to write to mmap'ed memory that they don't have write permissions to. It was never intended to become a general memory access error exception, so it seems prudent to restrict it as much as possible. To make this happen, there is some platform specific code here to read the memory error register out of the signal context. Decoding this register is shared code between the operating systems, but the register itself is in an OS-specifc location in the signal frame. I have implemented the retrieval code for all our CI'ed platforms. Other users will get an appropriate `#warning` (similar to other code in this file) and can fill in the necessary code at their leisure. A new test in test/misc.jl will indicate whether or not the check is correct.
This replaces #36625. Essentially the question is what should reading from PROT_NONE memory do. At the moment we throw ReadOnlyMemoryError on Linux and pass through the segfault on Windows/Mac. It's not super clear what the right answer is, though it would be nice to be consistent. After some discussion, it seemed that not throwing ReadOnlyMemoryError on Linux was probably the better consistency direction for two reasons: 1. Getting a ReadOnlyMemoryError is confusing if the failing operation is a read. We could of course rename the error, but that would be a bigger breaking change. 2. The purpose of this exception is to protect people who accidentally try to write to mmap'ed memory that they don't have write permissions to. It was never intended to become a general memory access error exception, so it seems prudent to restrict it as much as possible. To make this happen, there is some platform specific code here to read the memory error register out of the signal context. Decoding this register is shared code between the operating systems, but the register itself is in an OS-specifc location in the signal frame. I have implemented the retrieval code for all our CI'ed platforms. Other users will get an appropriate `#warning` (similar to other code in this file) and can fill in the necessary code at their leisure. A new test in test/misc.jl will indicate whether or not the check is correct.
This replaces #36625. Essentially the question is what should reading from PROT_NONE memory do. At the moment we throw ReadOnlyMemoryError on Linux and pass through the segfault on Windows/Mac. It's not super clear what the right answer is, though it would be nice to be consistent. After some discussion, it seemed that not throwing ReadOnlyMemoryError on Linux was probably the better consistency direction for two reasons: 1. Getting a ReadOnlyMemoryError is confusing if the failing operation is a read. We could of course rename the error, but that would be a bigger breaking change. 2. The purpose of this exception is to protect people who accidentally try to write to mmap'ed memory that they don't have write permissions to. It was never intended to become a general memory access error exception, so it seems prudent to restrict it as much as possible. To make this happen, there is some platform specific code here to read the memory error register out of the signal context. Decoding this register is shared code between the operating systems, but the register itself is in an OS-specifc location in the signal frame. I have implemented the retrieval code for all our CI'ed platforms. Other users will get an appropriate `#warning` (similar to other code in this file) and can fill in the necessary code at their leisure. A new test in test/misc.jl will indicate whether or not the check is correct.
This replaces #36625. Essentially the question is what should reading from PROT_NONE memory do. At the moment we throw ReadOnlyMemoryError on Linux and pass through the segfault on Windows/Mac. It's not super clear what the right answer is, though it would be nice to be consistent. After some discussion, it seemed that not throwing ReadOnlyMemoryError on Linux was probably the better consistency direction for two reasons: 1. Getting a ReadOnlyMemoryError is confusing if the failing operation is a read. We could of course rename the error, but that would be a bigger breaking change. 2. The purpose of this exception is to protect people who accidentally try to write to mmap'ed memory that they don't have write permissions to. It was never intended to become a general memory access error exception, so it seems prudent to restrict it as much as possible. To make this happen, there is some platform specific code here to read the memory error register out of the signal context. Decoding this register is shared code between the operating systems, but the register itself is in an OS-specifc location in the signal frame. I have implemented the retrieval code for all our CI'ed platforms. Other users will get an appropriate `#warning` (similar to other code in this file) and can fill in the necessary code at their leisure. A new test in test/misc.jl will indicate whether or not the check is correct.
This replaces JuliaLang#36625. Essentially the question is what should reading from PROT_NONE memory do. At the moment we throw ReadOnlyMemoryError on Linux and pass through the segfault on Windows/Mac. It's not super clear what the right answer is, though it would be nice to be consistent. After some discussion, it seemed that not throwing ReadOnlyMemoryError on Linux was probably the better consistency direction for two reasons: 1. Getting a ReadOnlyMemoryError is confusing if the failing operation is a read. We could of course rename the error, but that would be a bigger breaking change. 2. The purpose of this exception is to protect people who accidentally try to write to mmap'ed memory that they don't have write permissions to. It was never intended to become a general memory access error exception, so it seems prudent to restrict it as much as possible. To make this happen, there is some platform specific code here to read the memory error register out of the signal context. Decoding this register is shared code between the operating systems, but the register itself is in an OS-specifc location in the signal frame. I have implemented the retrieval code for all our CI'ed platforms. Other users will get an appropriate `#warning` (similar to other code in this file) and can fill in the necessary code at their leisure. A new test in test/misc.jl will indicate whether or not the check is correct.
This replaces JuliaLang#36625. Essentially the question is what should reading from PROT_NONE memory do. At the moment we throw ReadOnlyMemoryError on Linux and pass through the segfault on Windows/Mac. It's not super clear what the right answer is, though it would be nice to be consistent. After some discussion, it seemed that not throwing ReadOnlyMemoryError on Linux was probably the better consistency direction for two reasons: 1. Getting a ReadOnlyMemoryError is confusing if the failing operation is a read. We could of course rename the error, but that would be a bigger breaking change. 2. The purpose of this exception is to protect people who accidentally try to write to mmap'ed memory that they don't have write permissions to. It was never intended to become a general memory access error exception, so it seems prudent to restrict it as much as possible. To make this happen, there is some platform specific code here to read the memory error register out of the signal context. Decoding this register is shared code between the operating systems, but the register itself is in an OS-specifc location in the signal frame. I have implemented the retrieval code for all our CI'ed platforms. Other users will get an appropriate `#warning` (similar to other code in this file) and can fill in the necessary code at their leisure. A new test in test/misc.jl will indicate whether or not the check is correct.
Needs decoding of the ARM64 ESR register. Additionally, the Aarch64 ABI requires 16 byte aligned stack
pointers on function entry, so we can't push the return pointer there. Whether we need to construct a
stack frame instead will depend on the unwinder (which doesn't work yet), but I don't believe so,
since the ABI mandates a frame pointer.