public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* GCC miscompilation with __seg_fs
@ 2023-03-13 15:24 Sergey Bugaev
  2023-03-13 15:45 ` Jakub Jelinek
  0 siblings, 1 reply; 4+ messages in thread
From: Sergey Bugaev @ 2023-03-13 15:24 UTC (permalink / raw)
  To: libc-alpha, Jakub Jelinek, Florian Weimer

Hello,

while exploring the generated assembly for an entirely unrelated
reason, I found out that GCC eliminates stores through THREAD_SELF
when it's declared using __seg_fs. This is easily reproducible outside
of glibc; here's a sample reproducer (I've also put it on Godbolt [0]
for easy exploration):

[0]: https://godbolt.org/z/PeYv1TP8Y

#include <stddef.h>

typedef struct
{
  void *tcb;
  int some_member;
} tcbhead_t;

#define THREAD_SELF                                            \
  (*(tcbhead_t * __seg_fs *) offsetof (tcbhead_t, tcb))
#define THREAD_SELF_VOLATILE                                   \
  (*(volatile tcbhead_t * __seg_fs *) offsetof (tcbhead_t, tcb))

#define THREAD_SETMEM_SEG_FS(descr, member, value)             \
  (*(__typeof (descr->member) __seg_fs *)                      \
   offsetof (tcbhead_t, member)) = (value)

#define THREAD_SETMEM_ASM(descr, member, value)                \
  asm volatile ("movl %0, %%fs:%P1" :                          \
                : "rmi" (value),                               \
                "i" (offsetof (tcbhead_t, member)))

void
assign_using_setmem_seg_fs (void)
{
  THREAD_SETMEM_SEG_FS (THREAD_SELF, some_member, 42);
}
// assign_using_setmem_seg_fs:
//         movl $42, %fs:8
//         ret

void
assign_using_setmem_asm (void)
{
  THREAD_SETMEM_ASM (THREAD_SELF, some_member, 42);
}
// assign_using_setmem_asm:
//         movl $42, %fs:8
//         ret

void
assign_through_self (void)
{
  THREAD_SELF->some_member = 42;
}
// assign_through_self:
//         ret

void
assign_through_self_volatile (void)
{
  THREAD_SELF_VOLATILE->some_member = 42;
}
// assign_through_self_volatile:
//         movq %fs:0, %rax
//         movl $42, 8(%rax)
//         ret

void
unused_self_volatile (void)
{
    tcbhead_t *tcb = THREAD_SELF_VOLATILE;
}
// unused_self_volatile:
//         ret

As you can see, assigning to TCB members using THREAD_SETMEM
(implemented either with the inline assembly or __seg_fs) works, but
assigning them through the THREAD_SELF pointer does not. The Hurd port
does that explicitly (see __hurd_local_reply_port), and that is where
I caught the miscompilation in the act. But it is entirely possible
that NPTL suffers from this too, perhaps in code like this:

void
pthread_smth (pthread_t t)
{
  struct pthread *pt = (struct pthread *) t;
  t->some_member = 42;
}

pthread_t
__pthread_self (void)
{
  return (pthread_t) THREAD_SELF;
}

void
foo (void)
{
  pthread_smth (__pthread_self ());
}

One workaround would be redefining THREAD_SELF with volatile (see
THREAD_SELF_VOLATILE above), this makes GCC do the right thing for
assignments and does _not_ prevent optimizations if the value is
unused (see unused_self_volatile above). This does however result in
warnings:

<source>:10:30: warning: initialization discards 'volatile' qualifier
from pointer target type [-Wdiscarded-qualifiers]
   10 | #define THREAD_SELF_VOLATILE (*(volatile tcbhead_t * __seg_fs
*) offsetof (tcbhead_t, tcb))
      |                              ^
<source>:47:22: note: in expansion of macro 'THREAD_SELF_VOLATILE'
   47 |     tcbhead_t *tcb = THREAD_SELF_VOLATILE;
      |                      ^~~~~~~~~~~~~~~~~~~~

What do we do?

Sergey

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

end of thread, other threads:[~2023-03-13 16:13 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-03-13 15:24 GCC miscompilation with __seg_fs Sergey Bugaev
2023-03-13 15:45 ` Jakub Jelinek
2023-03-13 15:53   ` Andrew Pinski
2023-03-13 16:13   ` Sergey Bugaev

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).