Read only function pointers (MonoThreadInfoRuntimeCallbacks). (#16545)
Read only memory is preferred, for efficiency and security.
Even if it requires relocation first.
If the runtime is loaded in more than one process, physical pages can be shared (at least on Windows, where the kernel does the relocation).
If there is memory corruption, writes to here will sigsegv/accessviolate.
The older code also copied the pointers. For lifetime purposes that could be useful, but generally is not. i.e. they live with the code they point to.
Writable function pointers are also particularly targets for attackers.
There's been tons of defenses put around them through the years.
Read only ones are not vulnerable -- unless the attacker escalates and calls mprotect first.
When there is a JIT, arguably there is just tons of attack surface.
But there is also AOT.
Structs of function pointers are usually read only in the wider world.