public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* Confirm the semantic of GCC extension "Conditionals with Omitted Operands"
@ 2020-07-01 14:11 Gong, Sishuai
  2020-07-23 19:22 ` Gong, Sishuai
  0 siblings, 1 reply; 4+ messages in thread
From: Gong, Sishuai @ 2020-07-01 14:11 UTC (permalink / raw)
  To: gcc-help, gcc

Hello,

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;
 }

 int main()
 {
     int tmp;
     tmp = rand() % 10000;
     int *ptr = &tmp;
     int **pptr = &ptr;
     unsigned int result = hello(pptr);
 }

We compiled this code for two sets of GCC options and compare the disassembly of hello(). In option set 1, we found two memory access (option set 1:521, option set 1:526), thus it has the concurrency issue while in option set 2, we only saw on memory read(option set 2:521). We are wondering if this double memory read pattern is one of the side effects GCC should always avoid?


  1.
option set 1

gcc -m32 -O1 -fno-if-conversion -fno-if-conversion2 -fno-delayed-branch -fno-tree-fre -fno-tree-dominator-opts -fno-cprop-registers simple.c -o option1


  1.
option set 2

gcc -m32 -O1 -fno-if-conversion -fno-if-conversion2 -fno-delayed-branch -fno-cprop-registers simple.c -o option2


  1.
option set 1

0000051d <hello>:
 51d:   8b 44 24 04             mov    0x4(%esp),%eax
 521:   f6 00 fe                testb  $0xfe,(%eax)
 524:   74 08                   je     52e <hello+0x11>
 526:   8b 00                   mov    (%eax),%eax
 528:   25 fe 00 00 00          and    $0xfe,%eax
 52d:   c3                      ret
 52e:   b8 23 01 00 00          mov    $0x123,%eax
 533:   c3                      ret


  1.
option set 2

0000051d <hello>:
 51d:   8b 44 24 04             mov    0x4(%esp),%eax
 521:   8b 00                   mov    (%eax),%eax
 523:   25 fe 00 00 00          and    $0xfe,%eax
 528:   74 02                   je     52c <hello+0xf>
 52a:   f3 c3                   repz ret
 52c:   b8 23 01 00 00          mov    $0x123,%eax
531:   eb f7                   jmp    52a <hello+0xd>

GCC version
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 7.5.0-3ubuntu1~18.04' --with-bugurl=file:///usr/share/doc/gcc-7/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-7 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)


Thanks,
Sishuai


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Confirm the semantic of GCC extension "Conditionals with Omitted Operands"
  2020-07-01 14:11 Confirm the semantic of GCC extension "Conditionals with Omitted Operands" Gong, Sishuai
@ 2020-07-23 19:22 ` Gong, Sishuai
  2020-07-23 19:39   ` Jonathan Wakely
  0 siblings, 1 reply; 4+ messages in thread
From: Gong, Sishuai @ 2020-07-23 19:22 UTC (permalink / raw)
  To: gcc-help

Hi,

I’d like to follow-up on my previous email.

What exactly is the semantic of the GCC extension “Conditionals with Omitted Operands”? Does it guarantee that the read operations of the first operand are only made once (which is not what happens in our experiments)? If not, is there a way to guarantee that the reads of the first operand are only made once to avoid concurrency problems (e.g., a double read that sees different results because of a write made by a concurrent thread)?

Thanks,
Sishuai


On Jul 1, 2020, at 10:11 AM, Gong, Sishuai <sishuai@purdue.edu<mailto:sishuai@purdue.edu>> wrote:

Hello,

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;
 }

 int main()
 {
     int tmp;
     tmp = rand() % 10000;
     int *ptr = &tmp;
     int **pptr = &ptr;
     unsigned int result = hello(pptr);
 }

We compiled this code for two sets of GCC options and compare the disassembly of hello(). In option set 1, we found two memory access (option set 1:521, option set 1:526), thus it has the concurrency issue while in option set 2, we only saw on memory read(option set 2:521). We are wondering if this double memory read pattern is one of the side effects GCC should always avoid?


  1.
option set 1

gcc -m32 -O1 -fno-if-conversion -fno-if-conversion2 -fno-delayed-branch -fno-tree-fre -fno-tree-dominator-opts -fno-cprop-registers simple.c -o option1


  1.
option set 2

gcc -m32 -O1 -fno-if-conversion -fno-if-conversion2 -fno-delayed-branch -fno-cprop-registers simple.c -o option2


  1.
option set 1

0000051d <hello>:
 51d:   8b 44 24 04             mov    0x4(%esp),%eax
 521:   f6 00 fe                testb  $0xfe,(%eax)
 524:   74 08                   je     52e <hello+0x11>
 526:   8b 00                   mov    (%eax),%eax
 528:   25 fe 00 00 00          and    $0xfe,%eax
 52d:   c3                      ret
 52e:   b8 23 01 00 00          mov    $0x123,%eax
 533:   c3                      ret


  1.
option set 2

0000051d <hello>:
 51d:   8b 44 24 04             mov    0x4(%esp),%eax
 521:   8b 00                   mov    (%eax),%eax
 523:   25 fe 00 00 00          and    $0xfe,%eax
 528:   74 02                   je     52c <hello+0xf>
 52a:   f3 c3                   repz ret
 52c:   b8 23 01 00 00          mov    $0x123,%eax
531:   eb f7                   jmp    52a <hello+0xd>

GCC version
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 7.5.0-3ubuntu1~18.04' --with-bugurl=file:///usr/share/doc/gcc-7/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-7 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)


Thanks,
Sishuai



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Confirm the semantic of GCC extension "Conditionals with Omitted Operands"
  2020-07-23 19:22 ` Gong, Sishuai
@ 2020-07-23 19:39   ` Jonathan Wakely
  2020-07-23 20:03     ` Gong, Sishuai
  0 siblings, 1 reply; 4+ messages in thread
From: Jonathan Wakely @ 2020-07-23 19:39 UTC (permalink / raw)
  To: Gong, Sishuai; +Cc: gcc-help

On Thu, 23 Jul 2020 at 20:24, Gong, Sishuai via Gcc-help
<gcc-help@gcc.gnu.org> wrote:
>
> Hi,
>
> I’d like to follow-up on my previous email.
>
> What exactly is the semantic of the GCC extension “Conditionals with Omitted Operands”? Does it guarantee that the read operations of the first operand are only made once (which is not what happens in our experiments)? If not, is there a way to guarantee that the reads of the first operand are only made once to avoid concurrency problems (e.g., a double read that sees different results because of a write made by a concurrent thread)?

Did you read the previous replies?

To make a variable safe for concurrent access by multiple t threads
you need to use atomic operations, and there is no atomic version of
the ?: operator.

So you will need to do something like:

unsigned int hello(int *const *a)
 {
    int b;
    __atomic_load(a, &, __ATOMIC_SEQ_CST);
    unsigned int c = b;
    return c & 0xFE ?: 0x123;
}

In other words, if the GCC extension doesn't provide the guarantees
you need, do something different.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Confirm the semantic of GCC extension "Conditionals with Omitted Operands"
  2020-07-23 19:39   ` Jonathan Wakely
@ 2020-07-23 20:03     ` Gong, Sishuai
  0 siblings, 0 replies; 4+ messages in thread
From: Gong, Sishuai @ 2020-07-23 20:03 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: gcc-help

Hello,

Thanks for the clarification! I apologize for missing your first replies. For some reason, they didn’t come to my mailbox until yours.

Thanks,
Sishuai

> On Jul 23, 2020, at 3:39 PM, Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
> 
> On Thu, 23 Jul 2020 at 20:24, Gong, Sishuai via Gcc-help
> <gcc-help@gcc.gnu.org> wrote:
>> 
>> Hi,
>> 
>> I’d like to follow-up on my previous email.
>> 
>> What exactly is the semantic of the GCC extension “Conditionals with Omitted Operands”? Does it guarantee that the read operations of the first operand are only made once (which is not what happens in our experiments)? If not, is there a way to guarantee that the reads of the first operand are only made once to avoid concurrency problems (e.g., a double read that sees different results because of a write made by a concurrent thread)?
> 
> Did you read the previous replies?
> 
> To make a variable safe for concurrent access by multiple t threads
> you need to use atomic operations, and there is no atomic version of
> the ?: operator.
> 
> So you will need to do something like:
> 
> unsigned int hello(int *const *a)
> {
>    int b;
>    __atomic_load(a, &, __ATOMIC_SEQ_CST);
>    unsigned int c = b;
>    return c & 0xFE ?: 0x123;
> }
> 
> In other words, if the GCC extension doesn't provide the guarantees
> you need, do something different.


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2020-07-23 20:03 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-01 14:11 Confirm the semantic of GCC extension "Conditionals with Omitted Operands" Gong, Sishuai
2020-07-23 19:22 ` Gong, Sishuai
2020-07-23 19:39   ` Jonathan Wakely
2020-07-23 20:03     ` Gong, Sishuai

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).