5941adc3204ffe3cf8d39b1e699c70fbb4ffa717
[openwrt.git] / toolchain / musl / patches / 001-git-2015-06-16.patch
1 commit 1b0cdc8700d29ef018bf226d74b2b58b23bce91c
2 Author: Rich Felker <dalias@aerifal.cx>
3 Date:   Tue Jun 16 07:11:19 2015 +0000
4
5     refactor stdio open file list handling, move it out of global libc struct
6     
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.
11     
12     function signatures were chosen to facilitate tail call optimization
13     and reduce the need for additional accessor functions.
14     
15     with these changes, static linked programs that do not use stdio no
16     longer have an open file list at all.
17
18 commit f22a9edaf8a6f2ca1d314d18b3785558279a5c03
19 Author: Rich Felker <dalias@aerifal.cx>
20 Date:   Tue Jun 16 06:18:00 2015 +0000
21
22     byte-based C locale, phase 3: make MB_CUR_MAX variable to activate code
23     
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.
29
30 commit 16f18d036d9a7bf590ee6eb86785c0a9658220b6
31 Author: Rich Felker <dalias@aerifal.cx>
32 Date:   Tue Jun 16 05:35:31 2015 +0000
33
34     byte-based C locale, phase 2: stdio and iconv (multibyte callers)
35     
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
41     stdio and iconv.
42     
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
46     continue working.
47     
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.
53     
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.
63
64 commit 1507ebf837334e9e07cfab1ca1c2e88449069a80
65 Author: Rich Felker <dalias@aerifal.cx>
66 Date:   Tue Jun 16 04:44:17 2015 +0000
67
68     byte-based C locale, phase 1: multibyte character handling functions
69     
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.
76     
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.
85
86 commit 38e2f727237230300fea6aff68802db04625fd23
87 Author: Rich Felker <dalias@aerifal.cx>
88 Date:   Tue Jun 16 04:21:38 2015 +0000
89
90     fix btowc corner case
91     
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
95     convert, for now.
96
97 commit ee59c296d56bf26f49f354d6eb32b4b6d4190188
98 Author: Szabolcs Nagy <nsz@port70.net>
99 Date:   Wed Jun 3 10:32:14 2015 +0100
100
101     arm: add vdso support
102     
103     vdso will be available on arm in linux v4.2, the user-space code
104     for it is in kernel commit 8512287a8165592466cb9cb347ba94892e9c56a5
105
106 commit e3bc22f1eff87b8f029a6ab31f1a269d69e4b053
107 Author: Rich Felker <dalias@aerifal.cx>
108 Date:   Sun Jun 14 01:59:02 2015 +0000
109
110     refactor malloc's expand_heap to share with __simple_malloc
111     
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.
116     
117     it also extends support for using mmap when brk fails, which full
118     malloc got in commit 5446303328adf4b4e36d9fba21848e6feb55fab4, to
119     __simple_malloc.
120     
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.
128
129 commit 4ef9b828c1f39553a69e0635ac91f0fcadd6e8c6
130 Author: Rich Felker <dalias@aerifal.cx>
131 Date:   Sat Jun 13 20:53:02 2015 +0000
132
133     remove cancellation points in stdio
134     
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.
143     
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.
148
149 commit 536c6d5a4205e2a3f161f2983ce1e0ac3082187d
150 Author: Rich Felker <dalias@aerifal.cx>
151 Date:   Sat Jun 13 05:17:16 2015 +0000
152
153     fix idiom for setting stdio stream orientation to wide
154     
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.
164
165 commit f8f565df467c13248104223f99abf7f37cef7584
166 Author: Rich Felker <dalias@aerifal.cx>
167 Date:   Sat Jun 13 04:42:38 2015 +0000
168
169     add printing of null %s arguments as "(null)" in wide printf
170     
171     this is undefined, but supported in our implementation of the normal
172     printf, so for consistency the wide variant should support it too.
173
174 commit f9e25d813860d53cd1e9b6145cc63375d2fe2529
175 Author: Rich Felker <dalias@aerifal.cx>
176 Date:   Sat Jun 13 04:37:27 2015 +0000
177
178     add %m support to wide printf
179
180 commit ec634aad91f57479ef17525e33ed446c780a61f4
181 Author: Rich Felker <dalias@aerifal.cx>
182 Date:   Thu Jun 11 05:01:04 2015 +0000
183
184     add sh asm for vfork
185
186 commit c30cbcb0a646b1f13a22c645616dce624465b883
187 Author: Rich Felker <dalias@aerifal.cx>
188 Date:   Wed Jun 10 02:27:40 2015 +0000
189
190     implement arch-generic version of __unmapself
191     
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.
195     
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.
201
202 commit 276904c2f6bde3a31a24ebfa201482601d18b4f9
203 Author: Rich Felker <dalias@aerifal.cx>
204 Date:   Tue Jun 9 20:30:35 2015 +0000
205
206     in malloc, refuse to use brk if it grows into stack
207     
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
213     makes brk unusable.
214     
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.
224     
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.
229
230 commit bd1eaceaa3975bd2a2a34e211cff896affaecadf
231 Author: Rich Felker <dalias@aerifal.cx>
232 Date:   Tue Jun 9 20:09:27 2015 +0000
233
234     fix spurious errors from pwd/grp functions when nscd backend is absent
235     
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.
242     
243     this commit also fixed an outdated/incorrect comment.
244
245 commit 75ce4503950621b11fcc7f1fd1187dbcf3cde312
246 Author: Rich Felker <dalias@aerifal.cx>
247 Date:   Sun Jun 7 20:55:23 2015 +0000
248
249     fix regression in pre-v7 arm on kernels with kuser helper removed
250     
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.
258     
259     upcoming work on superh will use similar runtime detection.
260     
261     ideally this early-init code should be cleanly refactored and shared
262     between the dynamic linker and static-linked startup.
263
264 commit 32f3c4f70633488550c29a2444f819aafdf345ff
265 Author: Rich Felker <dalias@aerifal.cx>
266 Date:   Sun Jun 7 03:09:16 2015 +0000
267
268     add multiple inclusion guard to locale_impl.h
269
270 commit 04b8360adbb6487f61aa0c00e53ec3a90a5a0d29
271 Author: Rich Felker <dalias@aerifal.cx>
272 Date:   Sun Jun 7 02:59:49 2015 +0000
273
274     remove redefinition of MB_CUR_MAX in locale_impl.h
275     
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
280     unaffected.
281
282 commit 16bf466532d7328e971012b0731ad493b017ad29
283 Author: Rich Felker <dalias@aerifal.cx>
284 Date:   Sat Jun 6 18:53:02 2015 +0000
285
286     make static C and C.UTF-8 locales available outside of newlocale
287
288 commit 312eea2ea4f4363fb01b73660c08bfcf43dd3bb4
289 Author: Rich Felker <dalias@aerifal.cx>
290 Date:   Sat Jun 6 18:20:30 2015 +0000
291
292     remove another invalid skip of locking in ungetwc
293
294 commit 3d7e32d28dc9962e9efc1c317c5b44b5b2df3008
295 Author: Rich Felker <dalias@aerifal.cx>
296 Date:   Sat Jun 6 18:16:22 2015 +0000
297
298     add macro version of ctype.h isascii function
299     
300     presumably internal code (ungetwc and fputwc) was written assuming a
301     macro implementation existed; otherwise use of isascii is just a
302     pessimization.
303
304 commit 7e816a6487932cbb3cb71d94b609e50e81f4e5bf
305 Author: Rich Felker <dalias@aerifal.cx>
306 Date:   Sat Jun 6 18:11:17 2015 +0000
307
308     remove invalid skip of locking in ungetwc
309     
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.
313
314 commit 63f4b9f18f3674124d8bcb119739fec85e6da005
315 Author: Timo Teräs <timo.teras@iki.fi>
316 Date:   Fri Jun 5 10:39:42 2015 +0300
317
318     fix uselocale((locale_t)0) not to modify locale
319     
320     commit 68630b55c0c7219fe9df70dc28ffbf9efc8021d8 made the new locale to
321     be assigned unconditonally resulting in crashes later on.
322
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));
328  }
329 +
330 +#define VDSO_USEFUL
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);
336  int   toascii(int);
337  #define _tolower(a) ((a)|0x20)
338  #define _toupper(a) ((a)&0x5f)
339 +#define isascii(a) (0 ? isascii(a) : (unsigned)(a) < 128)
340  
341  #endif
342  
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
348  
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())
352  
353  #define RAND_MAX (0x7fffffff)
354  
355 --- a/src/ctype/__ctype_get_mb_cur_max.c
356 +++ b/src/ctype/__ctype_get_mb_cur_max.c
357 @@ -1,6 +1,7 @@
358 -#include <stddef.h>
359 +#include <stdlib.h>
360 +#include "locale_impl.h"
361  
362  size_t __ctype_get_mb_cur_max()
363  {
364 -       return 4;
365 +       return MB_CUR_MAX;
366  }
367 --- a/src/ctype/isascii.c
368 +++ b/src/ctype/isascii.c
369 @@ -1,4 +1,5 @@
370  #include <ctype.h>
371 +#undef isascii
372  
373  int isascii(int c)
374  {
375 --- a/src/internal/libc.h
376 +++ b/src/internal/libc.h
377 @@ -17,8 +17,6 @@ struct __libc {
378         int secure;
379         volatile int threads_minus_1;
380         size_t *auxv;
381 -       FILE *ofl_head;
382 -       volatile int ofl_lock[2];
383         size_t tls_size;
384         size_t page_size;
385         struct __locale_struct global_locale;
386 --- a/src/internal/locale_impl.h
387 +++ b/src/internal/locale_impl.h
388 @@ -1,3 +1,6 @@
389 +#ifndef _LOCALE_IMPL_H
390 +#define _LOCALE_IMPL_H
391 +
392  #include <locale.h>
393  #include <stdlib.h>
394  #include "libc.h"
395 @@ -12,6 +15,10 @@ struct __locale_map {
396         const struct __locale_map *next;
397  };
398  
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;
402 +
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)
409  
410 +#define C_LOCALE ((locale_t)&__c_locale)
411 +#define UTF8_LOCALE ((locale_t)&__c_dot_utf8_locale)
412 +
413  #define CURRENT_LOCALE (__pthread_self()->locale)
414  
415  #define CURRENT_UTF8 (!!__pthread_self()->locale->cat[LC_CTYPE])
416  
417  #undef MB_CUR_MAX
418  #define MB_CUR_MAX (CURRENT_UTF8 ? 4 : 1)
419 +
420 +#endif
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;
425         off_t shlim, shcnt;
426         FILE *prev_locked, *next_locked;
427 +       struct __locale_struct *locale;
428  };
429  
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 *);
434  
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);
440  
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;
448  
449 +       /* Find aux vector just past environ[] and use it to initialize
450 +        * global data that may be needed before we can make syscalls. */
451 +       __environ = envp;
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]);
459 +
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)
464                 a_crash();
465         }
466  
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);
474 -
475 -       decode_vec(auxv, aux, AUX_CNT);
476 -
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]) {
480 -               env_path = 0;
481 -               env_preload = 0;
482 -               libc.secure = 1;
483 +       if (!libc.secure) {
484 +               env_path = getenv("LD_LIBRARY_PATH");
485 +               env_preload = getenv("LD_PRELOAD");
486         }
487 -       libc.page_size = aux[AT_PAGESZ];
488 -       libc.auxv = auxv;
489  
490         /* If the main program was already loaded by the kernel,
491          * AT_PHDR will point to some location other than the dynamic
492 --- /dev/null
493 +++ b/src/locale/c_locale.c
494 @@ -0,0 +1,15 @@
495 +#include "locale_impl.h"
496 +#include <stdint.h>
497 +
498 +static const uint32_t empty_mo[] = { 0x950412de, 0, -1, -1, -1 };
499 +
500 +const struct __locale_map __c_dot_utf8 = {
501 +       .map = empty_mo,
502 +       .map_size = sizeof empty_mo,
503 +       .name = "C.UTF-8"
504 +};
505 +
506 +const struct __locale_struct __c_locale = { 0 };
507 +const struct __locale_struct __c_dot_utf8_locale = {
508 +       .cat[LC_CTYPE] = &__c_dot_utf8
509 +};
510 --- a/src/locale/iconv.c
511 +++ b/src/locale/iconv.c
512 @@ -5,6 +5,7 @@
513  #include <stdlib.h>
514  #include <limits.h>
515  #include <stdint.h>
516 +#include "locale_impl.h"
517  
518  #define UTF_32BE    0300
519  #define UTF_16LE    0301
520 @@ -165,9 +166,12 @@ size_t iconv(iconv_t cd0, char **restric
521         int err;
522         unsigned char type = map[-1];
523         unsigned char totype = tomap[-1];
524 +       locale_t *ploc = &CURRENT_LOCALE, loc = *ploc;
525  
526         if (!in || !*in || !*inb) return 0;
527  
528 +       *ploc = UTF8_LOCALE;
529 +
530         for (; *inb; *in+=l, *inb-=l) {
531                 c = *(unsigned char *)*in;
532                 l = 1;
533 @@ -431,6 +435,7 @@ size_t iconv(iconv_t cd0, char **restric
534                         break;
535                 }
536         }
537 +       *ploc = loc;
538         return x;
539  ilseq:
540         err = EILSEQ;
541 @@ -445,5 +450,6 @@ starved:
542         x = -1;
543  end:
544         errno = err;
545 +       *ploc = loc;
546         return x;
547  }
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;
552         const char *str;
553  
554 -       if (item == CODESET) return "UTF-8";
555 +       if (item == CODESET)
556 +               return MB_CUR_MAX==1 ? "UTF-8-CODE-UNITS" : "UTF-8";
557         
558         switch (cat) {
559         case LC_NUMERIC:
560 --- a/src/locale/locale_map.c
561 +++ b/src/locale/locale_map.c
562 @@ -24,14 +24,6 @@ static const char envvars[][12] = {
563         "LC_MESSAGES",
564  };
565  
566 -static const uint32_t empty_mo[] = { 0x950412de, 0, -1, -1, -1 };
567 -
568 -const struct __locale_map __c_dot_utf8 = {
569 -       .map = empty_mo,
570 -       .map_size = sizeof empty_mo,
571 -       .name = "C.UTF-8"
572 -};
573 -
574  const struct __locale_map *__get_locale(int cat, const char *val)
575  {
576         static int lock[2];
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);
586                 new->name[n] = 0;
587                 new->next = loc_head;
588 --- a/src/locale/newlocale.c
589 +++ b/src/locale/newlocale.c
590 @@ -3,16 +3,9 @@
591  #include "locale_impl.h"
592  #include "libc.h"
593  
594 -extern const struct __locale_map __c_dot_utf8;
595 -
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
599 -};
600 -
601  int __loc_is_allocated(locale_t loc)
602  {
603 -       return loc && loc != &c_locale && loc != &c_dot_utf8_locale;
604 +       return loc && loc != C_LOCALE && loc != UTF8_LOCALE;
605  }
606  
607  locale_t __newlocale(int mask, const char *name, locale_t loc)
608 @@ -44,9 +37,9 @@ locale_t __newlocale(int mask, const cha
609         }
610  
611         if (!j)
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;
615 +               return C_LOCALE;
616 +       if (j==1 && tmp.cat[LC_CTYPE]==&__c_dot_utf8)
617 +               return UTF8_LOCALE;
618  
619         if ((loc = malloc(sizeof *loc))) *loc = tmp;
620  
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;
626  
627 -       if (new == LC_GLOBAL_LOCALE) new = global;
628 -
629 -       self->locale = new;
630 +       if (new) self->locale = new == LC_GLOBAL_LOCALE ? global : new;
631  
632         return old == global ? LC_GLOBAL_LOCALE : old;
633  }
634 --- /dev/null
635 +++ b/src/malloc/expand_heap.c
636 @@ -0,0 +1,72 @@
637 +#include <limits.h>
638 +#include <stdint.h>
639 +#include <errno.h>
640 +#include <sys/mman.h>
641 +#include "libc.h"
642 +#include "syscall.h"
643 +
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. */
649 +
650 +static int traverses_stack_p(uintptr_t old, uintptr_t new)
651 +{
652 +       const uintptr_t len = 8<<20;
653 +       uintptr_t a, b;
654 +
655 +       b = (uintptr_t)libc.auxv;
656 +       a = b > len ? b-len : 0;
657 +       if (new>a && old<b) return 1;
658 +
659 +       b = (uintptr_t)&b;
660 +       a = b > len ? b-len : 0;
661 +       if (new>a && old<b) return 1;
662 +
663 +       return 0;
664 +}
665 +
666 +void *__mmap(void *, size_t, int, int, int, off_t);
667 +
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. */
675 +
676 +void *__expand_heap(size_t *pn)
677 +{
678 +       static uintptr_t brk;
679 +       static unsigned mmap_step;
680 +       size_t n = *pn;
681 +
682 +       if (n > SIZE_MAX/2 - PAGE_SIZE) {
683 +               errno = ENOMEM;
684 +               return 0;
685 +       }
686 +       n += -n & PAGE_SIZE-1;
687 +
688 +       if (!brk) {
689 +               brk = __syscall(SYS_brk, 0);
690 +               brk += -brk & PAGE_SIZE-1;
691 +       }
692 +
693 +       if (n < SIZE_MAX-brk && !traverses_stack_p(brk, brk+n)
694 +           && __syscall(SYS_brk, brk+n)==brk+n) {
695 +               *pn = n;
696 +               brk += n;
697 +               return (void *)(brk-n);
698 +       }
699 +
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;
705 +       *pn = n;
706 +       mmap_step++;
707 +       return area;
708 +}
709 --- a/src/malloc/lite_malloc.c
710 +++ b/src/malloc/lite_malloc.c
711 @@ -4,43 +4,46 @@
712  #include <errno.h>
713  #include "libc.h"
714  
715 -uintptr_t __brk(uintptr_t);
716 -
717  #define ALIGN 16
718  
719 +void *__expand_heap(size_t *);
720 +
721  void *__simple_malloc(size_t n)
722  {
723 -       static uintptr_t cur, brk;
724 -       uintptr_t base, new;
725 +       static char *cur, *end;
726         static volatile int lock[2];
727 -       size_t align=1;
728 +       size_t align=1, pad;
729 +       void *p;
730  
731         if (!n) n++;
732 -       if (n > SIZE_MAX/2) goto toobig;
733 -
734         while (align<n && align<ALIGN)
735                 align += align;
736 -       n = n + align - 1 & -align;
737  
738         LOCK(lock);
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;
745 -               brk = new;
746 -       }
747 -       cur = base+n;
748 -       UNLOCK(lock);
749  
750 -       return (void *)base;
751 +       pad = -(uintptr_t)cur & align-1;
752 +
753 +       if (n <= SIZE_MAX/2 + ALIGN) n += pad;
754 +
755 +       if (n > end-cur) {
756 +               size_t m = n;
757 +               char *new = __expand_heap(&m);
758 +               if (!new) {
759 +                       UNLOCK(lock);
760 +                       return 0;
761 +               }
762 +               if (new != end) {
763 +                       cur = new;
764 +                       n -= pad;
765 +                       pad = 0;
766 +               }
767 +               end = new + m;
768 +       }
769  
770 -fail:
771 +       p = cur + pad;
772 +       cur += n;
773         UNLOCK(lock);
774 -toobig:
775 -       errno = ENOMEM;
776 -       return 0;
777 +       return p;
778  }
779  
780  weak_alias(__simple_malloc, malloc);
781 --- a/src/malloc/malloc.c
782 +++ b/src/malloc/malloc.c
783 @@ -13,7 +13,6 @@
784  #define inline inline __attribute__((always_inline))
785  #endif
786  
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 {
792  };
793  
794  static struct {
795 -       uintptr_t brk;
796 -       size_t *heap;
797         volatile uint64_t binmap;
798         struct bin bins[64];
799 -       volatile int brk_lock[2];
800         volatile int free_lock[2];
801 -       unsigned mmap_step;
802  } mal;
803  
804  
805 @@ -152,69 +147,52 @@ void __dump_heap(int x)
806  }
807  #endif
808  
809 +void *__expand_heap(size_t *);
810 +
811  static struct chunk *expand_heap(size_t n)
812  {
813 -       static int init;
814 +       static int heap_lock[2];
815 +       static void *end;
816 +       void *p;
817         struct chunk *w;
818 -       uintptr_t new;
819 -
820 -       lock(mal.brk_lock);
821  
822 -       if (!init) {
823 -               mal.brk = __brk(0);
824 -#ifdef SHARED
825 -               mal.brk = mal.brk + PAGE_SIZE-1 & -PAGE_SIZE;
826 -#endif
827 -               mal.brk = mal.brk + 2*SIZE_ALIGN-1 & -SIZE_ALIGN;
828 -               mal.heap = (void *)mal.brk;
829 -               init = 1;
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. */
833 +       n += SIZE_ALIGN;
834 +
835 +       lock(heap_lock);
836 +
837 +       p = __expand_heap(&n);
838 +       if (!p) {
839 +               unlock(heap_lock);
840 +               return 0;
841         }
842  
843 -       if (n > SIZE_MAX - mal.brk - 2*PAGE_SIZE) goto fail;
844 -       new = mal.brk + n + SIZE_ALIGN + PAGE_SIZE - 1 & -PAGE_SIZE;
845 -       n = new - mal.brk;
846 -
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;
854 -
855 -               mal.mmap_step++;
856 -               area = (char *)area + SIZE_ALIGN - OVERHEAD;
857 -               w = area;
858 +       /* If not just expanding existing space, we need to make a
859 +        * new sentinel chunk below the allocated space. */
860 +       if (p != end) {
861 +               /* Valid/safe because of the prologue increment. */
862                 n -= SIZE_ALIGN;
863 +               p = (char *)p + SIZE_ALIGN;
864 +               w = MEM_TO_CHUNK(p);
865                 w->psize = 0 | C_INUSE;
866 -               w->csize = n | C_INUSE;
867 -               w = NEXT_CHUNK(w);
868 -               w->psize = n | C_INUSE;
869 -               w->csize = 0 | C_INUSE;
870 -
871 -               unlock(mal.brk_lock);
872 -
873 -               return area;
874         }
875  
876 -       w = MEM_TO_CHUNK(mal.heap);
877 -       w->psize = 0 | C_INUSE;
878 -
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;
885  
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;
891 -       mal.brk = new;
892 -       
893 -       unlock(mal.brk_lock);
894 +
895 +       unlock(heap_lock);
896  
897         return w;
898 -fail:
899 -       unlock(mal.brk_lock);
900 -       errno = ENOMEM;
901 -       return 0;
902  }
903  
904  static int adjust_size(size_t *n)
905 --- a/src/multibyte/btowc.c
906 +++ b/src/multibyte/btowc.c
907 @@ -1,7 +1,10 @@
908  #include <stdio.h>
909  #include <wchar.h>
910 +#include <stdlib.h>
911 +#include "internal.h"
912  
913  wint_t btowc(int c)
914  {
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;
918  }
919 --- a/src/multibyte/internal.h
920 +++ b/src/multibyte/internal.h
921 @@ -23,3 +23,10 @@ extern const uint32_t bittab[];
922  
923  #define SA 0xc2u
924  #define SB 0xf4u
925 +
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)
929 +
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
934 @@ -4,6 +4,7 @@
935   * unnecessary.
936   */
937  
938 +#include <stdlib.h>
939  #include <wchar.h>
940  #include <errno.h>
941  #include "internal.h"
942 @@ -27,6 +28,7 @@ size_t mbrtowc(wchar_t *restrict wc, con
943         if (!n) return -2;
944         if (!c) {
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--;
949         }
950 --- a/src/multibyte/mbsrtowcs.c
951 +++ b/src/multibyte/mbsrtowcs.c
952 @@ -7,6 +7,8 @@
953  #include <stdint.h>
954  #include <wchar.h>
955  #include <errno.h>
956 +#include <string.h>
957 +#include <stdlib.h>
958  #include "internal.h"
959  
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
962                 }
963         }
964  
965 +       if (MB_CUR_MAX==1) {
966 +               if (!ws) return strlen((const char *)s);
967 +               for (;;) {
968 +                       if (!wn) {
969 +                               *src = (const void *)s;
970 +                               return wn0;
971 +                       }
972 +                       if (!*s) break;
973 +                       c = *s++;
974 +                       *ws++ = CODEUNIT(c);
975 +                       wn--;
976 +               }
977 +               *ws = 0;
978 +               *src = 0;
979 +               return wn0-wn;
980 +       }
981 +
982         if (!ws) for (;;) {
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
987 @@ -4,6 +4,7 @@
988   * unnecessary.
989   */
990  
991 +#include <stdlib.h>
992  #include <wchar.h>
993  #include <errno.h>
994  #include "internal.h"
995 @@ -19,6 +20,7 @@ int mbtowc(wchar_t *restrict wc, const c
996         if (!wc) wc = &dummy;
997  
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];
1002  
1003 --- a/src/multibyte/wcrtomb.c
1004 +++ b/src/multibyte/wcrtomb.c
1005 @@ -4,8 +4,10 @@
1006   * unnecessary.
1007   */
1008  
1009 +#include <stdlib.h>
1010  #include <wchar.h>
1011  #include <errno.h>
1012 +#include "internal.h"
1013  
1014  size_t wcrtomb(char *restrict s, wchar_t wc, mbstate_t *restrict st)
1015  {
1016 @@ -13,6 +15,13 @@ size_t wcrtomb(char *restrict s, wchar_t
1017         if ((unsigned)wc < 0x80) {
1018                 *s = wc;
1019                 return 1;
1020 +       } else if (MB_CUR_MAX == 1) {
1021 +               if (!IS_CODEUNIT(wc)) {
1022 +                       errno = EILSEQ;
1023 +                       return -1;
1024 +               }
1025 +               *s = wc;
1026 +               return 1;
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
1032 @@ -1,8 +1,10 @@
1033 -#include <stdio.h>
1034  #include <wchar.h>
1035 +#include <stdlib.h>
1036 +#include "internal.h"
1037  
1038  int wctob(wint_t c)
1039  {
1040         if (c < 128U) return c;
1041 +       if (MB_CUR_MAX==1 && IS_CODEUNIT(c)) return (unsigned char)c;
1042         return EOF;
1043  }
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
1047                 },
1048                 .msg_iovlen = 2
1049         };
1050 +       int errno_save = errno;
1051  
1052         *swap = 0;
1053  retry:
1054 @@ -50,11 +51,14 @@ retry:
1055                 return f;
1056  
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
1060 -                */
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;
1068                         return f;
1069 +               }
1070                 goto error;
1071         }
1072  
1073 --- /dev/null
1074 +++ b/src/process/sh/vfork.s
1075 @@ -0,0 +1,23 @@
1076 +.global __vfork
1077 +.weak vfork
1078 +.type __vfork,@function
1079 +.type vfork,@function
1080 +__vfork:
1081 +vfork:
1082 +       mov #95, r3
1083 +       add r3, r3
1084 +
1085 +       trapa #16
1086 +       or    r0, r0
1087 +       or    r0, r0
1088 +       or    r0, r0
1089 +       or    r0, r0
1090 +       or    r0, r0
1091 +
1092 +       mov r0, r4
1093 +       mov.l 1f, r0
1094 +2:     braf r0
1095 +        nop
1096 +       .align 2
1097 +       .hidden __syscall_ret
1098 +1:     .long __syscall_ret@PLT-(2b+4-.)
1099 --- a/src/regex/fnmatch.c
1100 +++ b/src/regex/fnmatch.c
1101 @@ -18,6 +18,7 @@
1102  #include <stdlib.h>
1103  #include <wchar.h>
1104  #include <wctype.h>
1105 +#include "locale_impl.h"
1106  
1107  #define END 0
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);
1116         }
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;
1122  
1123         /* Add new FILE to open file list */
1124 -       OFLLOCK();
1125 -       f->next = libc.ofl_head;
1126 -       if (libc.ofl_head) libc.ofl_head->prev = f;
1127 -       libc.ofl_head = f;
1128 -       OFLUNLOCK();
1129 -
1130 -       return f;
1131 +       return __ofl_add(f);
1132  }
1133  
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)
1139  {
1140         FILE *f;
1141 -       OFLLOCK();
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);
1146  }
1147 --- a/src/stdio/__stdio_read.c
1148 +++ b/src/stdio/__stdio_read.c
1149 @@ -1,12 +1,5 @@
1150  #include "stdio_impl.h"
1151  #include <sys/uio.h>
1152 -#include <pthread.h>
1153 -
1154 -static void cleanup(void *p)
1155 -{
1156 -       FILE *f = p;
1157 -       if (!f->lockcount) __unlockfile(f);
1158 -}
1159  
1160  size_t __stdio_read(FILE *f, unsigned char *buf, size_t len)
1161  {
1162 @@ -16,9 +9,7 @@ size_t __stdio_read(FILE *f, unsigned ch
1163         };
1164         ssize_t cnt;
1165  
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);
1170         if (cnt <= 0) {
1171                 f->flags |= F_EOF ^ ((F_ERR^F_EOF) & cnt);
1172                 return cnt;
1173 --- a/src/stdio/__stdio_write.c
1174 +++ b/src/stdio/__stdio_write.c
1175 @@ -1,12 +1,5 @@
1176  #include "stdio_impl.h"
1177  #include <sys/uio.h>
1178 -#include <pthread.h>
1179 -
1180 -static void cleanup(void *p)
1181 -{
1182 -       FILE *f = p;
1183 -       if (!f->lockcount) __unlockfile(f);
1184 -}
1185  
1186  size_t __stdio_write(FILE *f, const unsigned char *buf, size_t len)
1187  {
1188 @@ -19,9 +12,7 @@ size_t __stdio_write(FILE *f, const unsi
1189         int iovcnt = 2;
1190         ssize_t cnt;
1191         for (;;) {
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);
1196                 if (cnt == rem) {
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
1200                 }
1201                 rem -= cnt;
1202                 if (cnt > iov[0].iov_len) {
1203 -                       f->wpos = f->wbase = f->buf;
1204                         cnt -= iov[0].iov_len;
1205                         iov++; iovcnt--;
1206 -               } else if (iovcnt == 2) {
1207 -                       f->wbase += cnt;
1208                 }
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);
1215  
1216         if (!(perm = f->flags & F_PERM)) {
1217 -               OFLLOCK();
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;
1222 -               OFLUNLOCK();
1223 +               if (*head == f) *head = f->next;
1224 +               __ofl_unlock();
1225         }
1226  
1227         r = fflush(f);
1228 --- a/src/stdio/fflush.c
1229 +++ b/src/stdio/fflush.c
1230 @@ -35,13 +35,12 @@ int fflush(FILE *f)
1231  
1232         r = __stdout_used ? fflush(__stdout_used) : 0;
1233  
1234 -       OFLLOCK();
1235 -       for (f=libc.ofl_head; f; f=f->next) {
1236 +       for (f=*__ofl_lock(); f; f=f->next) {
1237                 FLOCK(f);
1238                 if (f->wpos > f->wbase) r |= __fflush_unlocked(f);
1239                 FUNLOCK(f);
1240         }
1241 -       OFLUNLOCK();
1242 +       __ofl_unlock();
1243         
1244         return r;
1245  }
1246 --- a/src/stdio/fgetwc.c
1247 +++ b/src/stdio/fgetwc.c
1248 @@ -1,8 +1,9 @@
1249  #include "stdio_impl.h"
1250 +#include "locale_impl.h"
1251  #include <wchar.h>
1252  #include <errno.h>
1253  
1254 -wint_t __fgetwc_unlocked(FILE *f)
1255 +static wint_t __fgetwc_unlocked_internal(FILE *f)
1256  {
1257         mbstate_t st = { 0 };
1258         wchar_t wc;
1259 @@ -10,8 +11,6 @@ wint_t __fgetwc_unlocked(FILE *f)
1260         unsigned char b;
1261         size_t l;
1262  
1263 -       f->mode |= f->mode+1;
1264 -
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)
1269         return wc;
1270  }
1271  
1272 +wint_t __fgetwc_unlocked(FILE *f)
1273 +{
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);
1278 +       *ploc = loc;
1279 +       return wc;
1280 +}
1281 +
1282  wint_t fgetwc(FILE *f)
1283  {
1284         wint_t c;
1285 --- a/src/stdio/fmemopen.c
1286 +++ b/src/stdio/fmemopen.c
1287 @@ -110,11 +110,5 @@ FILE *fmemopen(void *restrict buf, size_
1288  
1289         if (!libc.threaded) f->lock = -1;
1290  
1291 -       OFLLOCK();
1292 -       f->next = libc.ofl_head;
1293 -       if (libc.ofl_head) libc.ofl_head->prev = f;
1294 -       libc.ofl_head = f;
1295 -       OFLUNLOCK();
1296 -
1297 -       return f;
1298 +       return __ofl_add(f);
1299  }
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);
1305  
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
1313 @@ -1,4 +1,5 @@
1314  #include "stdio_impl.h"
1315 +#include "locale_impl.h"
1316  #include <wchar.h>
1317  #include <limits.h>
1318  #include <ctype.h>
1319 @@ -7,8 +8,10 @@ wint_t __fputwc_unlocked(wchar_t c, FILE
1320  {
1321         char mbc[MB_LEN_MAX];
1322         int l;
1323 +       locale_t *ploc = &CURRENT_LOCALE, loc = *ploc;
1324  
1325 -       f->mode |= f->mode+1;
1326 +       if (f->mode <= 0) fwide(f, 1);
1327 +       *ploc = f->locale;
1328  
1329         if (isascii(c)) {
1330                 c = putc_unlocked(c, f);
1331 @@ -20,6 +23,8 @@ wint_t __fputwc_unlocked(wchar_t c, FILE
1332                 l = wctomb(mbc, c);
1333                 if (l < 0 || __fwritex((void *)mbc, l, f) < l) c = WEOF;
1334         }
1335 +       if (c==WEOF) f->flags |= F_ERR;
1336 +       *ploc = loc;
1337         return c;
1338  }
1339  
1340 --- a/src/stdio/fputws.c
1341 +++ b/src/stdio/fputws.c
1342 @@ -1,23 +1,28 @@
1343  #include "stdio_impl.h"
1344 +#include "locale_impl.h"
1345  #include <wchar.h>
1346  
1347  int fputws(const wchar_t *restrict ws, FILE *restrict f)
1348  {
1349         unsigned char buf[BUFSIZ];
1350         size_t l=0;
1351 +       locale_t *ploc = &CURRENT_LOCALE, loc = *ploc;
1352  
1353         FLOCK(f);
1354  
1355 -       f->mode |= f->mode+1;
1356 +       fwide(f, 1);
1357 +       *ploc = f->locale;
1358  
1359         while (ws && (l = wcsrtombs((void *)buf, (void*)&ws, sizeof buf, 0))+1 > 1)
1360                 if (__fwritex(buf, l, f) < l) {
1361                         FUNLOCK(f);
1362 +                       *ploc = loc;
1363                         return -1;
1364                 }
1365  
1366         FUNLOCK(f);
1367  
1368 +       *ploc = loc;
1369         return l; /* 0 or -1 */
1370  }
1371  
1372 --- a/src/stdio/fwide.c
1373 +++ b/src/stdio/fwide.c
1374 @@ -1,13 +1,14 @@
1375 -#include <wchar.h>
1376  #include "stdio_impl.h"
1377 -
1378 -#define SH (8*sizeof(int)-1)
1379 -#define NORMALIZE(x) ((x)>>SH | -((-(x))>>SH))
1380 +#include "locale_impl.h"
1381  
1382  int fwide(FILE *f, int mode)
1383  {
1384         FLOCK(f);
1385 -       if (!f->mode) f->mode = NORMALIZE(mode);
1386 +       if (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;
1390 +       }
1391         mode = f->mode;
1392         FUNLOCK(f);
1393         return mode;
1394 --- /dev/null
1395 +++ b/src/stdio/ofl.c
1396 @@ -0,0 +1,16 @@
1397 +#include "stdio_impl.h"
1398 +#include "libc.h"
1399 +
1400 +static FILE *ofl_head;
1401 +static volatile int ofl_lock[2];
1402 +
1403 +FILE **__ofl_lock()
1404 +{
1405 +       LOCK(ofl_lock);
1406 +       return &ofl_head;
1407 +}
1408 +
1409 +void __ofl_unlock()
1410 +{
1411 +       UNLOCK(ofl_lock);
1412 +}
1413 --- /dev/null
1414 +++ b/src/stdio/ofl_add.c
1415 @@ -0,0 +1,11 @@
1416 +#include "stdio_impl.h"
1417 +
1418 +FILE *__ofl_add(FILE *f)
1419 +{
1420 +       FILE **head = __ofl_lock();
1421 +       f->next = *head;
1422 +       if (*head) (*head)->prev = f;
1423 +       *head = f;
1424 +       __ofl_unlock();
1425 +       return f;
1426 +}
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
1430  
1431         if (!libc.threaded) f->lock = -1;
1432  
1433 -       OFLLOCK();
1434 -       f->next = libc.ofl_head;
1435 -       if (libc.ofl_head) libc.ofl_head->prev = f;
1436 -       libc.ofl_head = f;
1437 -       OFLUNLOCK();
1438 -
1439 -       return f;
1440 +       return __ofl_add(f);
1441  }
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
1445  
1446         if (!libc.threaded) f->lock = -1;
1447  
1448 -       OFLLOCK();
1449 -       f->next = libc.ofl_head;
1450 -       if (libc.ofl_head) libc.ofl_head->prev = f;
1451 -       libc.ofl_head = f;
1452 -       OFLUNLOCK();
1453 -
1454 -       return f;
1455 +       return __ofl_add(f);
1456  }
1457 --- a/src/stdio/ungetwc.c
1458 +++ b/src/stdio/ungetwc.c
1459 @@ -1,4 +1,5 @@
1460  #include "stdio_impl.h"
1461 +#include "locale_impl.h"
1462  #include <wchar.h>
1463  #include <limits.h>
1464  #include <ctype.h>
1465 @@ -8,21 +9,19 @@ wint_t ungetwc(wint_t c, FILE *f)
1466  {
1467         unsigned char mbc[MB_LEN_MAX];
1468         int l=1;
1469 -
1470 -       if (c == WEOF) return c;
1471 -
1472 -       /* Try conversion early so we can fail without locking if invalid */
1473 -       if (!isascii(c) && (l = wctomb((void *)mbc, c)) < 0)
1474 -               return WEOF;
1475 +       locale_t *ploc = &CURRENT_LOCALE, loc = *ploc;
1476  
1477         FLOCK(f);
1478  
1479 -       f->mode |= f->mode+1;
1480 +       if (f->mode <= 0) fwide(f, 1);
1481 +       *ploc = f->locale;
1482  
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)) {
1487                 FUNLOCK(f);
1488 -               return EOF;
1489 +               *ploc = loc;
1490 +               return WEOF;
1491         }
1492  
1493         if (isascii(c)) *--f->rpos = c;
1494 @@ -31,5 +30,6 @@ wint_t ungetwc(wint_t c, FILE *f)
1495         f->flags &= ~F_EOF;
1496  
1497         FUNLOCK(f);
1498 +       *ploc = loc;
1499         return c;
1500  }
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, "");
1505                         l=w;
1506                         continue;
1507 +               case 'm':
1508 +                       arg.p = strerror(errno);
1509                 case 's':
1510 +                       if (!arg.p) arg.p = "(null)";
1511                         bs = arg.p;
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
1515         }
1516  
1517         FLOCK(f);
1518 -       f->mode |= f->mode+1;
1519 +       fwide(f, 1);
1520         olderr = f->flags & F_ERR;
1521         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
1526  
1527         FLOCK(f);
1528  
1529 -       f->mode |= f->mode+1;
1530 +       fwide(f, 1);
1531  
1532         for (p=fmt; *p; p++) {
1533  
1534 --- /dev/null
1535 +++ b/src/thread/__unmapself.c
1536 @@ -0,0 +1,29 @@
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"
1542 +
1543 +static volatile int lock;
1544 +static void *unmap_base;
1545 +static size_t unmap_size;
1546 +static char shared_stack[256];
1547 +
1548 +static void do_unmap()
1549 +{
1550 +       __syscall(SYS_munmap, unmap_base, unmap_size);
1551 +       __syscall(SYS_exit);
1552 +}
1553 +
1554 +void __unmapself(void *base, size_t size)
1555 +{
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))
1560 +               a_spin();
1561 +       __syscall(SYS_set_tid_address, &lock);
1562 +       unmap_base = base;
1563 +       unmap_size = size;
1564 +       CRTJMP(do_unmap, stack);
1565 +}
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)
1574                         init_file_lock(f);
1575 +               __ofl_unlock();
1576                 init_file_lock(__stdin_used);
1577                 init_file_lock(__stdout_used);
1578                 init_file_lock(__stderr_used);