Register memory ranges that might cause access violation and throw manged exception #24767
Labels
api-suggestion
Early API idea and discussion, it is NOT ready for implementation
area-System.Runtime
Milestone
Rational
When using memory mapped files, there is the need to handle the standard set of I/O issues, however, the CoreCLR currently expose not such way to do so. In the Full .Net Framework, there is
HandleProcessCorruptedStateExceptions
, which provide some answer to that.However, that require to modify all call sites and is a bit of throwing the baby with the bath waters.
The Core CLR should be able to handle such scenarios cleanly and easily.
Example problem usage:
This code will error with an
SEHException
on Windows, killing the entire process. As it currently stands, there is no good way to protect against this at all.Proposed solution
Provide a way to register memory ranges with the execution engine that will not be subject to the same behavior. When an access violation occurs, the CLR will first check if the memory range of the error occurred in one of these ranges, and if so, will translate the error into a normal manage exception, subject to all the usual rules of such exceptions.
In particular, this will not be a process killer.
This is similar to how a memory access on the first 64KB of the address space is translated to a managed
NullReferenceException
.Proposed API
Sample usage:
The exception thrown
The exception thrown in this case will be a new one:
Semantics
ErrorState
is that it would make it much easier for users to be able to track down the error if they could tag the range with some meaningful value, such as the file name, for example.Implementation details
MemoryAccessViolationBehavior.ThrowOnInvalidMemoryAccessInRange(start, len)
.In this case, there are two options. First, we can have the return object implement a finalizer, which will clear the range protection. Alternatively, we can threat this as intentional sign from the user that they never want to clear the protection of this range. I'm inclined to the first option, because assuming that the user intentionally ignored the disposable is probably a bad idea.
MemoryMappedFile
API, because it should be useful for other types of memory. Either calling directly to the native API (mmap
/CreateViewOfFile
) or using other types of shared memory (shm_open
, etc).Potential issues with this proposal
A user may register a range, then free it and then it is used for some other purpose, which can raise memory access errors, these errors would then be erroneously reported as exception instead of crashing the process.
Given that this is an explicit (and very low level) API, I don't think that this can happen by accident, and the error is explicit enough that it should be obvious what happened, especially given the optional state.
Other considerations
This behavior should ideally apply for managed code and native code alike. Calling a method such as
memcpy
on a range ofmmap
memory can trigger the error as easily as if it was accessed directly.That said, what about the behavior when this occurs during GC, for example? That would be a clear error, and I'm not sure what the behavior of that should be.
Note that this is in contrast to how
NullReferencException
works right now, consider:The managed code accessing the invalid null pointer will get a
NullReferenceExecption
while native code will raise anAccessViolationException
in the debugger and kill the process otherwise.I don't know if this behavior can be applied to native code as well in the same manner (gut feeling is probably not), but even just in managed code, that would be sufficient.
The text was updated successfully, but these errors were encountered: