On Wed, Jul 01, 2020 at 11:53:05AM -0400, Nathan Sidwell wrote:
> On 7/1/20 10:11 AM, Gong, Sishuai via Gcc wrote:
> > Hope this mail finds you well. I am writing this to ask about one extension 
> > in GCC, which is “Conditionals with Omitted Operands”.
> > 
> >  From the document at https://gcc.gnu.org/onlinedocs/gcc/Conditionals.html 
> > , we learn that this extension could be useful in terms of avoiding the 
> > side effects of recomputing. However, we recently observed a case in the 
> > Linux kernel, where the kernel develops are using this extension but 
> > compiling their code with certain optimizations disabled may lead to a 
> > concurrency vulnerability. The general idea of this problem is, for a line 
> > of code leveraging “Conditionals with Omitted Operands", GCC, with fewer 
> > optimizations, could generate a disassembly contains two memory read to the 
> > same object. One is for checking the value in the first operand in the 
> > ternary expression and another is for the second operand, which is omitted 
> > in order to leverage this extension. Thus, another thread could update the 
> > object between the two read and lead to inconsistent behavior. We are not 
> > sure if this is a problem with GCC or the kernel developers should be aware 
> > of this vulnerability. Hope you could give us some hints.
> > 
> > Here I put a simple program that I hope could explain this problem.
> > #include<stdio.h>
> > #include<stdlib.h>
> > 
> >   unsigned int hello(int *const *a)
> >   {
> >       return (unsigned int)((unsigned int)*a & 0xFE) ? : 0x123;
> >   }
> 
> because a's type is 'int *', there are no changes in semantics, at the C
> abstract machine level, for accessing *a any number of times.  Thus
> depending on a specific number of accesses is unreliable.

Yeah, this is in no way related to ?: with omitted middle operand, e.g. with
register allocation a value from memory might be read many times rather than
just once even if in the source it is read once - the compiler sees the
value in some memory and if it can prove the value doesn't change in
between, rather than e.g. spilling it to a new stack slot it can just read
it again.
If you need guarantees, you should be using __atomic_load_n, or inline asm
that will ensure the value is only in a register (or could be spilled to
stack), but never reread from he containing memory, or you could use
volatile (that hurts other optimizations though).

        Jakub

Reply via email to