<div dir="ltr"><div dir="ltr">On Tue, Mar 26, 2019 at 11:34 AM Alexander Potapenko <<a href="mailto:glider@google.com">glider@google.com</a>> wrote:<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Right now there's a handful of places in the kernel where we have to<br>
use __attribute__((uninitialized)) just to avoid creating an extra<br>
initializer: <a href="https://github.com/google/kmsan/commit/00387943691e6466659daac0312c8c5d8f9420b9" rel="noreferrer" target="_blank">https://github.com/google/kmsan/commit/00387943691e6466659daac0312c8c5d8f9420b9</a><br>
and <a href="https://github.com/google/kmsan/commit/2954f1c33a81c6f15c7331876f5b6e2fec0d631f" rel="noreferrer" target="_blank">https://github.com/google/kmsan/commit/2954f1c33a81c6f15c7331876f5b6e2fec0d631f</a><br>
All those assembly directives are using local scalar variables of size<br>
<= 8 bytes as "=qm" outputs, so we can narrow the problem down to "let<br>
DSE remove redundant stores to local scalars that are used as asm()<br>
"m" outputs"<br>
False positives will sure be possible in theory, but hopefully rare in practice.<br>
<br>
I would still love to know what's the main source of truth for the<br>
semantics of asm() constraints.<br>
For example, we've noticed that the BSF instruction, which can be used<br>
as follows:<br>
<br>
unsigned long ffs(unsigned long word) {<br>
  unsigned long ret;<br>
  asm("rep; bsf %1,%0" : "=r" (ret) : "rm" (word));<br>
  return ret;<br>
}<br>
<br>
isn't guaranteed to initialize its output in the case |word| is 0<br>
(according to unnamed Intel architect, it just zeroes out the top 32<br>
bits of the return value).<br>
Therefore the elimination of dead stores to |ret| done by both Clang<br>
and GCC is correct only if the callers are careful enough</blockquote><div><br></div><div>I'm not sure what you mean. If the asm code says "=r" (or "=" *anything*) and fails to write a value to the variable, then you cannot use that value afterwards. That's an error.</div><div><br class="gmail-Apple-interchange-newline"></div><div>It's just like "oops, I didn't return a value from the function":</div><div><br></div><div>int novalueret(int word) { if (word != 0) return 5; }<br></div><div>int f(int word) {</div><div>  int ret;</div><div>  ret = novalueret(word);</div><div>  return ret;</div><div>}</div><div><br></div><div>A mechanism to verify the correctness of arbitrary inline-asm, and check its constraints match is certainly an interesting project, and one that's been discussed before. But if that's even feasible at ALL (which I'm rather skeptical of), that's going to need to be an entirely separate sanitization/hardening/warning framework.</div><div><br></div><div>In the rest of the compiler, if the asm constraints say something, we NEED to trust that the instructions actually do so -- having that power is what inline asm is FOR. There is nothing else useful that we can do.</div></div></div>