I'm sure some C++ lawyer can correct me, but isn't branching off of `m_ptr` (e.g. `CHECK()`ing the value) after `std::move(m_ptr)` technically Unspecified Behavior since `std::move(m_ptr)` leaves `m_ptr` as an Unspecified Value? It would be up to the compiler to define the behavior if they so pleased, but the C++ spec would not require such behavior to be defined at all.
There is a big difference between "undefined" and "unspecified" behavior. In this case, the behavior of `unique_ptr(unique_ptr&&)` is in fact specified. [0] However, the bigger issue with that code is that it can easily stop working with a simple refactor. Consider: void foo(std::unique_ptr ptr) {} void bar(std::unique_ptr && ptr) {} int main() { std::unique_ptr p1{new int{1}}; std::unique_ptr p2{new int{2}}; foo(std…
Please restore our registers when you’re done with them
121–130 of 142 posts
Re: Please restore our registers when you’re done with them
#122I'm sure some C++ lawyer can correct me, but isn't branching off of `m_ptr` (e.g. `CHECK()`ing the value) after `std::move(m_ptr)` technically Unspecified Behavior since `std::move(m_ptr)` leaves `m_ptr` as an Unspecified Value? It would be up to the compiler to define the behavior if they so pleased, but the C++ spec would not require such behavior to be defined at all.
Moves in C++ don't make the whole object invalid, it just leaves them in a valid but unspecified state, so that at least the destructor can still run. This means calling operator bool on your unique_ptr ought to be fine, because the unique_ptr still has a valid state (you don't know what that state is, it's unspecified, but it's guaranteed to not be radioactive on mere contact. It has to be a valid unspecified state.…
Re: Please restore our registers when you’re done with them
#123Earlier quoted context omitted.
I was wondering if anybody was going to point that out. It did occur to me that the CHECK was not technically valid due to that exact concern, but given that we control the compiler and the C++ library implementation and given that it's just debugging code (albeit debugging code that we ship to users) I'm fine with it. In other words, I guess you shouldn't oughta do that generally, but I was fine with it being used t…
It appears that the question of what is valid on a moved-from object is tricky. Here is one discussion: https://stackoverflow.com/questions/7027523/what-can-i-do-wi... FWIW, here is the move operator for the type of the object in question: https://source.chromium.org/chromium/chromium/src/+/main:bas...
Re: Please restore our registers when you’re done with them
#124Earlier quoted context omitted.
It's literally undecidable in principle whether some assembler correctly restores some register R. That's a non-trivial semantic property, Rice's theorem applies. So the compiler's only practical option if it worked this way would be a conservative option - any time it's unclear whether register R is clobbered, treat it as clobbered. As a trivial example of why a register might not be clobbered even though my code to…
> It's literally undecidable in principle whether some assembler correctly restores some register R. No, it's literally undecidable in principle whether every bit of assembler correctly restores some register R. For any given bit of inline assembler, it's quite likely to be trivial. In any case, we can have a useful safety feature without requiring the compiler to decide. The compiler can easily work out all the regi…
Thanks, I was trying to think about the correct way to express this but clearly I didn't do the best job.
Re: Please restore our registers when you’re done with them
#125Earlier quoted context omitted.
Yes. That's pretty common, unfortunately.
I'd love to see Chrome and Firefox and IE working together to detect this kind of thing and put up a malware warning explaining how to uninstall it, and see how quickly it can be eliminated. Seriously, there is zero valid reason to ever inject code into another program, other than as a debugging tool on a system being debugged.
Re: Please restore our registers when you’re done with them
#126Earlier quoted context omitted.
Yes, that is true. However, moving a zero to a register does take time. Time that would otherwise be used operating with the zero value already present in the zero register. The second best is what moto did. As you point out, there is the instruction fetch, which could be the intended operation, rather than developing the zero itself. On par with that is having enough registers to just hold a zero, and whether that m…
But moving it from the zero register to another register would also take time. If what you want is a zero in a register other than the zero register (say, one that is going to serve as the index of a loop, which the zero register cannot do), then MOVEQ should not take any longer than a MOVE from the zero register to another register.
Say we are zeroing memory. No advantage there. Coupla cycles right at the start, then a ton of writes.
Say we are forming a bitmask. Could be an advantage there in that having a zero handy in a register means no fetching one. When a lot of dynamically created masks are needed, this can be a nice gain.
I'm sure we can come up with more. It's not always important, and like you mention with the moto designs, may not matter too much due to many other optimizations possible given a good instruction set.
Some people would rather have the register free for general use! I'm one of those, but if there is a zero register, I use it to get the benefit of it when I can. On the devices I've seen, there are generally a lot of registers so the marginal impact of having a zero register isn't significant. There are plenty to work with.
Maybe I should be clear here too. I personally don't care whether there is one. If it's there, I do things in ways that leverage it, and was just pointing out why devices that have one, ahem... have one! Those that don't may or may not have options that make sense. The way moto did it is very good, and there are other pretty great optimizations possible with their ISA, abusing the stack to write memory, etc...
If not, then I do other things. It's assembly language! Work the chip, right?
Re: Please restore our registers when you’re done with them
#127Earlier quoted context omitted.
IIRC we do block DLLs that aren't signed by either Google or Microsoft in some of our processes. In other processes we can't because third-party DLLs are needed for shell extensions (utility processes) or accessibility (browser process). And, as you say, code injection is possible without loading a DLL, and does seem to happen. In this case I don't understand how the state leaked from the file-system filter driver to…
> In this case I don't understand how the state leaked from the file-system filter driver to our process, as it seems to have done. I assume you made some Windows API call somewhere, which ended up in the filesystem filter driver, which then clobbered the register. And I'm guessing the NT kernel code and Windows DLLs never save/restore the register, because it isn't supposed to be clobbered. Couldn't one approach be…
Re: Please restore our registers when you’re done with them
#128Earlier quoted context omitted.
It’s an unspecified but required to be valid value for the moved type. The author mentions it’s a smart pointer type, which could easily be defined to act like this.
It appears that you need to be really smart in order to not blow your own foot off with this "smart pointer." I'll stick to the regular dumb kind, thanks.
Re: Please restore our registers when you’re done with them
#129I think the real fix is to set all registers to a canary value at the start of int main(), and then when exiting check the canary value is still there. If anything has messed with any registers without permission, you crash and collect as much data as possible about any injected dll's. Then you correlate these to find the culprits, and for each you contact the authors of the DLL and figure out a way to block the inje…
Any good function upstream of the bad one that also uses the same register will mask the issue
Re: Please restore our registers when you’re done with them
#130Earlier quoted context omitted.
It would be easy to have an "auto" clobber list option. The inline assembler would note which registers were touched (mostly trivial, a few instructions have implicit destinations) and would add them all to the clobber list. In about 99% of cases this would be sufficient. I am not aware of any code that conditionally uses a register _and_ conditionally preserves it. So, 1% of assembly code would use the manual clobbe…
If your numbers are roughly correct then I agree it's worth trying to do this. My guess was that the assembly we actually use tends to be aggressively hand-optimised to solve very nice problems in the most optimal way and therefore would be more rather than less likely to trip up analysis, but I haven't experimented.
Or, put another way, writing tiny little assembly language functions is probably not worth it because the mere fact that you are using assembly language instead of (say) C/C++ means that you have missed many opportunities (code reordering, inlining, etc.) so assembly language functions _should_ be doing enough work to justify their calling cost.
But, I'm not working on an assembler or even using one so I don't think I'll even file a feature request.