Merge "Update to kernel headers v4.12.3."
diff --git a/libc/Android.bp b/libc/Android.bp
index d9b8a2b..701a1b0 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1446,6 +1446,7 @@
"bionic/getpriority.cpp",
"bionic/gettid.cpp",
"bionic/grp_pwd.cpp",
+ "bionic/icu_wrappers.cpp",
"bionic/ifaddrs.cpp",
"bionic/inotify_init.cpp",
"bionic/ioctl.cpp",
@@ -1553,6 +1554,7 @@
"bionic/wchar_l.cpp",
"bionic/wcstod.cpp",
"bionic/wctype.cpp",
+ "bionic/wcwidth.cpp",
"bionic/wmempcpy.cpp",
],
@@ -1948,6 +1950,8 @@
no_default_compiler_flags: true,
+ cflags: ["-Wno-gcc-compat", "-Werror"],
+
arch: {
arm: {
local_include_dirs: ["arch-arm/include"],
@@ -1974,6 +1978,8 @@
cc_defaults {
name: "crt_so_defaults",
+ cflags: ["-Wno-gcc-compat", "-Werror"],
+
vendor_available: true,
arch: {
mips: {
diff --git a/libc/bionic/grp_pwd.cpp b/libc/bionic/grp_pwd.cpp
index 078a0b3..2823662 100644
--- a/libc/bionic/grp_pwd.cpp
+++ b/libc/bionic/grp_pwd.cpp
@@ -467,7 +467,16 @@
char* getlogin() { // NOLINT: implementing bad function.
passwd *pw = getpwuid(getuid()); // NOLINT: implementing bad function in terms of bad function.
- return (pw != NULL) ? pw->pw_name : NULL;
+ return pw ? pw->pw_name : nullptr;
+}
+
+int getlogin_r(char* buf, size_t size) {
+ char* login = getlogin();
+ if (login == nullptr) return errno;
+ size_t login_length = strlen(login) + 1;
+ if (login_length > size) return ERANGE;
+ memcpy(buf, login, login_length);
+ return 0;
}
void setpwent() {
diff --git a/libc/bionic/icu_wrappers.cpp b/libc/bionic/icu_wrappers.cpp
new file mode 100644
index 0000000..d9f2745
--- /dev/null
+++ b/libc/bionic/icu_wrappers.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "private/icu.h"
+
+int8_t __icu_charType(wint_t wc) {
+ typedef int8_t (*u_charType_t)(UChar32);
+ static auto u_charType = reinterpret_cast<u_charType_t>(__find_icu_symbol("u_charType"));
+ return u_charType ? u_charType(wc) : -1;
+}
+
+int32_t __icu_getIntPropertyValue(wint_t wc, UProperty property) {
+ typedef int32_t (*u_getIntPropertyValue_t)(UChar32, UProperty);
+ static auto u_getIntPropertyValue =
+ reinterpret_cast<u_getIntPropertyValue_t>(__find_icu_symbol("u_getIntPropertyValue"));
+ return u_getIntPropertyValue ? u_getIntPropertyValue(wc, property) : 0;
+}
+
+bool __icu_hasBinaryProperty(wint_t wc, UProperty property, int (*fallback)(int)) {
+ typedef UBool (*u_hasBinaryProperty_t)(UChar32, UProperty);
+ static auto u_hasBinaryProperty =
+ reinterpret_cast<u_hasBinaryProperty_t>(__find_icu_symbol("u_hasBinaryProperty"));
+ return u_hasBinaryProperty ? u_hasBinaryProperty(wc, property) : fallback(wc);
+}
diff --git a/libc/bionic/sysconf.cpp b/libc/bionic/sysconf.cpp
index 4a23fec..7325dbd 100644
--- a/libc/bionic/sysconf.cpp
+++ b/libc/bionic/sysconf.cpp
@@ -135,12 +135,12 @@
case _SC_TIMERS: return _POSIX_TIMERS;
case _SC_GETGR_R_SIZE_MAX: return 1024;
case _SC_GETPW_R_SIZE_MAX: return 1024;
- case _SC_LOGIN_NAME_MAX: return 256; // Seems default on linux.
+ case _SC_LOGIN_NAME_MAX: return LOGIN_NAME_MAX;
case _SC_THREAD_DESTRUCTOR_ITERATIONS: return PTHREAD_DESTRUCTOR_ITERATIONS;
case _SC_THREAD_KEYS_MAX: return PTHREAD_KEYS_MAX;
case _SC_THREAD_STACK_MIN: return PTHREAD_STACK_MIN;
case _SC_THREAD_THREADS_MAX: return -1; // No specific limit.
- case _SC_TTY_NAME_MAX: return 32; // Seems default on linux.
+ case _SC_TTY_NAME_MAX: return TTY_NAME_MAX;
case _SC_THREADS: return _POSIX_THREADS;
case _SC_THREAD_ATTR_STACKADDR: return _POSIX_THREAD_ATTR_STACKADDR;
case _SC_THREAD_ATTR_STACKSIZE: return _POSIX_THREAD_ATTR_STACKSIZE;
diff --git a/libc/bionic/wctype.cpp b/libc/bionic/wctype.cpp
index 8e2acef..05b6e19 100644
--- a/libc/bionic/wctype.cpp
+++ b/libc/bionic/wctype.cpp
@@ -53,12 +53,6 @@
WC_TYPE_MAX
};
-static bool __icu_hasBinaryProperty(wint_t wc, UProperty property, int (*fallback)(int)) {
- typedef UBool (*FnT)(UChar32, UProperty);
- static auto u_hasBinaryProperty = reinterpret_cast<FnT>(__find_icu_symbol("u_hasBinaryProperty"));
- return u_hasBinaryProperty ? u_hasBinaryProperty(wc, property) : fallback(wc);
-}
-
int iswalnum(wint_t wc) { return __icu_hasBinaryProperty(wc, UCHAR_POSIX_ALNUM, isalnum); }
int iswalpha(wint_t wc) { return __icu_hasBinaryProperty(wc, UCHAR_ALPHABETIC, isalpha); }
int iswblank(wint_t wc) { return __icu_hasBinaryProperty(wc, UCHAR_POSIX_BLANK, isblank); }
@@ -155,10 +149,6 @@
return wctype(property);
}
-int wcwidth(wchar_t wc) {
- return (wc > 0);
-}
-
static wctrans_t wctrans_tolower = wctrans_t(1);
static wctrans_t wctrans_toupper = wctrans_t(2);
diff --git a/libc/bionic/wcwidth.cpp b/libc/bionic/wcwidth.cpp
new file mode 100644
index 0000000..9676b5a
--- /dev/null
+++ b/libc/bionic/wcwidth.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <wchar.h>
+
+#include "private/icu.h"
+
+int wcwidth(wchar_t wc) {
+ // Fast-path ASCII.
+ if (wc >= 0x20 && wc < 0x7f) return 1;
+
+ // ASCII NUL is a special case.
+ if (wc == 0) return 0;
+
+ // C0.
+ if (wc < ' ' || (wc >= 0x7f && wc <= 0xa0)) return -1;
+
+ // Now for the i18n part. This isn't defined or standardized, so a lot of the choices are
+ // pretty arbitrary. See https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c for more details.
+
+ // Fancy unicode control characters?
+ switch (__icu_charType(wc)) {
+ case -1:
+ // No icu4c available; give up.
+ return -1;
+ case U_CONTROL_CHAR:
+ return -1;
+ case U_NON_SPACING_MARK:
+ case U_ENCLOSING_MARK:
+ case U_FORMAT_CHAR:
+ return 0;
+ }
+ if (__icu_hasBinaryProperty(wc, UCHAR_DEFAULT_IGNORABLE_CODE_POINT, nullptr)) return 0;
+
+ // Medial and final jamo render as zero width when used correctly.
+ switch (__icu_getIntPropertyValue(wc, UCHAR_HANGUL_SYLLABLE_TYPE)) {
+ case U_HST_VOWEL_JAMO:
+ case U_HST_TRAILING_JAMO:
+ return 0;
+ case U_HST_LEADING_JAMO:
+ case U_HST_LV_SYLLABLE:
+ case U_HST_LVT_SYLLABLE:
+ return 2;
+ }
+
+ if (wc >= 0x3248 && wc <= 0x4dff) {
+ // Circled two-digit CJK "speed sign" numbers. EastAsianWidth is ambiguous,
+ // but wide makes more sense.
+ if (wc <= 0x324f) return 2;
+ // Hexagrams. EastAsianWidth is neutral, but wide seems better.
+ if (wc >= 0x4dc0) return 2;
+ }
+
+ // The EastAsianWidth property is at least defined by the Unicode standard!
+ switch (__icu_getIntPropertyValue(wc, UCHAR_EAST_ASIAN_WIDTH)) {
+ case U_EA_AMBIGUOUS:
+ case U_EA_HALFWIDTH:
+ case U_EA_NARROW:
+ case U_EA_NEUTRAL:
+ return 1;
+ case U_EA_FULLWIDTH:
+ case U_EA_WIDE:
+ return 2;
+ }
+
+ return 0;
+}
diff --git a/libc/include/android/api-level.h b/libc/include/android/api-level.h
index c83c18d..7e3aa99 100644
--- a/libc/include/android/api-level.h
+++ b/libc/include/android/api-level.h
@@ -41,6 +41,8 @@
#ifndef __ANDROID_API__
#define __ANDROID_API__ __ANDROID_API_FUTURE__
+#else
+#define __ANDROID_NDK__ 1
#endif
#define __ANDROID_API_G__ 9
diff --git a/libc/include/android/legacy_stdlib_inlines.h b/libc/include/android/legacy_stdlib_inlines.h
index 82186c7..e26e5f2 100644
--- a/libc/include/android/legacy_stdlib_inlines.h
+++ b/libc/include/android/legacy_stdlib_inlines.h
@@ -29,6 +29,8 @@
#ifndef _ANDROID_LEGACY_STDLIB_INLINES_H_
#define _ANDROID_LEGACY_STDLIB_INLINES_H_
+#include <errno.h>
+#include <float.h>
#include <stdlib.h>
#include <sys/cdefs.h>
@@ -36,10 +38,16 @@
__BEGIN_DECLS
-__noreturn void _Exit(int) __RENAME(_exit);
-
-static __inline float strtof(const char *nptr, char **endptr) {
- return (float)strtod(nptr, endptr);
+static __inline float strtof(const char* nptr, char** endptr) {
+ double d = strtod(nptr, endptr);
+ if (d > FLT_MAX) {
+ errno = ERANGE;
+ return __builtin_huge_valf();
+ } else if (d < -FLT_MAX) {
+ errno = ERANGE;
+ return -__builtin_huge_valf();
+ }
+ return __BIONIC_CAST(static_cast, float, d);
}
static __inline double atof(const char *nptr) { return (strtod(nptr, NULL)); }
diff --git a/libc/include/limits.h b/libc/include/limits.h
index 157f7a6..51f4fad 100644
--- a/libc/include/limits.h
+++ b/libc/include/limits.h
@@ -137,6 +137,8 @@
#include <bits/posix_limits.h>
#define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
+#define LOGIN_NAME_MAX 256
+#define TTY_NAME_MAX 32
#define _POSIX_VERSION 200809L
#define _POSIX2_VERSION _POSIX_VERSION
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index e024527..8336976 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -118,6 +118,7 @@
int getresuid(uid_t* __ruid, uid_t* __euid, uid_t* __suid);
int getresgid(gid_t* __rgid, gid_t* __egid, gid_t* __sgid);
char* getlogin(void);
+int getlogin_r(char* __buffer, size_t __buffer_size) __INTRODUCED_IN_FUTURE;
long fpathconf(int __fd, int __name);
long pathconf(const char* __path, int __name);
diff --git a/libc/include/wchar.h b/libc/include/wchar.h
index c9a78be..a86c8a9 100644
--- a/libc/include/wchar.h
+++ b/libc/include/wchar.h
@@ -42,6 +42,11 @@
__BEGIN_DECLS
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnullability-completeness"
+#endif
+
wint_t btowc(int);
int fwprintf(FILE *, const wchar_t *, ...);
int fwscanf(FILE *, const wchar_t *, ...);
@@ -134,6 +139,10 @@
wchar_t* wcsdup(const wchar_t*);
size_t wcsnlen(const wchar_t*, size_t);
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
__END_DECLS
#endif /* _WCHAR_H_ */
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index a4212dd..45ca9eb 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -1316,6 +1316,11 @@
wctrans_l; # introduced=26
} LIBC_N;
+LIBC_P {
+ global:
+ getlogin_r; # future
+} LIBC_O;
+
LIBC_PRIVATE {
global:
___Unwind_Backtrace; # arm
@@ -1532,7 +1537,7 @@
vfdprintf; # arm x86 mips
wait3; # arm x86 mips
wcswcs; # arm x86 mips
-} LIBC_O;
+} LIBC_P;
LIBC_DEPRECATED {
global:
@@ -1554,4 +1559,4 @@
malloc_disable;
malloc_enable;
malloc_iterate;
-} LIBC_O;
+} LIBC_P;
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index bf0341a..ed1e82c 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -1238,6 +1238,11 @@
wctrans_l; # introduced=26
} LIBC_N;
+LIBC_P {
+ global:
+ getlogin_r; # future
+} LIBC_O;
+
LIBC_PRIVATE {
global:
android_getaddrinfofornet;
@@ -1249,7 +1254,7 @@
free_malloc_leak_info;
get_malloc_leak_info;
gMallocLeakZygoteChild;
-} LIBC_O;
+} LIBC_P;
LIBC_DEPRECATED {
global:
@@ -1271,4 +1276,4 @@
malloc_disable;
malloc_enable;
malloc_iterate;
-} LIBC_O;
+} LIBC_P;
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index c271a57..8b1d6de 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1341,6 +1341,11 @@
wctrans_l; # introduced=26
} LIBC_N;
+LIBC_P {
+ global:
+ getlogin_r; # future
+} LIBC_O;
+
LIBC_PRIVATE {
global:
___Unwind_Backtrace; # arm
@@ -1558,7 +1563,7 @@
vfdprintf; # arm x86 mips
wait3; # arm x86 mips
wcswcs; # arm x86 mips
-} LIBC_O;
+} LIBC_P;
LIBC_DEPRECATED {
global:
@@ -1580,4 +1585,4 @@
malloc_disable;
malloc_enable;
malloc_iterate;
-} LIBC_O;
+} LIBC_P;
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index 214c7f5..256ca9e 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -1300,6 +1300,11 @@
wctrans_l; # introduced=26
} LIBC_N;
+LIBC_P {
+ global:
+ getlogin_r; # future
+} LIBC_O;
+
LIBC_PRIVATE {
global:
__accept4; # arm x86 mips
@@ -1373,7 +1378,7 @@
vfdprintf; # arm x86 mips
wait3; # arm x86 mips
wcswcs; # arm x86 mips
-} LIBC_O;
+} LIBC_P;
LIBC_DEPRECATED {
global:
@@ -1395,4 +1400,4 @@
malloc_disable;
malloc_enable;
malloc_iterate;
-} LIBC_O;
+} LIBC_P;
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index bf0341a..ed1e82c 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -1238,6 +1238,11 @@
wctrans_l; # introduced=26
} LIBC_N;
+LIBC_P {
+ global:
+ getlogin_r; # future
+} LIBC_O;
+
LIBC_PRIVATE {
global:
android_getaddrinfofornet;
@@ -1249,7 +1254,7 @@
free_malloc_leak_info;
get_malloc_leak_info;
gMallocLeakZygoteChild;
-} LIBC_O;
+} LIBC_P;
LIBC_DEPRECATED {
global:
@@ -1271,4 +1276,4 @@
malloc_disable;
malloc_enable;
malloc_iterate;
-} LIBC_O;
+} LIBC_P;
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index 145b64e..2ebc86c 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -1298,6 +1298,11 @@
wctrans_l; # introduced=26
} LIBC_N;
+LIBC_P {
+ global:
+ getlogin_r; # future
+} LIBC_O;
+
LIBC_PRIVATE {
global:
__accept4; # arm x86 mips
@@ -1372,7 +1377,7 @@
vfdprintf; # arm x86 mips
wait3; # arm x86 mips
wcswcs; # arm x86 mips
-} LIBC_O;
+} LIBC_P;
LIBC_DEPRECATED {
global:
@@ -1394,4 +1399,4 @@
malloc_disable;
malloc_enable;
malloc_iterate;
-} LIBC_O;
+} LIBC_P;
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index bf0341a..ed1e82c 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -1238,6 +1238,11 @@
wctrans_l; # introduced=26
} LIBC_N;
+LIBC_P {
+ global:
+ getlogin_r; # future
+} LIBC_O;
+
LIBC_PRIVATE {
global:
android_getaddrinfofornet;
@@ -1249,7 +1254,7 @@
free_malloc_leak_info;
get_malloc_leak_info;
gMallocLeakZygoteChild;
-} LIBC_O;
+} LIBC_P;
LIBC_DEPRECATED {
global:
@@ -1271,4 +1276,4 @@
malloc_disable;
malloc_enable;
malloc_iterate;
-} LIBC_O;
+} LIBC_P;
diff --git a/libc/private/icu.h b/libc/private/icu.h
index 03fdf66..ae253fa 100644
--- a/libc/private/icu.h
+++ b/libc/private/icu.h
@@ -30,12 +30,14 @@
#define _PRIVATE_ICU_H
#include <stdint.h>
+#include <wchar.h>
typedef int8_t UBool;
typedef int32_t UChar32;
enum UProperty {
UCHAR_ALPHABETIC = 0,
+ UCHAR_DEFAULT_IGNORABLE_CODE_POINT = 5,
UCHAR_LOWERCASE = 22,
UCHAR_POSIX_ALNUM = 44,
UCHAR_POSIX_BLANK = 45,
@@ -44,12 +46,39 @@
UCHAR_POSIX_XDIGIT = 48,
UCHAR_UPPERCASE = 30,
UCHAR_WHITE_SPACE = 31,
+ UCHAR_EAST_ASIAN_WIDTH = 0x1004,
+ UCHAR_HANGUL_SYLLABLE_TYPE = 0x100b,
};
enum UCharCategory {
+ U_NON_SPACING_MARK = 6,
+ U_ENCLOSING_MARK = 7,
U_CONTROL_CHAR = 15,
+ U_FORMAT_CHAR = 16,
};
+enum UEastAsianWidth {
+ U_EA_NEUTRAL,
+ U_EA_AMBIGUOUS,
+ U_EA_HALFWIDTH,
+ U_EA_FULLWIDTH,
+ U_EA_NARROW,
+ U_EA_WIDE,
+};
+
+enum UHangulSyllableType {
+ U_HST_NOT_APPLICABLE,
+ U_HST_LEADING_JAMO,
+ U_HST_VOWEL_JAMO,
+ U_HST_TRAILING_JAMO,
+ U_HST_LV_SYLLABLE,
+ U_HST_LVT_SYLLABLE,
+};
+
+int8_t __icu_charType(wint_t wc);
+int32_t __icu_getIntPropertyValue(wint_t wc, UProperty property);
+bool __icu_hasBinaryProperty(wint_t wc, UProperty property, int (*fallback)(int));
+
void* __find_icu_symbol(const char* symbol_name);
#endif // _PRIVATE_ICU_H
diff --git a/libc/stdio/local.h b/libc/stdio/local.h
index d8b1a57..afb02ca 100644
--- a/libc/stdio/local.h
+++ b/libc/stdio/local.h
@@ -134,7 +134,7 @@
#define __SEOF 0x0020 // Found EOF.
#define __SERR 0x0040 // Found error.
#define __SMBF 0x0080 // `_buf` is from malloc.
-#define __SAPP 0x0100 // fdopen()ed in append mode.
+// #define __SAPP 0x0100 --- historical (fdopen()ed in append mode).
#define __SSTR 0x0200 // This is an sprintf/snprintf string.
// #define __SOPT 0x0400 --- historical (do fseek() optimization).
// #define __SNPT 0x0800 --- historical (do not do fseek() optimization).
diff --git a/libc/stdio/stdio.cpp b/libc/stdio/stdio.cpp
index cd4be2e..4d6438b 100644
--- a/libc/stdio/stdio.cpp
+++ b/libc/stdio/stdio.cpp
@@ -68,14 +68,8 @@
_THREAD_PRIVATE_MUTEX(__sfp_mutex);
-// TODO: when we no longer have to support both clang and GCC, we can simplify all this.
-#define SBUF_INIT {0,0}
-#if defined(__LP64__)
-#define MBSTATE_T_INIT {{0},{0}}
-#else
-#define MBSTATE_T_INIT {{0}}
-#endif
-#define WCHAR_IO_DATA_INIT {MBSTATE_T_INIT,MBSTATE_T_INIT,{0},0,0}
+#define SBUF_INIT {}
+#define WCHAR_IO_DATA_INIT {}
static struct __sfileext __sFext[3] = {
{ SBUF_INIT, WCHAR_IO_DATA_INIT, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, false, __sseek64 },
@@ -212,11 +206,11 @@
}
FILE* fopen(const char* file, const char* mode) {
- int oflags;
- int flags = __sflags(mode, &oflags);
+ int mode_flags;
+ int flags = __sflags(mode, &mode_flags);
if (flags == 0) return nullptr;
- int fd = open(file, oflags, DEFFILEMODE);
+ int fd = open(file, mode_flags, DEFFILEMODE);
if (fd == -1) {
return nullptr;
}
@@ -228,41 +222,34 @@
return nullptr;
}
- // When opening in append mode, even though we use O_APPEND,
- // we need to seek to the end so that ftell() gets the right
- // answer. If the user then alters the seek pointer, or
- // the file extends, this will fail, but there is not much
- // we can do about this. (We could set __SAPP and check in
- // fseek and ftell.)
- // TODO: check in __sseek instead.
- if (oflags & O_APPEND) __sseek64(fp, 0, SEEK_END);
-
+ // For append mode, even though we use O_APPEND, we need to seek to the end now.
+ if ((mode_flags & O_APPEND) != 0) __sseek64(fp, 0, SEEK_END);
return fp;
}
__strong_alias(fopen64, fopen);
FILE* fdopen(int fd, const char* mode) {
- int oflags;
- int flags = __sflags(mode, &oflags);
+ int mode_flags;
+ int flags = __sflags(mode, &mode_flags);
if (flags == 0) return nullptr;
// Make sure the mode the user wants is a subset of the actual mode.
- int fdflags = fcntl(fd, F_GETFL, 0);
- if (fdflags < 0) return nullptr;
- int tmp = fdflags & O_ACCMODE;
- if (tmp != O_RDWR && (tmp != (oflags & O_ACCMODE))) {
+ int fd_flags = fcntl(fd, F_GETFL, 0);
+ if (fd_flags == -1) return nullptr;
+ int tmp = fd_flags & O_ACCMODE;
+ if (tmp != O_RDWR && (tmp != (mode_flags & O_ACCMODE))) {
errno = EINVAL;
return nullptr;
}
- // If opened for appending, but underlying descriptor does not have
- // O_APPEND bit set, assert __SAPP so that __swrite() will lseek to
- // end before each write.
- // TODO: use fcntl(2) to set O_APPEND instead.
- if ((oflags & O_APPEND) && !(fdflags & O_APPEND)) flags |= __SAPP;
+ // Make sure O_APPEND is set on the underlying fd if our mode has 'a'.
+ // POSIX says we just take the current offset of the underlying fd.
+ if ((mode_flags & O_APPEND) && !(fd_flags & O_APPEND)) {
+ if (fcntl(fd, F_SETFL, fd_flags | O_APPEND) == -1) return nullptr;
+ }
- // If close-on-exec was requested, then turn it on if not already.
- if ((oflags & O_CLOEXEC) && !((tmp = fcntl(fd, F_GETFD)) & FD_CLOEXEC)) {
+ // Make sure O_CLOEXEC is set on the underlying fd if our mode has 'x'.
+ if ((mode_flags & O_CLOEXEC) && !((tmp = fcntl(fd, F_GETFD)) & FD_CLOEXEC)) {
fcntl(fd, F_SETFD, tmp | FD_CLOEXEC);
}
@@ -274,8 +261,8 @@
// all possible, no matter what.
// TODO: rewrite this mess completely.
FILE* freopen(const char* file, const char* mode, FILE* fp) {
- int oflags;
- int flags = __sflags(mode, &oflags);
+ int mode_flags;
+ int flags = __sflags(mode, &mode_flags);
if (flags == 0) {
fclose(fp);
return nullptr;
@@ -307,13 +294,13 @@
}
// Get a new descriptor to refer to the new file.
- int fd = open(file, oflags, DEFFILEMODE);
+ int fd = open(file, mode_flags, DEFFILEMODE);
if (fd < 0 && isopen) {
// If out of fd's close the old one and try again.
if (errno == ENFILE || errno == EMFILE) {
(*fp->_close)(fp->_cookie);
isopen = 0;
- fd = open(file, oflags, DEFFILEMODE);
+ fd = open(file, mode_flags, DEFFILEMODE);
}
}
@@ -346,7 +333,7 @@
// to maintain the descriptor. Various C library routines (perror)
// assume stderr is always fd STDERR_FILENO, even if being freopen'd.
if (wantfd >= 0 && fd != wantfd) {
- if (dup3(fd, wantfd, oflags & O_CLOEXEC) >= 0) {
+ if (dup3(fd, wantfd, mode_flags & O_CLOEXEC) >= 0) {
close(fd);
fd = wantfd;
}
@@ -367,13 +354,8 @@
fp->_close = __sclose;
_EXT(fp)->_seek64 = __sseek64;
- // When opening in append mode, even though we use O_APPEND,
- // we need to seek to the end so that ftell() gets the right
- // answer. If the user then alters the seek pointer, or
- // the file extends, this will fail, but there is not much
- // we can do about this. (We could set __SAPP and check in
- // fseek and ftell.)
- if (oflags & O_APPEND) __sseek64(fp, 0, SEEK_END);
+ // For append mode, even though we use O_APPEND, we need to seek to the end now.
+ if ((mode_flags & O_APPEND) != 0) __sseek64(fp, 0, SEEK_END);
return fp;
}
__strong_alias(freopen64, freopen);
@@ -452,12 +434,6 @@
int __swrite(void* cookie, const char* buf, int n) {
FILE* fp = reinterpret_cast<FILE*>(cookie);
- if (fp->_flags & __SAPP) {
- // The FILE* is in append mode, but the underlying fd doesn't have O_APPEND set.
- // We need to seek manually.
- // TODO: use fcntl(2) to set O_APPEND in fdopen(3) instead?
- TEMP_FAILURE_RETRY(lseek64(fp->_file, 0, SEEK_END));
- }
return TEMP_FAILURE_RETRY(write(fp->_file, buf, n));
}
@@ -496,6 +472,7 @@
static off64_t __ftello64_unlocked(FILE* fp) {
// Find offset of underlying I/O object, then adjust for buffered bytes.
__sflush(fp); // May adjust seek offset on append stream.
+
off64_t result = __seek_unlocked(fp, 0, SEEK_CUR);
if (result == -1) {
return -1;
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index 1f27c83..dac7056 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -47,6 +47,24 @@
class stdio_DeathTest : public BionicDeathTest {};
class stdio_nofortify_DeathTest : public BionicDeathTest {};
+static void SetFileTo(const char* path, const char* content) {
+ FILE* fp;
+ ASSERT_NE(nullptr, fp = fopen(path, "w"));
+ ASSERT_NE(EOF, fputs(content, fp));
+ ASSERT_EQ(0, fclose(fp));
+}
+
+static void AssertFileIs(const char* path, const char* expected) {
+ FILE* fp;
+ ASSERT_NE(nullptr, fp = fopen(path, "r"));
+ char* line = nullptr;
+ size_t length;
+ ASSERT_NE(EOF, getline(&line, &length, fp));
+ ASSERT_EQ(0, fclose(fp));
+ ASSERT_STREQ(expected, line);
+ free(line);
+}
+
static void AssertFileIs(FILE* fp, const char* expected, bool is_fmemopen = false) {
rewind(fp);
@@ -1846,3 +1864,57 @@
sprintf(&buf[0], "hello");
ASSERT_EQ(buf, "hello");
}
+
+TEST(STDIO_TEST, fopen_append_mode_and_ftell) {
+ TemporaryFile tf;
+ SetFileTo(tf.filename, "0123456789");
+ FILE* fp = fopen(tf.filename, "a");
+ EXPECT_EQ(10, ftell(fp));
+ ASSERT_EQ(0, fseek(fp, 2, SEEK_SET));
+ EXPECT_EQ(2, ftell(fp));
+ ASSERT_NE(EOF, fputs("xxx", fp));
+ ASSERT_EQ(0, fflush(fp));
+ EXPECT_EQ(13, ftell(fp));
+ ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
+ EXPECT_EQ(13, ftell(fp));
+ ASSERT_EQ(0, fclose(fp));
+ AssertFileIs(tf.filename, "0123456789xxx");
+}
+
+TEST(STDIO_TEST, fdopen_append_mode_and_ftell) {
+ TemporaryFile tf;
+ SetFileTo(tf.filename, "0123456789");
+ int fd = open(tf.filename, O_RDWR);
+ ASSERT_NE(-1, fd);
+ // POSIX: "The file position indicator associated with the new stream is set to the position
+ // indicated by the file offset associated with the file descriptor."
+ ASSERT_EQ(4, lseek(fd, 4, SEEK_SET));
+ FILE* fp = fdopen(fd, "a");
+ EXPECT_EQ(4, ftell(fp));
+ ASSERT_EQ(0, fseek(fp, 2, SEEK_SET));
+ EXPECT_EQ(2, ftell(fp));
+ ASSERT_NE(EOF, fputs("xxx", fp));
+ ASSERT_EQ(0, fflush(fp));
+ EXPECT_EQ(13, ftell(fp));
+ ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
+ EXPECT_EQ(13, ftell(fp));
+ ASSERT_EQ(0, fclose(fp));
+ AssertFileIs(tf.filename, "0123456789xxx");
+}
+
+TEST(STDIO_TEST, freopen_append_mode_and_ftell) {
+ TemporaryFile tf;
+ SetFileTo(tf.filename, "0123456789");
+ FILE* other_fp = fopen("/proc/version", "r");
+ FILE* fp = freopen(tf.filename, "a", other_fp);
+ EXPECT_EQ(10, ftell(fp));
+ ASSERT_EQ(0, fseek(fp, 2, SEEK_SET));
+ EXPECT_EQ(2, ftell(fp));
+ ASSERT_NE(EOF, fputs("xxx", fp));
+ ASSERT_EQ(0, fflush(fp));
+ EXPECT_EQ(13, ftell(fp));
+ ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
+ EXPECT_EQ(13, ftell(fp));
+ ASSERT_EQ(0, fclose(fp));
+ AssertFileIs(tf.filename, "0123456789xxx");
+}
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index a81f112..9b811ed 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -837,6 +837,7 @@
VERIFY_SYSCONF_UNSUPPORTED(_SC_2_FORT_DEV);
VERIFY_SYSCONF_UNSUPPORTED(_SC_2_FORT_RUN);
VERIFY_SYSCONF_UNSUPPORTED(_SC_2_UPE);
+ VERIFY_SYSCONF_POSIX_VERSION(_SC_2_VERSION);
VERIFY_SYSCONF_POSITIVE(_SC_JOB_CONTROL);
VERIFY_SYSCONF_POSITIVE(_SC_SAVED_IDS);
VERIFY_SYSCONF_POSIX_VERSION(_SC_VERSION);
@@ -952,7 +953,6 @@
VERIFY_SYSCONF_UNSUPPORTED(_SC_2_CHAR_TERM);
VERIFY_SYSCONF_UNSUPPORTED(_SC_2_LOCALEDEF);
VERIFY_SYSCONF_UNSUPPORTED(_SC_2_SW_DEV);
- VERIFY_SYSCONF_UNSUPPORTED(_SC_2_VERSION);
VERIFY_SYSCONF_UNSUPPORTED(_SC_XOPEN_CRYPT);
VERIFY_SYSCONF_UNSUPPORTED(_SC_XOPEN_ENH_I18N);
@@ -1372,3 +1372,10 @@
ASSERT_EXIT(execve("/system/bin/run-as", args, envs), testing::ExitedWithCode(1),
"<unknown>: usage: run-as");
}
+
+TEST(UNISTD_TEST, getlogin_r) {
+ char buf[LOGIN_NAME_MAX] = {};
+ EXPECT_EQ(ERANGE, getlogin_r(buf, 0));
+ EXPECT_EQ(0, getlogin_r(buf, sizeof(buf)));
+ EXPECT_STREQ(getlogin(), buf);
+}
diff --git a/tests/wchar_test.cpp b/tests/wchar_test.cpp
index 097647f..a795d2c 100644
--- a/tests/wchar_test.cpp
+++ b/tests/wchar_test.cpp
@@ -754,3 +754,80 @@
TEST(wchar, wcstold) {
CheckWcsToFloat(wcstold);
}
+
+static void AssertWcwidthRange(wchar_t begin, wchar_t end, int expected) {
+ for (wchar_t i = begin; i < end; ++i) {
+ EXPECT_EQ(expected, wcwidth(i)) << static_cast<int>(i);
+ }
+}
+
+TEST(wchar, wcwidth_NUL) {
+ // NUL is defined to return 0 rather than -1, despite being a C0 control.
+ EXPECT_EQ(0, wcwidth(0));
+}
+
+TEST(wchar, wcwidth_ascii) {
+ AssertWcwidthRange(0x20, 0x7f, 1); // Non-C0 non-DEL ASCII.
+}
+
+TEST(wchar, wcwidth_controls) {
+ AssertWcwidthRange(0x01, 0x20, -1); // C0 controls.
+ EXPECT_EQ(-1, wcwidth(0x7f)); // DEL.
+ AssertWcwidthRange(0x80, 0xa0, -1); // C1 controls.
+}
+
+TEST(wchar, wcwidth_non_spacing_and_enclosing_marks_and_format) {
+ EXPECT_EQ(0, wcwidth(0x0300)); // Combining grave.
+ EXPECT_EQ(0, wcwidth(0x20dd)); // Combining enclosing circle.
+ EXPECT_EQ(0, wcwidth(0x00ad)); // Soft hyphen (SHY).
+ EXPECT_EQ(0, wcwidth(0x200b)); // Zero width space.
+}
+
+TEST(wchar, wcwidth_cjk) {
+ EXPECT_EQ(2, wcwidth(0x4e00)); // Start of CJK unified block.
+ EXPECT_EQ(2, wcwidth(0x9fff)); // End of CJK unified block.
+ EXPECT_EQ(2, wcwidth(0x3400)); // Start of CJK extension A block.
+ EXPECT_EQ(2, wcwidth(0x4dbf)); // End of CJK extension A block.
+ EXPECT_EQ(2, wcwidth(0x20000)); // Start of CJK extension B block.
+ EXPECT_EQ(2, wcwidth(0x2a6df)); // End of CJK extension B block.
+}
+
+TEST(wchar, wcwidth_korean_combining_jamo) {
+ AssertWcwidthRange(0x1160, 0x1200, 0); // Original range.
+ EXPECT_EQ(0, wcwidth(0xd7b0)); // Newer.
+ EXPECT_EQ(0, wcwidth(0xd7cb));
+}
+
+TEST(wchar, wcwidth_korean_jeongeul_syllables) {
+ EXPECT_EQ(2, wcwidth(0xac00)); // Start of block.
+ EXPECT_EQ(2, wcwidth(0xd7a3)); // End of defined code points in Unicode 7.
+ // Undefined characters at the end of the block have width 1.
+}
+
+TEST(wchar, wcwidth_kana) {
+ // Hiragana (most, not undefined).
+ AssertWcwidthRange(0x3041, 0x3097, 2);
+ // Katakana.
+ AssertWcwidthRange(0x30a0, 0x3100, 2);
+}
+
+TEST(wchar, wcwidth_circled_two_digit_cjk) {
+ // Circled two-digit CJK "speed sign" numbers are wide,
+ // though EastAsianWidth is ambiguous.
+ AssertWcwidthRange(0x3248, 0x3250, 2);
+}
+
+TEST(wchar, wcwidth_hexagrams) {
+ // Hexagrams are wide, though EastAsianWidth is neutral.
+ AssertWcwidthRange(0x4dc0, 0x4e00, 2);
+}
+
+TEST(wchar, wcwidth_default_ignorables) {
+ AssertWcwidthRange(0xfff0, 0xfff8, 0); // Unassigned by default ignorable.
+ EXPECT_EQ(0, wcwidth(0xe0000)); // ...through 0xe0fff.
+}
+
+TEST(wchar, wcwidth_korean_common_non_syllables) {
+ EXPECT_EQ(2, wcwidth(L'ㅜ')); // Korean "crying" emoticon.
+ EXPECT_EQ(2, wcwidth(L'ㅋ')); // Korean "laughing" emoticon.
+}
diff --git a/tools/versioner/src/Driver.cpp b/tools/versioner/src/Driver.cpp
index 1b631b6..a094818 100644
--- a/tools/versioner/src/Driver.cpp
+++ b/tools/versioner/src/Driver.cpp
@@ -100,11 +100,12 @@
std::vector<std::string> cmd = { "versioner" };
cmd.push_back("-std=c11");
cmd.push_back("-x");
- cmd.push_back("c-header");
+ cmd.push_back("c");
cmd.push_back("-fsyntax-only");
cmd.push_back("-Wall");
cmd.push_back("-Wextra");
+ cmd.push_back("-Weverything");
cmd.push_back("-Werror");
cmd.push_back("-Wundef");
cmd.push_back("-Wno-unused-macros");
@@ -134,7 +135,9 @@
cmd.push_back(dir);
}
+ cmd.push_back("-include");
cmd.push_back(filename_placeholder);
+ cmd.push_back("-");
auto diags = constructDiags();
driver::Driver driver("versioner", llvm::sys::getDefaultTargetTriple(), *diags, vfs);
diff --git a/tools/versioner/src/versioner.cpp b/tools/versioner/src/versioner.cpp
index 735ea04..747c767 100644
--- a/tools/versioner/src/versioner.cpp
+++ b/tools/versioner/src/versioner.cpp
@@ -18,6 +18,7 @@
#include <err.h>
#include <limits.h>
#include <stdio.h>
+#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
@@ -190,6 +191,21 @@
}
}
+ // Dup an empty file to stdin, so that we can use `clang -include a.h -` instead of `clang a.h`,
+ // since some warnings don't get generated in files that are compiled directly.
+ FILE* empty_file = tmpfile();
+ if (!empty_file) {
+ err(1, "failed to create temporary file");
+ }
+
+ int empty_file_fd = fileno(empty_file);
+ if (empty_file_fd == -1) {
+ errx(1, "fileno failed on tmpfile");
+ }
+
+ dup2(empty_file_fd, STDIN_FILENO);
+ fclose(empty_file);
+
thread_count = std::min(thread_count, jobs.size());
if (thread_count == 1) {