public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
From: "jakub at gcc dot gnu.org" <gcc-bugzilla@gcc.gnu.org>
To: gcc-bugs@gcc.gnu.org
Subject: [Bug sanitizer/114217] -fsanitize=alignment false positive with intended unaligned struct member access
Date: Mon, 04 Mar 2024 07:46:18 +0000	[thread overview]
Message-ID: <bug-114217-4-wZobCvVqTB@http.gcc.gnu.org/bugzilla/> (raw)
In-Reply-To: <bug-114217-4@http.gcc.gnu.org/bugzilla/>

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114217

Jakub Jelinek <jakub at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |jsm28 at gcc dot gnu.org

--- Comment #9 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
(In reply to Akihiko Odaki from comment #8)
> It would certainly workaround the issue, but it's only dirtier and brings no
> benefit except suppressed UBSan errors. Why not allow
> get_unaligned(&entry->offset) when UBSan does not complain about that hack?

The purpose of the sanitizer is to find undefined behavior, and it found one.
If you don't want it to find undefined behavior, don't use it.

> > If you want something that will be valid even in C, don't pass struct
> > dir_entry *entry
> > argument, but void *entry instead, and use e.g.
> > __get_unaligned_t(__typeof(((struct dir_entry *)0)->offset), ((char
> > *)entry)+offsetof(struct dir_entry, offset)))
> > You can surely hide that all under some macro.
> 
> The definition still involves UB for ((struct dir_entry *)0)->offset.
> Perhaps __typeof() may be considered as an exception, but what if offsetof()
> is defined as follows?
> 
> #define offsetof(T, x) ((uintptr_t)&(((T *)0)->x))

typeof nor sizeof operators don't evaluate their arguments unless the
expressions have VLA type.  So, if there would be undefined behavior if they
were evaluated, it doesn't matter because they aren't.  So, e.g.

void
foo (int n, int *p)
{
  typedef int A[n];
  A b[4];
  typedef int C[10];
  C d[4];
  int i = 0;
  int j = 0;
  typeof (b[++i]) e;
  typeof (d[++j]) f;
  typeof (d[100][4]) g;
  p[0] = i;
  p[1] = j;
}

doesn't invoke undefined behavior and sets p[0] to 1 and p[1] to 0, b[++i] had
VLA type, so it got evaluated, the other 2 didn't, so ++j wasn't evaluated and
the d[100]
UB wasn't triggered, as if the program did if (n == 54) d[100][4]; and n at
runtime was
never 54.  __typeof is a GNU extension but behaves the same way.

offsetof is a standard C macro.  It is not defined in the standard as
dereferencing NULL pointer, but as if there was an object of the T type and it
computed the difference between the address of the x member of it and the start
of the object.
If offsetof is defined as
#define offsetof(T, x) ((size_t)(uintptr_t)&(((T *)0)->x))
by the implementation (and yes, e.g. GCC < 4 used to define it similarly), then
obviously the compiler can't assume there is undefined behavior on such
expressions,
but it didn't at that point, there was no UBSAN, such expressions evaluated to
a constant expression early before anything could have considered there might
be UB and after it was just the resulting constant.
If the implementation doesn't have some exception that considers expressions
like
&(((T *)0)->x) valid, then it can't use such offsetof definition and needs to
use something else, like GCC uses __builtin_offsetof.  That said, GCC AFAIK
still treats expressions like the above as offsetof-like (because there has
been a lot of such code in the wild for decades), folds them to constant right
away and doesn't complain about it with ubsan; clang does complain about it
though and doesn't treat it that way.
Anyway, if you use something like ((size_t)(uintptr_t)&(((T *)0)->x)), per C
rules you are invoking UB, while if you use offsetof(T, x), it is well defined.

  parent reply	other threads:[~2024-03-04  7:46 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-03-03  7:03 [Bug sanitizer/114217] New: " akihiko.odaki at daynix dot com
2024-03-03  7:10 ` [Bug sanitizer/114217] " pinskia at gcc dot gnu.org
2024-03-03  7:15 ` pinskia at gcc dot gnu.org
2024-03-03  7:19 ` akihiko.odaki at daynix dot com
2024-03-03  7:22 ` pinskia at gcc dot gnu.org
2024-03-03  7:29 ` akihiko.odaki at daynix dot com
2024-03-03  7:46 ` akihiko.odaki at daynix dot com
2024-03-03 19:01 ` jakub at gcc dot gnu.org
2024-03-04  5:26 ` akihiko.odaki at daynix dot com
2024-03-04  7:46 ` jakub at gcc dot gnu.org [this message]
2024-03-04  7:54 ` jakub at gcc dot gnu.org
2024-03-04  8:11 ` akihiko.odaki at daynix dot com
2024-03-04  8:35 ` jakub at gcc dot gnu.org
2024-03-04  8:45 ` akihiko.odaki at daynix dot com
2024-03-04 21:48 ` i at maskray dot me

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=bug-114217-4-wZobCvVqTB@http.gcc.gnu.org/bugzilla/ \
    --to=gcc-bugzilla@gcc.gnu.org \
    --cc=gcc-bugs@gcc.gnu.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).