1 commit 1b0cdc8700d29ef018bf226d74b2b58b23bce91c
2 Author: Rich Felker <dalias@aerifal.cx>
3 Date: Tue Jun 16 07:11:19 2015 +0000
5 refactor stdio open file list handling, move it out of global libc struct
7 functions which open in-memory FILE stream variants all shared a tail
8 with __fdopen, adding the FILE structure to stdio's open file list.
9 replacing this common tail with a function call reduces code size and
10 duplication of logic. the list is also partially encapsulated now.
12 function signatures were chosen to facilitate tail call optimization
13 and reduce the need for additional accessor functions.
15 with these changes, static linked programs that do not use stdio no
16 longer have an open file list at all.
18 commit f22a9edaf8a6f2ca1d314d18b3785558279a5c03
19 Author: Rich Felker <dalias@aerifal.cx>
20 Date: Tue Jun 16 06:18:00 2015 +0000
22 byte-based C locale, phase 3: make MB_CUR_MAX variable to activate code
24 this patch activates the new byte-based C locale (high bytes treated
25 as abstract code unit "characters" rather than decoded as multibyte
26 characters) by making the value of MB_CUR_MAX depend on the active
27 locale. for the C locale, the LC_CTYPE category pointer is null,
28 yielding a value of 1. all other locales yield a value of 4.
30 commit 16f18d036d9a7bf590ee6eb86785c0a9658220b6
31 Author: Rich Felker <dalias@aerifal.cx>
32 Date: Tue Jun 16 05:35:31 2015 +0000
34 byte-based C locale, phase 2: stdio and iconv (multibyte callers)
36 this patch adjusts libc components which use the multibyte functions
37 internally, and which depend on them operating in a particular
38 encoding, to make the appropriate locale changes before calling them
39 and restore the calling thread's locale afterwards. activating the
40 byte-based C locale without these changes would cause regressions in
43 in the case of iconv, the current implementation was simply using the
44 multibyte functions as UTF-8 conversions. setting a multibyte UTF-8
45 locale for the duration of the iconv operation allows the code to
48 in the case of stdio, POSIX requires that FILE streams have an
49 encoding rule bound at the time of setting wide orientation. as long
50 as all locales, including the C locale, used the same encoding,
51 treating high bytes as UTF-8, there was no need to store an encoding
52 rule as part of the stream's state.
54 a new locale field in the FILE structure points to the locale that
55 should be made active during fgetwc/fputwc/ungetwc on the stream. it
56 cannot point to the locale active at the time the stream becomes
57 oriented, because this locale could be mutable (the global locale) or
58 could be destroyed (locale_t objects produced by newlocale) before the
59 stream is closed. instead, a pointer to the static C or C.UTF-8 locale
60 object added in commit commit aeeac9ca5490d7d90fe061ab72da446c01ddf746
61 is used. this is valid since categories other than LC_CTYPE will not
62 affect these functions.
64 commit 1507ebf837334e9e07cfab1ca1c2e88449069a80
65 Author: Rich Felker <dalias@aerifal.cx>
66 Date: Tue Jun 16 04:44:17 2015 +0000
68 byte-based C locale, phase 1: multibyte character handling functions
70 this patch makes the functions which work directly on multibyte
71 characters treat the high bytes as individual abstract code units
72 rather than as multibyte sequences when MB_CUR_MAX is 1. since
73 MB_CUR_MAX is presently defined as a constant 4, all of the new code
74 added is dead code, and optimizing compilers' code generation should
75 not be affected at all. a future commit will activate the new code.
77 as abstract code units, bytes 0x80 to 0xff are represented by wchar_t
78 values 0xdf80 to 0xdfff, at the end of the surrogates range. this
79 ensures that they will never be misinterpreted as Unicode characters,
80 and that all wctype functions return false for these "characters"
81 without needing locale-specific logic. a high range outside of Unicode
82 such as 0x7fffff80 to 0x7fffffff was also considered, but since C11's
83 char16_t also needs to be able to represent conversions of these
84 bytes, the surrogate range was the natural choice.
86 commit 38e2f727237230300fea6aff68802db04625fd23
87 Author: Rich Felker <dalias@aerifal.cx>
88 Date: Tue Jun 16 04:21:38 2015 +0000
92 btowc is required to interpret its argument by conversion to unsigned
93 char, unless the argument is equal to EOF. since the conversion to
94 produces a non-character value anyway, we can just unconditionally
97 commit ee59c296d56bf26f49f354d6eb32b4b6d4190188
98 Author: Szabolcs Nagy <nsz@port70.net>
99 Date: Wed Jun 3 10:32:14 2015 +0100
101 arm: add vdso support
103 vdso will be available on arm in linux v4.2, the user-space code
104 for it is in kernel commit 8512287a8165592466cb9cb347ba94892e9c56a5
106 commit e3bc22f1eff87b8f029a6ab31f1a269d69e4b053
107 Author: Rich Felker <dalias@aerifal.cx>
108 Date: Sun Jun 14 01:59:02 2015 +0000
110 refactor malloc's expand_heap to share with __simple_malloc
112 this extends the brk/stack collision protection added to full malloc
113 in commit 276904c2f6bde3a31a24ebfa201482601d18b4f9 to also protect the
114 __simple_malloc function used in static-linked programs that don't
115 reference the free function.
117 it also extends support for using mmap when brk fails, which full
118 malloc got in commit 5446303328adf4b4e36d9fba21848e6feb55fab4, to
121 since __simple_malloc may expand the heap by arbitrarily large
122 increments, the stack collision detection is enhanced to detect
123 interval overlap rather than just proximity of a single address to the
124 stack. code size is increased a bit, but this is partly offset by the
125 sharing of code between the two malloc implementations, which due to
126 linking semantics, both get linked in a program that needs the full
127 malloc with realloc/free support.
129 commit 4ef9b828c1f39553a69e0635ac91f0fcadd6e8c6
130 Author: Rich Felker <dalias@aerifal.cx>
131 Date: Sat Jun 13 20:53:02 2015 +0000
133 remove cancellation points in stdio
135 commit 58165923890865a6ac042fafce13f440ee986fd9 added these optional
136 cancellation points on the basis that cancellable stdio could be
137 useful, to unblock threads stuck on stdio operations that will never
138 complete. however, the only way to ensure that cancellation can
139 achieve this is to violate the rules for side effects when
140 cancellation is acted upon, discarding knowledge of any partial data
141 transfer already completed. our implementation exhibited this behavior
142 and was thus non-conforming.
144 in addition to improving correctness, removing these cancellation
145 points moderately reduces code size, and should significantly improve
146 performance on i386, where sysenter/syscall instructions can be used
147 instead of "int $128" for non-cancellable syscalls.
149 commit 536c6d5a4205e2a3f161f2983ce1e0ac3082187d
150 Author: Rich Felker <dalias@aerifal.cx>
151 Date: Sat Jun 13 05:17:16 2015 +0000
153 fix idiom for setting stdio stream orientation to wide
155 the old idiom, f->mode |= f->mode+1, was adapted from the idiom for
156 setting byte orientation, f->mode |= f->mode-1, but the adaptation was
157 incorrect. unless the stream was alreasdy set byte-oriented, this code
158 incremented f->mode each time it was executed, which would eventually
159 lead to overflow. it could be fixed by changing it to f->mode |= 1,
160 but upcoming changes will require slightly more work at the time of
161 wide orientation, so it makes sense to just call fwide. as an
162 optimization in the single-character functions, fwide is only called
163 if the stream is not already wide-oriented.
165 commit f8f565df467c13248104223f99abf7f37cef7584
166 Author: Rich Felker <dalias@aerifal.cx>
167 Date: Sat Jun 13 04:42:38 2015 +0000
169 add printing of null %s arguments as "(null)" in wide printf
171 this is undefined, but supported in our implementation of the normal
172 printf, so for consistency the wide variant should support it too.
174 commit f9e25d813860d53cd1e9b6145cc63375d2fe2529
175 Author: Rich Felker <dalias@aerifal.cx>
176 Date: Sat Jun 13 04:37:27 2015 +0000
178 add %m support to wide printf
180 commit ec634aad91f57479ef17525e33ed446c780a61f4
181 Author: Rich Felker <dalias@aerifal.cx>
182 Date: Thu Jun 11 05:01:04 2015 +0000
186 commit c30cbcb0a646b1f13a22c645616dce624465b883
187 Author: Rich Felker <dalias@aerifal.cx>
188 Date: Wed Jun 10 02:27:40 2015 +0000
190 implement arch-generic version of __unmapself
192 this can be used to put off writing an asm version of __unmapself for
193 new archs, or as a permanent solution on archs where it's not
194 practical or even possible to run momentarily with no stack.
196 the concept here is simple: the caller takes a lock on a global shared
197 stack and uses it to make the munmap and exit syscalls. the only trick
198 is unlocking, which must be done after the thread exits, and this is
199 achieved by using the set_tid_address syscall to have the kernel zero
200 and futex-wake the lock word as part of the exit syscall.
202 commit 276904c2f6bde3a31a24ebfa201482601d18b4f9
203 Author: Rich Felker <dalias@aerifal.cx>
204 Date: Tue Jun 9 20:30:35 2015 +0000
206 in malloc, refuse to use brk if it grows into stack
208 the linux/nommu fdpic ELF loader sets up the brk range to overlap
209 entirely with the main thread's stack (but growing from opposite
210 ends), so that the resulting failure mode for malloc is not to return
211 a null pointer but to start returning pointers to memory that overlaps
212 with the caller's stack. needless to say this extremely dangerous and
215 since it's non-trivial to detect execution environments that might be
216 affected by this kernel bug, and since the severity of the bug makes
217 any sort of detection that might yield false-negatives unsafe, we
218 instead check the proximity of the brk to the stack pointer each time
219 the brk is to be expanded. both the main thread's stack (where the
220 real known risk lies) and the calling thread's stack are checked. an
221 arbitrary gap distance of 8 MB is imposed, chosen to be larger than
222 linux default main-thread stack reservation sizes and larger than any
223 reasonable stack configuration on nommu.
225 the effeciveness of this patch relies on an assumption that the amount
226 by which the brk is being grown is smaller than the gap limit, which
227 is always true for malloc's use of brk. reliance on this assumption is
228 why the check is being done in malloc-specific code and not in __brk.
230 commit bd1eaceaa3975bd2a2a34e211cff896affaecadf
231 Author: Rich Felker <dalias@aerifal.cx>
232 Date: Tue Jun 9 20:09:27 2015 +0000
234 fix spurious errors from pwd/grp functions when nscd backend is absent
236 for several pwd/grp functions, the only way the caller can distinguish
237 between a successful negative result ("no such user/group") and an
238 internal error is by clearing errno before the call and checking errno
239 afterwards. the nscd backend support code correctly simulated a
240 not-found response on systems where such a backend is not running, but
241 failed to restore errno.
243 this commit also fixed an outdated/incorrect comment.
245 commit 75ce4503950621b11fcc7f1fd1187dbcf3cde312
246 Author: Rich Felker <dalias@aerifal.cx>
247 Date: Sun Jun 7 20:55:23 2015 +0000
249 fix regression in pre-v7 arm on kernels with kuser helper removed
251 the arm atomics/TLS runtime selection code is called from
252 __set_thread_area and depends on having libc.auxv and __hwcap
253 available. commit 71f099cb7db821c51d8f39dfac622c61e54d794c moved the
254 first call to __set_thread_area to the top of dynamic linking stage 3,
255 before this data is made available, causing the runtime detection code
256 to always see __hwcap as zero and thereby select the atomics/TLS
257 implementations based on kuser helper.
259 upcoming work on superh will use similar runtime detection.
261 ideally this early-init code should be cleanly refactored and shared
262 between the dynamic linker and static-linked startup.
264 commit 32f3c4f70633488550c29a2444f819aafdf345ff
265 Author: Rich Felker <dalias@aerifal.cx>
266 Date: Sun Jun 7 03:09:16 2015 +0000
268 add multiple inclusion guard to locale_impl.h
270 commit 04b8360adbb6487f61aa0c00e53ec3a90a5a0d29
271 Author: Rich Felker <dalias@aerifal.cx>
272 Date: Sun Jun 7 02:59:49 2015 +0000
274 remove redefinition of MB_CUR_MAX in locale_impl.h
276 unless/until the byte-based C locale is implemented, defining
277 MB_CUR_MAX to 1 in the C locale is wrong. no internal code currently
278 uses the MB_CUR_MAX macro, but having it defined inconsistently is
279 error-prone. applications get the value from stdlib.h and were
282 commit 16bf466532d7328e971012b0731ad493b017ad29
283 Author: Rich Felker <dalias@aerifal.cx>
284 Date: Sat Jun 6 18:53:02 2015 +0000
286 make static C and C.UTF-8 locales available outside of newlocale
288 commit 312eea2ea4f4363fb01b73660c08bfcf43dd3bb4
289 Author: Rich Felker <dalias@aerifal.cx>
290 Date: Sat Jun 6 18:20:30 2015 +0000
292 remove another invalid skip of locking in ungetwc
294 commit 3d7e32d28dc9962e9efc1c317c5b44b5b2df3008
295 Author: Rich Felker <dalias@aerifal.cx>
296 Date: Sat Jun 6 18:16:22 2015 +0000
298 add macro version of ctype.h isascii function
300 presumably internal code (ungetwc and fputwc) was written assuming a
301 macro implementation existed; otherwise use of isascii is just a
304 commit 7e816a6487932cbb3cb71d94b609e50e81f4e5bf
305 Author: Rich Felker <dalias@aerifal.cx>
306 Date: Sat Jun 6 18:11:17 2015 +0000
308 remove invalid skip of locking in ungetwc
310 aside from being invalid, the early check only optimized the error
311 case, and likely pessimized the common case by separating the
312 two branches on isascii(c) at opposite ends of the function.
314 commit 63f4b9f18f3674124d8bcb119739fec85e6da005
315 Author: Timo Teräs <timo.teras@iki.fi>
316 Date: Fri Jun 5 10:39:42 2015 +0300
318 fix uselocale((locale_t)0) not to modify locale
320 commit 68630b55c0c7219fe9df70dc28ffbf9efc8021d8 made the new locale to
321 be assigned unconditonally resulting in crashes later on.
323 --- a/arch/arm/syscall_arch.h
324 +++ b/arch/arm/syscall_arch.h
325 @@ -72,3 +72,7 @@ static inline long __syscall6(long n, lo
326 register long r5 __asm__("r5") = f;
327 __asm_syscall("r"(r7), "0"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r5));
331 +#define VDSO_CGT_SYM "__vdso_clock_gettime"
332 +#define VDSO_CGT_VER "LINUX_2.6"
333 --- a/include/ctype.h
334 +++ b/include/ctype.h
335 @@ -64,6 +64,7 @@ int isascii(int);
337 #define _tolower(a) ((a)|0x20)
338 #define _toupper(a) ((a)&0x5f)
339 +#define isascii(a) (0 ? isascii(a) : (unsigned)(a) < 128)
343 --- a/include/stdlib.h
344 +++ b/include/stdlib.h
345 @@ -76,7 +76,8 @@ size_t wcstombs (char *__restrict, const
346 #define EXIT_FAILURE 1
347 #define EXIT_SUCCESS 0
349 -#define MB_CUR_MAX ((size_t)+4)
350 +size_t __ctype_get_mb_cur_max(void);
351 +#define MB_CUR_MAX (__ctype_get_mb_cur_max())
353 #define RAND_MAX (0x7fffffff)
355 --- a/src/ctype/__ctype_get_mb_cur_max.c
356 +++ b/src/ctype/__ctype_get_mb_cur_max.c
360 +#include "locale_impl.h"
362 size_t __ctype_get_mb_cur_max()
367 --- a/src/ctype/isascii.c
368 +++ b/src/ctype/isascii.c
375 --- a/src/internal/libc.h
376 +++ b/src/internal/libc.h
377 @@ -17,8 +17,6 @@ struct __libc {
379 volatile int threads_minus_1;
382 - volatile int ofl_lock[2];
385 struct __locale_struct global_locale;
386 --- a/src/internal/locale_impl.h
387 +++ b/src/internal/locale_impl.h
389 +#ifndef _LOCALE_IMPL_H
390 +#define _LOCALE_IMPL_H
395 @@ -12,6 +15,10 @@ struct __locale_map {
396 const struct __locale_map *next;
399 +extern const struct __locale_map __c_dot_utf8;
400 +extern const struct __locale_struct __c_locale;
401 +extern const struct __locale_struct __c_dot_utf8_locale;
403 const struct __locale_map *__get_locale(int, const char *);
404 const char *__mo_lookup(const void *, size_t, const char *);
405 const char *__lctrans(const char *, const struct __locale_map *);
406 @@ -20,9 +27,14 @@ const char *__lctrans_cur(const char *);
407 #define LCTRANS(msg, lc, loc) __lctrans(msg, (loc)->cat[(lc)])
408 #define LCTRANS_CUR(msg) __lctrans_cur(msg)
410 +#define C_LOCALE ((locale_t)&__c_locale)
411 +#define UTF8_LOCALE ((locale_t)&__c_dot_utf8_locale)
413 #define CURRENT_LOCALE (__pthread_self()->locale)
415 #define CURRENT_UTF8 (!!__pthread_self()->locale->cat[LC_CTYPE])
418 #define MB_CUR_MAX (CURRENT_UTF8 ? 4 : 1)
421 --- a/src/internal/stdio_impl.h
422 +++ b/src/internal/stdio_impl.h
423 @@ -47,6 +47,7 @@ struct _IO_FILE {
424 unsigned char *shend;
426 FILE *prev_locked, *next_locked;
427 + struct __locale_struct *locale;
430 size_t __stdio_read(FILE *, unsigned char *, size_t);
431 @@ -75,8 +76,9 @@ int __putc_unlocked(int, FILE *);
432 FILE *__fdopen(int, const char *);
433 int __fmodeflags(const char *);
435 -#define OFLLOCK() LOCK(libc.ofl_lock)
436 -#define OFLUNLOCK() UNLOCK(libc.ofl_lock)
437 +FILE *__ofl_add(FILE *f);
438 +FILE **__ofl_lock(void);
439 +void __ofl_unlock(void);
441 #define feof(f) ((f)->flags & F_EOF)
442 #define ferror(f) ((f)->flags & F_ERR)
443 --- a/src/ldso/dynlink.c
444 +++ b/src/ldso/dynlink.c
445 @@ -1192,6 +1192,17 @@ _Noreturn void __dls3(size_t *sp)
446 char **argv_orig = argv;
447 char **envp = argv+argc+1;
449 + /* Find aux vector just past environ[] and use it to initialize
450 + * global data that may be needed before we can make syscalls. */
452 + for (i=argc+1; argv[i]; i++);
453 + libc.auxv = auxv = (void *)(argv+i+1);
454 + decode_vec(auxv, aux, AUX_CNT);
455 + __hwcap = aux[AT_HWCAP];
456 + libc.page_size = aux[AT_PAGESZ];
457 + libc.secure = ((aux[0]&0x7800)!=0x7800 || aux[AT_UID]!=aux[AT_EUID]
458 + || aux[AT_GID]!=aux[AT_EGID] || aux[AT_SECURE]);
460 /* Setup early thread pointer in builtin_tls for ldso/libc itself to
461 * use during dynamic linking. If possible it will also serve as the
462 * thread pointer at runtime. */
463 @@ -1200,25 +1211,11 @@ _Noreturn void __dls3(size_t *sp)
467 - /* Find aux vector just past environ[] */
468 - for (i=argc+1; argv[i]; i++)
469 - if (!memcmp(argv[i], "LD_LIBRARY_PATH=", 16))
470 - env_path = argv[i]+16;
471 - else if (!memcmp(argv[i], "LD_PRELOAD=", 11))
472 - env_preload = argv[i]+11;
473 - auxv = (void *)(argv+i+1);
475 - decode_vec(auxv, aux, AUX_CNT);
477 /* Only trust user/env if kernel says we're not suid/sgid */
478 - if ((aux[0]&0x7800)!=0x7800 || aux[AT_UID]!=aux[AT_EUID]
479 - || aux[AT_GID]!=aux[AT_EGID] || aux[AT_SECURE]) {
483 + if (!libc.secure) {
484 + env_path = getenv("LD_LIBRARY_PATH");
485 + env_preload = getenv("LD_PRELOAD");
487 - libc.page_size = aux[AT_PAGESZ];
490 /* If the main program was already loaded by the kernel,
491 * AT_PHDR will point to some location other than the dynamic
493 +++ b/src/locale/c_locale.c
495 +#include "locale_impl.h"
498 +static const uint32_t empty_mo[] = { 0x950412de, 0, -1, -1, -1 };
500 +const struct __locale_map __c_dot_utf8 = {
502 + .map_size = sizeof empty_mo,
506 +const struct __locale_struct __c_locale = { 0 };
507 +const struct __locale_struct __c_dot_utf8_locale = {
508 + .cat[LC_CTYPE] = &__c_dot_utf8
510 --- a/src/locale/iconv.c
511 +++ b/src/locale/iconv.c
516 +#include "locale_impl.h"
518 #define UTF_32BE 0300
519 #define UTF_16LE 0301
520 @@ -165,9 +166,12 @@ size_t iconv(iconv_t cd0, char **restric
522 unsigned char type = map[-1];
523 unsigned char totype = tomap[-1];
524 + locale_t *ploc = &CURRENT_LOCALE, loc = *ploc;
526 if (!in || !*in || !*inb) return 0;
528 + *ploc = UTF8_LOCALE;
530 for (; *inb; *in+=l, *inb-=l) {
531 c = *(unsigned char *)*in;
533 @@ -431,6 +435,7 @@ size_t iconv(iconv_t cd0, char **restric
541 @@ -445,5 +450,6 @@ starved:
548 --- a/src/locale/langinfo.c
549 +++ b/src/locale/langinfo.c
550 @@ -33,7 +33,8 @@ char *__nl_langinfo_l(nl_item item, loca
551 int idx = item & 65535;
554 - if (item == CODESET) return "UTF-8";
555 + if (item == CODESET)
556 + return MB_CUR_MAX==1 ? "UTF-8-CODE-UNITS" : "UTF-8";
560 --- a/src/locale/locale_map.c
561 +++ b/src/locale/locale_map.c
562 @@ -24,14 +24,6 @@ static const char envvars[][12] = {
566 -static const uint32_t empty_mo[] = { 0x950412de, 0, -1, -1, -1 };
568 -const struct __locale_map __c_dot_utf8 = {
570 - .map_size = sizeof empty_mo,
574 const struct __locale_map *__get_locale(int cat, const char *val)
577 @@ -107,8 +99,8 @@ const struct __locale_map *__get_locale(
578 * sake of being able to do message translations at the
579 * application level. */
580 if (!new && (new = malloc(sizeof *new))) {
581 - new->map = empty_mo;
582 - new->map_size = sizeof empty_mo;
583 + new->map = __c_dot_utf8.map;
584 + new->map_size = __c_dot_utf8.map_size;
585 memcpy(new->name, val, n);
587 new->next = loc_head;
588 --- a/src/locale/newlocale.c
589 +++ b/src/locale/newlocale.c
591 #include "locale_impl.h"
594 -extern const struct __locale_map __c_dot_utf8;
596 -static const struct __locale_struct c_locale = { 0 };
597 -static const struct __locale_struct c_dot_utf8_locale = {
598 - .cat[LC_CTYPE] = &__c_dot_utf8
601 int __loc_is_allocated(locale_t loc)
603 - return loc && loc != &c_locale && loc != &c_dot_utf8_locale;
604 + return loc && loc != C_LOCALE && loc != UTF8_LOCALE;
607 locale_t __newlocale(int mask, const char *name, locale_t loc)
608 @@ -44,9 +37,9 @@ locale_t __newlocale(int mask, const cha
612 - return (locale_t)&c_locale;
613 - if (j==1 && tmp.cat[LC_CTYPE]==c_dot_utf8_locale.cat[LC_CTYPE])
614 - return (locale_t)&c_dot_utf8_locale;
616 + if (j==1 && tmp.cat[LC_CTYPE]==&__c_dot_utf8)
617 + return UTF8_LOCALE;
619 if ((loc = malloc(sizeof *loc))) *loc = tmp;
621 --- a/src/locale/uselocale.c
622 +++ b/src/locale/uselocale.c
623 @@ -8,9 +8,7 @@ locale_t __uselocale(locale_t new)
624 locale_t old = self->locale;
625 locale_t global = &libc.global_locale;
627 - if (new == LC_GLOBAL_LOCALE) new = global;
629 - self->locale = new;
630 + if (new) self->locale = new == LC_GLOBAL_LOCALE ? global : new;
632 return old == global ? LC_GLOBAL_LOCALE : old;
635 +++ b/src/malloc/expand_heap.c
640 +#include <sys/mman.h>
642 +#include "syscall.h"
644 +/* This function returns true if the interval [old,new]
645 + * intersects the 'len'-sized interval below &libc.auxv
646 + * (interpreted as the main-thread stack) or below &b
647 + * (the current stack). It is used to defend against
648 + * buggy brk implementations that can cross the stack. */
650 +static int traverses_stack_p(uintptr_t old, uintptr_t new)
652 + const uintptr_t len = 8<<20;
655 + b = (uintptr_t)libc.auxv;
656 + a = b > len ? b-len : 0;
657 + if (new>a && old<b) return 1;
660 + a = b > len ? b-len : 0;
661 + if (new>a && old<b) return 1;
666 +void *__mmap(void *, size_t, int, int, int, off_t);
668 +/* Expand the heap in-place if brk can be used, or otherwise via mmap,
669 + * using an exponential lower bound on growth by mmap to make
670 + * fragmentation asymptotically irrelevant. The size argument is both
671 + * an input and an output, since the caller needs to know the size
672 + * allocated, which will be larger than requested due to page alignment
673 + * and mmap minimum size rules. The caller is responsible for locking
674 + * to prevent concurrent calls. */
676 +void *__expand_heap(size_t *pn)
678 + static uintptr_t brk;
679 + static unsigned mmap_step;
682 + if (n > SIZE_MAX/2 - PAGE_SIZE) {
686 + n += -n & PAGE_SIZE-1;
689 + brk = __syscall(SYS_brk, 0);
690 + brk += -brk & PAGE_SIZE-1;
693 + if (n < SIZE_MAX-brk && !traverses_stack_p(brk, brk+n)
694 + && __syscall(SYS_brk, brk+n)==brk+n) {
697 + return (void *)(brk-n);
700 + size_t min = (size_t)PAGE_SIZE << mmap_step/2;
701 + if (n < min) n = min;
702 + void *area = __mmap(0, n, PROT_READ|PROT_WRITE,
703 + MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
704 + if (area == MAP_FAILED) return 0;
709 --- a/src/malloc/lite_malloc.c
710 +++ b/src/malloc/lite_malloc.c
715 -uintptr_t __brk(uintptr_t);
719 +void *__expand_heap(size_t *);
721 void *__simple_malloc(size_t n)
723 - static uintptr_t cur, brk;
724 - uintptr_t base, new;
725 + static char *cur, *end;
726 static volatile int lock[2];
728 + size_t align=1, pad;
732 - if (n > SIZE_MAX/2) goto toobig;
734 while (align<n && align<ALIGN)
736 - n = n + align - 1 & -align;
739 - if (!cur) cur = brk = __brk(0)+16;
740 - base = cur + align-1 & -align;
741 - if (n > SIZE_MAX - PAGE_SIZE - base) goto fail;
742 - if (base+n > brk) {
743 - new = base+n + PAGE_SIZE-1 & -PAGE_SIZE;
744 - if (__brk(new) != new) goto fail;
750 - return (void *)base;
751 + pad = -(uintptr_t)cur & align-1;
753 + if (n <= SIZE_MAX/2 + ALIGN) n += pad;
757 + char *new = __expand_heap(&m);
780 weak_alias(__simple_malloc, malloc);
781 --- a/src/malloc/malloc.c
782 +++ b/src/malloc/malloc.c
784 #define inline inline __attribute__((always_inline))
787 -uintptr_t __brk(uintptr_t);
788 void *__mmap(void *, size_t, int, int, int, off_t);
789 int __munmap(void *, size_t);
790 void *__mremap(void *, size_t, size_t, int, ...);
791 @@ -31,13 +30,9 @@ struct bin {
797 volatile uint64_t binmap;
799 - volatile int brk_lock[2];
800 volatile int free_lock[2];
801 - unsigned mmap_step;
805 @@ -152,69 +147,52 @@ void __dump_heap(int x)
809 +void *__expand_heap(size_t *);
811 static struct chunk *expand_heap(size_t n)
814 + static int heap_lock[2];
820 - lock(mal.brk_lock);
823 - mal.brk = __brk(0);
825 - mal.brk = mal.brk + PAGE_SIZE-1 & -PAGE_SIZE;
827 - mal.brk = mal.brk + 2*SIZE_ALIGN-1 & -SIZE_ALIGN;
828 - mal.heap = (void *)mal.brk;
830 + /* The argument n already accounts for the caller's chunk
831 + * overhead needs, but if the heap can't be extended in-place,
832 + * we need room for an extra zero-sized sentinel chunk. */
837 + p = __expand_heap(&n);
843 - if (n > SIZE_MAX - mal.brk - 2*PAGE_SIZE) goto fail;
844 - new = mal.brk + n + SIZE_ALIGN + PAGE_SIZE - 1 & -PAGE_SIZE;
847 - if (__brk(new) != new) {
848 - size_t min = (size_t)PAGE_SIZE << mal.mmap_step/2;
849 - n += -n & PAGE_SIZE-1;
850 - if (n < min) n = min;
851 - void *area = __mmap(0, n, PROT_READ|PROT_WRITE,
852 - MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
853 - if (area == MAP_FAILED) goto fail;
856 - area = (char *)area + SIZE_ALIGN - OVERHEAD;
858 + /* If not just expanding existing space, we need to make a
859 + * new sentinel chunk below the allocated space. */
861 + /* Valid/safe because of the prologue increment. */
863 + p = (char *)p + SIZE_ALIGN;
864 + w = MEM_TO_CHUNK(p);
865 w->psize = 0 | C_INUSE;
866 - w->csize = n | C_INUSE;
868 - w->psize = n | C_INUSE;
869 - w->csize = 0 | C_INUSE;
871 - unlock(mal.brk_lock);
876 - w = MEM_TO_CHUNK(mal.heap);
877 - w->psize = 0 | C_INUSE;
879 - w = MEM_TO_CHUNK(new);
880 + /* Record new heap end and fill in footer. */
881 + end = (char *)p + n;
882 + w = MEM_TO_CHUNK(end);
883 w->psize = n | C_INUSE;
884 w->csize = 0 | C_INUSE;
886 - w = MEM_TO_CHUNK(mal.brk);
887 + /* Fill in header, which may be new or may be replacing a
888 + * zero-size sentinel header at the old end-of-heap. */
889 + w = MEM_TO_CHUNK(p);
890 w->csize = n | C_INUSE;
893 - unlock(mal.brk_lock);
899 - unlock(mal.brk_lock);
904 static int adjust_size(size_t *n)
905 --- a/src/multibyte/btowc.c
906 +++ b/src/multibyte/btowc.c
911 +#include "internal.h"
915 - return c<128U ? c : EOF;
916 + int b = (unsigned char)c;
917 + return b<128U ? b : (MB_CUR_MAX==1 && c!=EOF) ? CODEUNIT(c) : WEOF;
919 --- a/src/multibyte/internal.h
920 +++ b/src/multibyte/internal.h
921 @@ -23,3 +23,10 @@ extern const uint32_t bittab[];
926 +/* Arbitrary encoding for representing code units instead of characters. */
927 +#define CODEUNIT(c) (0xdfff & (signed char)(c))
928 +#define IS_CODEUNIT(c) ((unsigned)(c)-0xdf80 < 0x80)
930 +/* Get inline definition of MB_CUR_MAX. */
931 +#include "locale_impl.h"
932 --- a/src/multibyte/mbrtowc.c
933 +++ b/src/multibyte/mbrtowc.c
941 #include "internal.h"
942 @@ -27,6 +28,7 @@ size_t mbrtowc(wchar_t *restrict wc, con
945 if (*s < 0x80) return !!(*wc = *s);
946 + if (MB_CUR_MAX==1) return (*wc = CODEUNIT(*s)), 1;
947 if (*s-SA > SB-SA) goto ilseq;
948 c = bittab[*s++-SA]; n--;
950 --- a/src/multibyte/mbsrtowcs.c
951 +++ b/src/multibyte/mbsrtowcs.c
958 #include "internal.h"
960 size_t mbsrtowcs(wchar_t *restrict ws, const char **restrict src, size_t wn, mbstate_t *restrict st)
961 @@ -24,6 +26,23 @@ size_t mbsrtowcs(wchar_t *restrict ws, c
965 + if (MB_CUR_MAX==1) {
966 + if (!ws) return strlen((const char *)s);
969 + *src = (const void *)s;
974 + *ws++ = CODEUNIT(c);
983 if (*s-1u < 0x7f && (uintptr_t)s%4 == 0) {
984 while (!(( *(uint32_t*)s | *(uint32_t*)s-0x01010101) & 0x80808080)) {
985 --- a/src/multibyte/mbtowc.c
986 +++ b/src/multibyte/mbtowc.c
994 #include "internal.h"
995 @@ -19,6 +20,7 @@ int mbtowc(wchar_t *restrict wc, const c
996 if (!wc) wc = &dummy;
998 if (*s < 0x80) return !!(*wc = *s);
999 + if (MB_CUR_MAX==1) return (*wc = CODEUNIT(*s)), 1;
1000 if (*s-SA > SB-SA) goto ilseq;
1001 c = bittab[*s++-SA];
1003 --- a/src/multibyte/wcrtomb.c
1004 +++ b/src/multibyte/wcrtomb.c
1009 +#include <stdlib.h>
1012 +#include "internal.h"
1014 size_t wcrtomb(char *restrict s, wchar_t wc, mbstate_t *restrict st)
1016 @@ -13,6 +15,13 @@ size_t wcrtomb(char *restrict s, wchar_t
1017 if ((unsigned)wc < 0x80) {
1020 + } else if (MB_CUR_MAX == 1) {
1021 + if (!IS_CODEUNIT(wc)) {
1027 } else if ((unsigned)wc < 0x800) {
1028 *s++ = 0xc0 | (wc>>6);
1029 *s = 0x80 | (wc&0x3f);
1030 --- a/src/multibyte/wctob.c
1031 +++ b/src/multibyte/wctob.c
1035 +#include <stdlib.h>
1036 +#include "internal.h"
1040 if (c < 128U) return c;
1041 + if (MB_CUR_MAX==1 && IS_CODEUNIT(c)) return (unsigned char)c;
1044 --- a/src/passwd/nscd_query.c
1045 +++ b/src/passwd/nscd_query.c
1046 @@ -32,6 +32,7 @@ FILE *__nscd_query(int32_t req, const ch
1050 + int errno_save = errno;
1054 @@ -50,11 +51,14 @@ retry:
1057 if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
1058 - /* If there isn't a running nscd we return -1 to indicate that
1059 - * that is precisely what happened
1061 - if (errno == EACCES || errno == ECONNREFUSED || errno == ENOENT)
1062 + /* If there isn't a running nscd we simulate a "not found"
1063 + * result and the caller is responsible for calling
1064 + * fclose on the (unconnected) socket. The value of
1065 + * errno must be left unchanged in this case. */
1066 + if (errno == EACCES || errno == ECONNREFUSED || errno == ENOENT) {
1067 + errno = errno_save;
1074 +++ b/src/process/sh/vfork.s
1078 +.type __vfork,@function
1079 +.type vfork,@function
1097 + .hidden __syscall_ret
1098 +1: .long __syscall_ret@PLT-(2b+4-.)
1099 --- a/src/regex/fnmatch.c
1100 +++ b/src/regex/fnmatch.c
1105 +#include "locale_impl.h"
1108 #define UNMATCHABLE -2
1109 @@ -229,7 +230,7 @@ static int fnmatch_internal(const char *
1110 * On illegal sequences we may get it wrong, but in that case
1111 * we necessarily have a matching failure anyway. */
1112 for (s=endstr; s>str && tailcnt; tailcnt--) {
1113 - if (s[-1] < 128U) s--;
1114 + if (s[-1] < 128U || MB_CUR_MAX==1) s--;
1115 else while ((unsigned char)*--s-0x80U<0x40 && s>str);
1117 if (tailcnt) return FNM_NOMATCH;
1118 --- a/src/stdio/__fdopen.c
1119 +++ b/src/stdio/__fdopen.c
1120 @@ -54,13 +54,7 @@ FILE *__fdopen(int fd, const char *mode)
1121 if (!libc.threaded) f->lock = -1;
1123 /* Add new FILE to open file list */
1125 - f->next = libc.ofl_head;
1126 - if (libc.ofl_head) libc.ofl_head->prev = f;
1127 - libc.ofl_head = f;
1131 + return __ofl_add(f);
1134 weak_alias(__fdopen, fdopen);
1135 --- a/src/stdio/__stdio_exit.c
1136 +++ b/src/stdio/__stdio_exit.c
1137 @@ -16,8 +16,7 @@ static void close_file(FILE *f)
1138 void __stdio_exit(void)
1142 - for (f=libc.ofl_head; f; f=f->next) close_file(f);
1143 + for (f=*__ofl_lock(); f; f=f->next) close_file(f);
1144 close_file(__stdin_used);
1145 close_file(__stdout_used);
1147 --- a/src/stdio/__stdio_read.c
1148 +++ b/src/stdio/__stdio_read.c
1150 #include "stdio_impl.h"
1151 #include <sys/uio.h>
1152 -#include <pthread.h>
1154 -static void cleanup(void *p)
1157 - if (!f->lockcount) __unlockfile(f);
1160 size_t __stdio_read(FILE *f, unsigned char *buf, size_t len)
1162 @@ -16,9 +9,7 @@ size_t __stdio_read(FILE *f, unsigned ch
1166 - pthread_cleanup_push(cleanup, f);
1167 - cnt = syscall_cp(SYS_readv, f->fd, iov, 2);
1168 - pthread_cleanup_pop(0);
1169 + cnt = syscall(SYS_readv, f->fd, iov, 2);
1171 f->flags |= F_EOF ^ ((F_ERR^F_EOF) & cnt);
1173 --- a/src/stdio/__stdio_write.c
1174 +++ b/src/stdio/__stdio_write.c
1176 #include "stdio_impl.h"
1177 #include <sys/uio.h>
1178 -#include <pthread.h>
1180 -static void cleanup(void *p)
1183 - if (!f->lockcount) __unlockfile(f);
1186 size_t __stdio_write(FILE *f, const unsigned char *buf, size_t len)
1188 @@ -19,9 +12,7 @@ size_t __stdio_write(FILE *f, const unsi
1192 - pthread_cleanup_push(cleanup, f);
1193 - cnt = syscall_cp(SYS_writev, f->fd, iov, iovcnt);
1194 - pthread_cleanup_pop(0);
1195 + cnt = syscall(SYS_writev, f->fd, iov, iovcnt);
1197 f->wend = f->buf + f->buf_size;
1198 f->wpos = f->wbase = f->buf;
1199 @@ -34,11 +25,8 @@ size_t __stdio_write(FILE *f, const unsi
1202 if (cnt > iov[0].iov_len) {
1203 - f->wpos = f->wbase = f->buf;
1204 cnt -= iov[0].iov_len;
1206 - } else if (iovcnt == 2) {
1209 iov[0].iov_base = (char *)iov[0].iov_base + cnt;
1210 iov[0].iov_len -= cnt;
1211 --- a/src/stdio/fclose.c
1212 +++ b/src/stdio/fclose.c
1213 @@ -14,11 +14,11 @@ int fclose(FILE *f)
1214 __unlist_locked_file(f);
1216 if (!(perm = f->flags & F_PERM)) {
1218 + FILE **head = __ofl_lock();
1219 if (f->prev) f->prev->next = f->next;
1220 if (f->next) f->next->prev = f->prev;
1221 - if (libc.ofl_head == f) libc.ofl_head = f->next;
1223 + if (*head == f) *head = f->next;
1228 --- a/src/stdio/fflush.c
1229 +++ b/src/stdio/fflush.c
1230 @@ -35,13 +35,12 @@ int fflush(FILE *f)
1232 r = __stdout_used ? fflush(__stdout_used) : 0;
1235 - for (f=libc.ofl_head; f; f=f->next) {
1236 + for (f=*__ofl_lock(); f; f=f->next) {
1238 if (f->wpos > f->wbase) r |= __fflush_unlocked(f);
1246 --- a/src/stdio/fgetwc.c
1247 +++ b/src/stdio/fgetwc.c
1249 #include "stdio_impl.h"
1250 +#include "locale_impl.h"
1254 -wint_t __fgetwc_unlocked(FILE *f)
1255 +static wint_t __fgetwc_unlocked_internal(FILE *f)
1257 mbstate_t st = { 0 };
1259 @@ -10,8 +11,6 @@ wint_t __fgetwc_unlocked(FILE *f)
1263 - f->mode |= f->mode+1;
1265 /* Convert character from buffer if possible */
1266 if (f->rpos < f->rend) {
1267 l = mbrtowc(&wc, (void *)f->rpos, f->rend - f->rpos, &st);
1268 @@ -39,6 +38,16 @@ wint_t __fgetwc_unlocked(FILE *f)
1272 +wint_t __fgetwc_unlocked(FILE *f)
1274 + locale_t *ploc = &CURRENT_LOCALE, loc = *ploc;
1275 + if (f->mode <= 0) fwide(f, 1);
1276 + *ploc = f->locale;
1277 + wchar_t wc = __fgetwc_unlocked_internal(f);
1282 wint_t fgetwc(FILE *f)
1285 --- a/src/stdio/fmemopen.c
1286 +++ b/src/stdio/fmemopen.c
1287 @@ -110,11 +110,5 @@ FILE *fmemopen(void *restrict buf, size_
1289 if (!libc.threaded) f->lock = -1;
1292 - f->next = libc.ofl_head;
1293 - if (libc.ofl_head) libc.ofl_head->prev = f;
1294 - libc.ofl_head = f;
1298 + return __ofl_add(f);
1300 --- a/src/stdio/fopen.c
1301 +++ b/src/stdio/fopen.c
1302 @@ -18,7 +18,7 @@ FILE *fopen(const char *restrict filenam
1303 /* Compute the flags to pass to open() */
1304 flags = __fmodeflags(mode);
1306 - fd = sys_open_cp(filename, flags, 0666);
1307 + fd = sys_open(filename, flags, 0666);
1308 if (fd < 0) return 0;
1309 if (flags & O_CLOEXEC)
1310 __syscall(SYS_fcntl, fd, F_SETFD, FD_CLOEXEC);
1311 --- a/src/stdio/fputwc.c
1312 +++ b/src/stdio/fputwc.c
1314 #include "stdio_impl.h"
1315 +#include "locale_impl.h"
1319 @@ -7,8 +8,10 @@ wint_t __fputwc_unlocked(wchar_t c, FILE
1321 char mbc[MB_LEN_MAX];
1323 + locale_t *ploc = &CURRENT_LOCALE, loc = *ploc;
1325 - f->mode |= f->mode+1;
1326 + if (f->mode <= 0) fwide(f, 1);
1327 + *ploc = f->locale;
1330 c = putc_unlocked(c, f);
1331 @@ -20,6 +23,8 @@ wint_t __fputwc_unlocked(wchar_t c, FILE
1333 if (l < 0 || __fwritex((void *)mbc, l, f) < l) c = WEOF;
1335 + if (c==WEOF) f->flags |= F_ERR;
1340 --- a/src/stdio/fputws.c
1341 +++ b/src/stdio/fputws.c
1343 #include "stdio_impl.h"
1344 +#include "locale_impl.h"
1347 int fputws(const wchar_t *restrict ws, FILE *restrict f)
1349 unsigned char buf[BUFSIZ];
1351 + locale_t *ploc = &CURRENT_LOCALE, loc = *ploc;
1355 - f->mode |= f->mode+1;
1357 + *ploc = f->locale;
1359 while (ws && (l = wcsrtombs((void *)buf, (void*)&ws, sizeof buf, 0))+1 > 1)
1360 if (__fwritex(buf, l, f) < l) {
1369 return l; /* 0 or -1 */
1372 --- a/src/stdio/fwide.c
1373 +++ b/src/stdio/fwide.c
1376 #include "stdio_impl.h"
1378 -#define SH (8*sizeof(int)-1)
1379 -#define NORMALIZE(x) ((x)>>SH | -((-(x))>>SH))
1380 +#include "locale_impl.h"
1382 int fwide(FILE *f, int mode)
1385 - if (!f->mode) f->mode = NORMALIZE(mode);
1387 + if (!f->locale) f->locale = MB_CUR_MAX==1
1388 + ? C_LOCALE : UTF8_LOCALE;
1389 + if (!f->mode) f->mode = mode>0 ? 1 : -1;
1395 +++ b/src/stdio/ofl.c
1397 +#include "stdio_impl.h"
1400 +static FILE *ofl_head;
1401 +static volatile int ofl_lock[2];
1403 +FILE **__ofl_lock()
1409 +void __ofl_unlock()
1414 +++ b/src/stdio/ofl_add.c
1416 +#include "stdio_impl.h"
1418 +FILE *__ofl_add(FILE *f)
1420 + FILE **head = __ofl_lock();
1422 + if (*head) (*head)->prev = f;
1427 --- a/src/stdio/open_memstream.c
1428 +++ b/src/stdio/open_memstream.c
1429 @@ -79,11 +79,5 @@ FILE *open_memstream(char **bufp, size_t
1431 if (!libc.threaded) f->lock = -1;
1434 - f->next = libc.ofl_head;
1435 - if (libc.ofl_head) libc.ofl_head->prev = f;
1436 - libc.ofl_head = f;
1440 + return __ofl_add(f);
1442 --- a/src/stdio/open_wmemstream.c
1443 +++ b/src/stdio/open_wmemstream.c
1444 @@ -81,11 +81,5 @@ FILE *open_wmemstream(wchar_t **bufp, si
1446 if (!libc.threaded) f->lock = -1;
1449 - f->next = libc.ofl_head;
1450 - if (libc.ofl_head) libc.ofl_head->prev = f;
1451 - libc.ofl_head = f;
1455 + return __ofl_add(f);
1457 --- a/src/stdio/ungetwc.c
1458 +++ b/src/stdio/ungetwc.c
1460 #include "stdio_impl.h"
1461 +#include "locale_impl.h"
1465 @@ -8,21 +9,19 @@ wint_t ungetwc(wint_t c, FILE *f)
1467 unsigned char mbc[MB_LEN_MAX];
1470 - if (c == WEOF) return c;
1472 - /* Try conversion early so we can fail without locking if invalid */
1473 - if (!isascii(c) && (l = wctomb((void *)mbc, c)) < 0)
1475 + locale_t *ploc = &CURRENT_LOCALE, loc = *ploc;
1479 - f->mode |= f->mode+1;
1480 + if (f->mode <= 0) fwide(f, 1);
1481 + *ploc = f->locale;
1483 if (!f->rpos) __toread(f);
1484 - if (!f->rpos || f->rpos < f->buf - UNGET + l) {
1485 + if (!f->rpos || f->rpos < f->buf - UNGET + l || c == WEOF ||
1486 + (!isascii(c) && (l = wctomb((void *)mbc, c)) < 0)) {
1493 if (isascii(c)) *--f->rpos = c;
1494 @@ -31,5 +30,6 @@ wint_t ungetwc(wint_t c, FILE *f)
1501 --- a/src/stdio/vfwprintf.c
1502 +++ b/src/stdio/vfwprintf.c
1503 @@ -293,7 +293,10 @@ static int wprintf_core(FILE *f, const w
1504 if ((fl&LEFT_ADJ)) fprintf(f, "%.*s", w-p, "");
1508 + arg.p = strerror(errno);
1510 + if (!arg.p) arg.p = "(null)";
1512 if (p<0) p = INT_MAX;
1513 for (i=l=0; l<p && (i=mbtowc(&wc, bs, MB_LEN_MAX))>0; bs+=i, l++);
1514 @@ -356,7 +359,7 @@ int vfwprintf(FILE *restrict f, const wc
1518 - f->mode |= f->mode+1;
1520 olderr = f->flags & F_ERR;
1522 ret = wprintf_core(f, fmt, &ap2, nl_arg, nl_type);
1523 --- a/src/stdio/vfwscanf.c
1524 +++ b/src/stdio/vfwscanf.c
1525 @@ -104,7 +104,7 @@ int vfwscanf(FILE *restrict f, const wch
1529 - f->mode |= f->mode+1;
1532 for (p=fmt; *p; p++) {
1535 +++ b/src/thread/__unmapself.c
1537 +#include "pthread_impl.h"
1538 +#include "atomic.h"
1539 +#include "syscall.h"
1540 +/* cheat and reuse CRTJMP macro from dynlink code */
1541 +#include "dynlink.h"
1543 +static volatile int lock;
1544 +static void *unmap_base;
1545 +static size_t unmap_size;
1546 +static char shared_stack[256];
1548 +static void do_unmap()
1550 + __syscall(SYS_munmap, unmap_base, unmap_size);
1551 + __syscall(SYS_exit);
1554 +void __unmapself(void *base, size_t size)
1556 + int tid=__pthread_self()->tid;
1557 + char *stack = shared_stack + sizeof shared_stack;
1558 + stack -= (uintptr_t)stack % 16;
1559 + while (lock || a_cas(&lock, 0, tid))
1561 + __syscall(SYS_set_tid_address, &lock);
1562 + unmap_base = base;
1563 + unmap_size = size;
1564 + CRTJMP(do_unmap, stack);
1566 --- a/src/thread/pthread_create.c
1567 +++ b/src/thread/pthread_create.c
1568 @@ -191,8 +191,9 @@ int __pthread_create(pthread_t *restrict
1569 if (!libc.can_do_threads) return ENOSYS;
1570 self = __pthread_self();
1571 if (!libc.threaded) {
1572 - for (FILE *f=libc.ofl_head; f; f=f->next)
1573 + for (FILE *f=*__ofl_lock(); f; f=f->next)
1576 init_file_lock(__stdin_used);
1577 init_file_lock(__stdout_used);
1578 init_file_lock(__stderr_used);