From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-3.3 required=5.0 tests=MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL autolearn=ham autolearn_force=no version=3.4.4 Received: (qmail 23302 invoked from network); 8 Apr 2021 17:49:32 -0000 Received: from mother.openwall.net (195.42.179.200) by inbox.vuxu.org with ESMTPUTF8; 8 Apr 2021 17:49:32 -0000 Received: (qmail 1753 invoked by uid 550); 8 Apr 2021 17:49:30 -0000 Mailing-List: contact musl-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Reply-To: musl@lists.openwall.com Received: (qmail 1732 invoked from network); 8 Apr 2021 17:49:30 -0000 Date: Thu, 8 Apr 2021 13:49:18 -0400 From: Rich Felker To: Ariadne Conill Cc: musl@lists.openwall.com Message-ID: <20210408174917.GB2546@brightrain.aerifal.cx> References: <00bc01d72c91$bdedb030$39c91090$@yandex-team.ru> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.21 (2010-09-15) Subject: Re: [musl] errno and swapcontext in a multithreaded setup On Thu, Apr 08, 2021 at 11:40:43AM -0600, Ariadne Conill wrote: > Hello, > > On Thu, 8 Apr 2021, Andrey Bugaevskiy wrote: > > >Hi, > > > >I'm using makecontext/swapcontext to migrate contexts between threads > >and this sometimes leads to getting incorrect errno values. > > This is not supported by libucontext. > > >Investigating further I've noticed that __errno_location > >is marked __attribute__((const)). > >This causes optimizers to assume that errno address never changes > >in the scope of the function which is not the case in my scenario. > > > >Namely, this code: > > > >int test(ucontext_t* old_ctx, const ucontext_t* new_ctx) { > > int err_before = errno; > > swapcontext(old_ctx, new_ctx); > > int err_after = errno; > > return err_before | err_after; // do not optimize out > >} > > > >translates with -O1 to something like this: > > > >0000000000001109 : > >1109: endbr64 > >110d: push %r13 > >110f: push %r12 > >1111: push %rbp > >1112: push %rbx > >1113: sub $0x8,%rsp > >1117: mov %rdi,%r12 > >111a: mov %rsi,%r13 > >111d: callq 1030 <__errno_location@plt> > >1122: mov %rax,%rbx > >1125: mov (%rax),%ebp > >1127: mov %r13,%rsi > >112a: mov %r12,%rdi > >112d: callq 1020 > >1132: mov %ebp,%eax > >1134: or (%rbx),%eax > >1136: add $0x8,%rsp > >113a: pop %rbx > >113b: pop %rbp > >113c: pop %r12 > >113e: pop %r13 > >1140: retq > > > >errno location is being stored to a register and then reused. > >However a call to __errno_location after swapcontext is expected to > >return a different address if the context have been swapped back > >into another thread. > >There are a couple of similarly affected functions (pthread_self, > >__h_errno_location). > > > >Removing __attribute__((const)) or changing it > >to __attribute__((pure)) resolves the problem in newly compiled code. > > I believe these values use TLS (but not 100% sure, at least in > uClibc they do). libucontext is not aware of TLS, and so clobbers > the TLS register. You could modify libucontext to add awareness of > the TLS register, but I don't think we would accept a patch for > that. Note that whether the "TLS register" is swapped or preserved is partly a function of whether it's userspace or kernelspace. For example on powerpc where it's in a general purpose register, the ucontext functions could be swapping it (but IMO shouldn't; this would break even worse by changing the "identity" of the thread when a programmer commits this kind of UB). On x86 where it's kernel state in segment descriptors (same descriptor value refers to a different segment in each thread context) they really can't swap it without a lot of hackery. Rich