From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pj1-x1030.google.com (mail-pj1-x1030.google.com [IPv6:2607:f8b0:4864:20::1030]) by sourceware.org (Postfix) with ESMTPS id 75DB23858C5F for ; Mon, 13 Mar 2023 15:24:59 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 75DB23858C5F Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-pj1-x1030.google.com with SMTP id u3-20020a17090a450300b00239db6d7d47so12046773pjg.4 for ; Mon, 13 Mar 2023 08:24:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; t=1678721098; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=+580wLULDaXbHhnIQPiq49dln8cbglvHpe5hm18fYOY=; b=aW1yUt0diCme24M+f1nsR+wh1C8a1y0vDgsYtLC2u+MAmb4vuhcNdXulYJUuKPsb68 8uwnjJcl2odrzqh9HJy3KZqAtsRqko2ggCJWQ6NsUE2x2prvTVbzCl09UJjY+KNJ5Az/ 38MYywn41Q3bO6ScN9gSLtJjY+rRSxhDWB5yuZFTRVE6pYljV1HA2chemA9nF+rV2YLS l9YU2KObMmUYrMq0+ti+Hk0qtqdDc2ebdEBM3idqcMPlXK/+GmPIdyTXx86hSFLo50oC GLCIuFJBujTrDF6NYKaxJPi7ICvyx3Y2tDn8Hj3rxQymNUoLaF8maQ/owFNXIrTz60pH fw6w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1678721098; h=to:subject:message-id:date:from:mime-version:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=+580wLULDaXbHhnIQPiq49dln8cbglvHpe5hm18fYOY=; b=N7bhcaOebMqHfkPotKYHpVE6nKLBli0t1UOT3y0TzlMEiHZ73wB/4qKaAzpYP+mWSB OZp9qjWFzMX3vk1qP1W2xXefYS09fT3Ls/8qJ1zbNzVOrLuQ1pp8aOiL12ZSJiMpW/4s NvaWSnd77ZPF8vhdB3AIQyQm9z9Eh65n8E4fUvkFVf/V0k5DGE2YLFzCGSxbBz52sz6b PumJ/UA6CVOFR0xl4YQ3xajWOrAijHA+1mwwxIgzA4j+qkdamy1H5f841VJj+84dsNZ3 kxEwa0jhC/kTL+SCzIWWNl7NcgdmHo9bmv4wGOxV9FR4yVjDHPbhemM9/4pqsYUrxo54 ttRw== X-Gm-Message-State: AO0yUKVLvHWA+H0HHIWoa9RVIMS2ZqrsFWZLXBlmt571PHEijniwKeYx ytAJPHJHEoidV03a8dPDxZfsg92B0xRMJI7yyb1T1rv6Uqo= X-Google-Smtp-Source: AK7set+WjnrL5uZjXr8JHhOmP2e4tqESmZ7jgWvUOX3UKd6ftTVyA5eIrAJNvXarEZnQhWDb4zw45kB30VE8vFm+nts= X-Received: by 2002:a17:90a:4a15:b0:23c:fea4:770c with SMTP id e21-20020a17090a4a1500b0023cfea4770cmr1429239pjh.3.1678721098164; Mon, 13 Mar 2023 08:24:58 -0700 (PDT) MIME-Version: 1.0 From: Sergey Bugaev Date: Mon, 13 Mar 2023 18:24:47 +0300 Message-ID: Subject: GCC miscompilation with __seg_fs To: libc-alpha@sourceware.org, Jakub Jelinek , Florian Weimer Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-2.2 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: 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 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: :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)) | ^ :47:22: note: in expansion of macro 'THREAD_SELF_VOLATILE' 47 | tcbhead_t *tcb = THREAD_SELF_VOLATILE; | ^~~~~~~~~~~~~~~~~~~~ What do we do? Sergey