public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
From: David Brown <david.brown@hesbynett.no>
To: Jonny Grant <jg@jguk.org>, gcc-help <gcc-help@gcc.gnu.org>
Subject: Re: Avoiding stack buffer clear being optimised out
Date: Wed, 30 Nov 2022 19:47:52 +0100	[thread overview]
Message-ID: <2a08f6a3-76bc-f9c7-ad51-9a3d6bbd80bd@hesbynett.no> (raw)
In-Reply-To: <4366aeb5-7fdb-6fa4-b0f5-ebe74c1d4fb2@jguk.org>

On 30/11/2022 17:26, Jonny Grant wrote:
> Hello
> 
> Does GCC have a clear way to avoid memset being compiled out by optimiser?
> 
> This article came up, so I combined the broken.c with GCC
> gcc -Wall -O2 -o broken broken.c
> 
> Note, I've been using gcc for many years, I'm not looking for just tips how to compile code. I only want to discuss this optimiser issue :-)
> 
> https://blog.cloudflare.com/the-linux-kernel-key-retention-service-and-why-you-should-use-it-in-your-next-application/
> 
> If I modify to clear the buffer, it gets removed by the compiler
> 
> The only way I could get it to not remove the memset is by adding another printf, (propagating a return code after checking memset wasn't enough)
> 
>      // gcc -Wall -O2 -o broken broken.c
> 
> #include <stdio.h>
> #include <stdint.h>
> #include <string.h>
> 
> static int encrypt(void)
> {
>      uint8_t key[] = "hunter2";
>      printf("encrypting with super secret key: %s\n", key);
>      void * addr = memset(key, 0, 8);
>      //printf("encrypting with super secret key: %s\n", key);
> 
>      if(addr) return 1;
>      else return 0;
> }
> 
> static void log_completion(void)
> {
>      /* oh no, we forgot to init the msg */
>      char msg[8];
> 
>      printf("not important, just fyi: %s\n", msg);
> }
> 
> int main(void)
> {
>      int ret = encrypt();
>      printf("ret:%d\n", ret);
>      /* notify that we're done */
>      log_completion();
>      return ret;
> }
> 
> Jonny
> 

If you are happy with gcc extensions, inline assembly can give you what 
you want.  It is even highly portable to different processor targets 
(and to clang), because it has no actual assembly code!

<https://godbolt.org/z/6nfY5o89a>

The simplest "sledgehammer" technique here is a memory barrier using a 
memory clobber after the "memset" :

	asm volatile("" ::: "memory");

This tells the compiler to output the instruction sequence "", and that 
it might read or write to anything in memory in unexpected ways.  So the 
compiler will flush out any "uncommitted" writes to memory before 
"executing" this code.  And it will re-read anything that had been 
cached in registers.  So it is quite general, but can have a significant 
performance impact on some kinds of code.  (Still, it is much less 
dramatic than a real memory barrier or memory fence instruction.)


A more targeted approach is to follow the "memset" with :

	asm volatile("" :: "m" (key) : );

This again has an empty set of assembly instructions.  But it tells the 
compiler that those instructions need the value of "key", available in 
memory.  So the "memset" must again be completed before "executing" the 
assembly instructions.  However, nothing else need be touched.


Of course, none of this helps if the compiler has made extra copies of 
the key, or left copies on the stack from other calls.


(I hope that Jonathan or other gcc experts can correct me if I am 
assuming too much from such inline assembly.  I have used this kind of 
construct on a number of occasions, but I have always checked the 
generated assembly afterwards.)



      parent reply	other threads:[~2022-11-30 18:48 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-11-30 16:26 Jonny Grant
2022-11-30 17:40 ` Jonathan Wakely
2022-11-30 17:41   ` Jonathan Wakely
2022-12-01 10:44     ` Jonny Grant
2022-12-01 11:31       ` Jonathan Wakely
2022-12-01 11:34         ` Jonathan Wakely
2022-12-01 11:55         ` Jonny Grant
2022-12-13 20:12   ` Jonny Grant
2022-12-13 20:31     ` Jonathan Wakely
2022-12-13 22:07       ` Jonny Grant
2022-12-13 23:13         ` Jonathan Wakely
2022-12-13 23:16           ` Jonny Grant
2023-01-24 13:52     ` Jonny Grant
2023-01-24 14:26       ` Jonathan Wakely
2022-11-30 18:47 ` David Brown [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2a08f6a3-76bc-f9c7-ad51-9a3d6bbd80bd@hesbynett.no \
    --to=david.brown@hesbynett.no \
    --cc=gcc-help@gcc.gnu.org \
    --cc=jg@jguk.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).