Basically, memory corruption is caused by overwriting memory you're not supposed to overwrite. I am wondering if this is possible with unsafe code in C# (i.e. not by calling into external unmanaged code). I see two possible cases:
In both cases it seems the runtime detects and prevents the potential memory corruption from taking place. Therefore, is it possible to corrupt memory from C# using unsafe code? And as a corollary, is it safe to catch AccessViolationExceptions from unsafe code?
What Does Unsafe Mean? Unsafe is a C programming language (C#) keyword used to denote a section of code that is not managed by the Common Language Runtime (CLR) of the . NET Framework, or unmanaged code. Unsafe is used in the declaration of a type or member or to specify block code.
Since memory safety bugs are often security issues, memory safe languages are more secure than languages that are not memory safe. Memory safe languages include Rust, Go, C#, Java, Swift, Python, and JavaScript. Languages that are not memory safe include C, C++, and assembly.
In an unsafe programming language, errors are not trapped. Rather, after executing an erroneous operation the program keeps going, but in a silently faulty way that may have observable consequences later on.
For example, Java is said to be memory-safe because its runtime error detection checks array bounds and pointer dereferences. In contrast, C and C++ allow arbitrary pointer arithmetic with pointers implemented as direct memory addresses with no provision for bounds checking, and thus are potentially memory-unsafe.
You are missing the Big Bullet:
Which is very common, there's always lots of writable memory around in a .NET program. Including writing the element beyond the end of an array, it rarely bombs. Memory protection is granular at memory page boundaries, 4096 bytes on Windows. The .NET GC bumps that up considerably, the generational heap segments are nice big hunks of VM. Catching AVEs is very unwise.
Some code to play with:
class Program {
static unsafe void Main(string[] args) {
var arr = new byte[1];
for (int fill = 0; fill < 2 * 1024 - 64; ++fill) {
byte[] dummy = new byte[1024];
}
fixed (byte* p = &arr[0]) {
for (int ix = 1; ; ++ix)
p[ix] = 42;
}
}
}
Overshoots by about 1.5 megabytes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With