-
Notifications
You must be signed in to change notification settings - Fork 30
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
Check memory protection per page #210
Check memory protection per page #210
Conversation
Thank you so much! For starters, the PR itself and the code style looks absolutely excellent, but I'm not super confident about the logic (which could actually be my own fault). Let me think it out loud. I agree that checking protection once per page is sufficient, and of course the 512 slots that we are checking (512*8=4096 bytes) are going to either fit in exactly one page or at most straddle two pages so that's a great optimization. And we can be pretty confident that, being The caveat is here. We are dereferencing the pointer to get the pointer to the For background, my PR comes out of an attempt of running a heuristic that would assess whether a given pointer had a COM vtable in it to then try to construct a
In this case, all of that contiguous memory space would be in the same page and thus have a single protection flag set, but each address on the right is in a different page so that would warrant one check per address. But with #209 we are now checking the pointer value itself i.e. Have I gotten some of this wrong? That being said, LGTM, and thank you for your contribution! I'll merge this in and finalize the other PR as soon as I get the chance. |
Thanks! :)
Yeah, since the struct members can be null or not a pointer at all, calling
What you wrote fits (and cleared some stuff up for me).
I think so too and event if the pointer is at the bottom of the struct, the whole struct should be within readable memory. This should be perfectly safe as long as they don't remove the pointer and we start reading outside the struct. The caveat you pointed out got me thinking that I might have misunderstood the code and broke something but after looking over both the old and new snippets again I'm sure it's still doing the same thing. I have no DirectX background (which is why I'm using this library :P), so I thought the I found this post and the offset from the answer is different from the one I get when testing (for me the command queue is at I attached a debugger to a DirectX 12 example and set a hardware breakpoint to see what reads/writes to |
Yeah, though I don't feel like risking it -- for example, on Wine the command queue is the first qword immediately after the vtable (e.g. offset +1) so there's no saying where different implementations might end up putting that.
Yep, that was definitely me mixing things up with the attempt before.
I discarded doing outright that because I got burned by it already a few years ago, when a new d3d11.dll was released and they shuffled the pointers around. I actually wanted to go the DirectComposition way myself which would've allowed me to not maintain 4 separate renderers but when I was already done I went ahead, tested it on Linux and discovered that that's not implemented by Wine, so had to roll everything back and start over. :(
I think that would be even trickier. I expect that a change in struct layout could send the optimizer down through different paths and result in different looking assembly at least for some functions, so that's kinda wobbly to rely upon. |
Memory protection flags are set per page so it's enough to check them at page boundaries. (See here)
This simplifies the code for #209 (relevant diff) to this
I've added a helper function that checks the memory protection at each page boundary in a memory region and returns a slice containing all consecutive readable elements starting from the start of the region.
I've stared at my implementation for a bit and I think the logic is correct.