Merge "Apply recent strto* fix, add new tests."
diff --git a/README.md b/README.md
index 61314b6..cb9c454 100644
--- a/README.md
+++ b/README.md
@@ -171,6 +171,10 @@
contents for external/kernel-headers/.
2. Run update_all.py to scrub those headers and import them into bionic.
+Note that if you're actually just trying to expose device-specific headers to
+build your device drivers, you shouldn't modify bionic. Instead use
+`TARGET_DEVICE_KERNEL_HEADERS` and friends described in [config.mk](https://android.googlesource.com/platform/build/+/master/core/config.mk#186).
+
Updating tzdata
---------------
@@ -327,19 +331,54 @@
32-bit ABI bugs
---------------
-This probably belongs in the NDK documentation rather than here, but these
-are the known ABI bugs in the 32-bit ABI:
+### `off_t` is 32-bit.
- * `time_t` is 32-bit. <http://b/5819737>. In the 64-bit ABI, time_t is
- 64-bit.
+On 32-bit Android, `off_t` is a signed 32-bit integer. This limits functions
+that use `off_t` to working on files no larger than 2GiB.
- * `off_t` is 32-bit. There is `off64_t`, and in newer releases there is
- almost-complete support for `_FILE_OFFSET_BITS`. Unfortunately our stdio
- implementation uses 32-bit offsets and -- worse -- function pointers to
- functions that use 32-bit offsets, so there's no good way to implement
- the last few pieces <http://b/24807045>. In the 64-bit ABI, off_t is
- off64_t.
+Android does not require the `_LARGEFILE_SOURCE` macro to be used to make
+`fseeko` and `ftello` available. Instead they're always available from API
+level 24 where they were introduced, and never available before then.
- * `sigset_t` is too small on ARM and x86 (but correct on MIPS), so support
- for real-time signals is broken. <http://b/5828899> In the 64-bit ABI,
- `sigset_t` is the correct size for every architecture.
+Android also does not require the `_LARGEFILE64_SOURCE` macro to be used
+to make `off64_t` and corresponding functions such as `ftruncate64` available.
+Instead, whatever subset of those functions was available at your target API
+level will be visible.
+
+There are a couple of exceptions to note. Firstly, `off64_t` and the single
+function `lseek64` were available right from the beginning in API 3. Secondly,
+Android has always silently inserted `O_LARGEFILE` into any open call, so if
+all you need are functions like `read` that don't take/return `off_t`, large
+files have always worked.
+
+Android support for `_FILE_OFFSET_BITS=64` (which turns `off_t` into `off64_t`
+and replaces each `off_t` function with its `off64_t` counterpart, such as
+`lseek` in the source becoming `lseek64` at runtime) was added late. Even when
+it became available for the platform, it wasn't available from the NDK until
+r15. Before NDK r15, `_FILE_OFFSET_BITS=64` silently did nothing: all code
+compiled with that was actually using a 32-bit `off_t`. With a new enough NDK,
+the situation becomes complicated. If you're targeting an API before 21, almost
+all functions that take an `off_t` become unavailable. You've asked for their
+64-bit equivalents, and none of them (except `lseek`/`lseek64`) exist. As you
+increase your target API level, you'll have more and more of the functions
+available. API 12 adds some of the `<unistd.h>` functions, API 21 adds `mmap`,
+and by API 24 you have everything including `<stdio.h>`. See the
+[linker map](libc/libc.map.txt) for full details.
+
+In the 64-bit ABI, `off_t` is always 64-bit.
+
+### `sigset_t` is too small for real-time signals.
+
+On 32-bit Android, `sigset_t` is too small for ARM and x86 (but correct for
+MIPS). This means that there is no support for real-time signals in 32-bit
+code.
+
+In the 64-bit ABI, `sigset_t` is the correct size for every architecture.
+
+### `time_t` is 32-bit.
+
+On 32-bit Android, `time_t` is 32-bit. The header `<time64.h>` and type
+`time64_t` exist as a workaround, but the kernel interfaces exposed on 32-bit
+Android all use the 32-bit `time_t`.
+
+In the 64-bit ABI, `time_t` is 64-bit.
diff --git a/benchmarks/Android.bp b/benchmarks/Android.bp
index 3f95aa1..0edba65 100644
--- a/benchmarks/Android.bp
+++ b/benchmarks/Android.bp
@@ -35,6 +35,17 @@
"time_benchmark.cpp",
"unistd_benchmark.cpp",
],
+ static_libs: ["libBionicBenchmarksUtils"],
+}
+
+cc_defaults {
+ name: "bionic-benchmarks-extras-defaults",
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wunused",
+ ],
}
// Build benchmarks for the device (with bionic's .so). Run with:
@@ -63,3 +74,19 @@
},
},
}
+
+cc_library_static {
+ name: "libBionicBenchmarksUtils",
+ defaults: ["bionic-benchmarks-extras-defaults"],
+ srcs: ["util.cpp"],
+ host_supported: true,
+}
+
+cc_test {
+ name: "bionic-benchmarks-tests",
+ defaults: ["bionic-benchmarks-extras-defaults"],
+ srcs: [
+ "tests/benchmark_test.cpp",
+ ],
+ static_libs: ["libBionicBenchmarksUtils"],
+}
diff --git a/benchmarks/string_benchmark.cpp b/benchmarks/string_benchmark.cpp
index 86a7c35..2ab65a8 100644
--- a/benchmarks/string_benchmark.cpp
+++ b/benchmarks/string_benchmark.cpp
@@ -18,188 +18,246 @@
#include <string.h>
#include <benchmark/benchmark.h>
+#include "util.h"
constexpr auto KB = 1024;
-#define AT_COMMON_SIZES \
- Arg(8)->Arg(64)->Arg(512)->Arg(1*KB)->Arg(8*KB)->Arg(16*KB)->Arg(32*KB)->Arg(64*KB)
+// NOTE: these constants are temporary replacements for AT_COMMON_SIZES until
+// the new interface for Bionic benchmarks is implemented.
-// TODO: test unaligned operation too? (currently everything will be 8-byte aligned by malloc.)
+// Set all four to 0 to test normal alignment.
+#define AT_SRC_ALIGN 0
+#define AT_DST_ALIGN 0
+
+#define AT_ALIGNED_TWOBUF \
+ Args({(8), AT_SRC_ALIGN, AT_DST_ALIGN})->Args({(64), AT_SRC_ALIGN, AT_DST_ALIGN})-> \
+ Args({(512), AT_SRC_ALIGN, AT_DST_ALIGN})->Args({(1*KB), AT_SRC_ALIGN, AT_DST_ALIGN})-> \
+ Args({(8*KB), AT_SRC_ALIGN, AT_DST_ALIGN})->Args({(16*KB), AT_SRC_ALIGN, AT_DST_ALIGN})-> \
+ Args({(32*KB), AT_SRC_ALIGN, AT_DST_ALIGN})->Args({(64*KB), AT_SRC_ALIGN, AT_DST_ALIGN})
+
+#define AT_ALIGNED_ONEBUF \
+ Args({(8), AT_SRC_ALIGN})->Args({(64), AT_SRC_ALIGN})->Args({(512), AT_SRC_ALIGN})-> \
+ Args({(1*KB), AT_SRC_ALIGN})->Args({(8*KB), AT_SRC_ALIGN})->Args({(16*KB), AT_SRC_ALIGN})-> \
+ Args({(32*KB), AT_SRC_ALIGN})->Args({(64*KB), AT_SRC_ALIGN})
static void BM_string_memcmp(benchmark::State& state) {
const size_t nbytes = state.range(0);
- char* src = new char[nbytes]; char* dst = new char[nbytes];
- memset(src, 'x', nbytes);
- memset(dst, 'x', nbytes);
+ const size_t src_alignment = state.range(1);
+ const size_t dst_alignment = state.range(2);
+
+ std::vector<char> src;
+ std::vector<char> dst;
+ char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes, 'x');
+ char* dst_aligned = GetAlignedPtrFilled(&dst, dst_alignment, nbytes, 'x');
volatile int c __attribute__((unused)) = 0;
while (state.KeepRunning()) {
- c += memcmp(dst, src, nbytes);
+ c += memcmp(dst_aligned, src_aligned, nbytes);
}
state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
- delete[] src;
- delete[] dst;
}
-BENCHMARK(BM_string_memcmp)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_memcmp)->AT_ALIGNED_TWOBUF;
static void BM_string_memcpy(benchmark::State& state) {
const size_t nbytes = state.range(0);
- char* src = new char[nbytes]; char* dst = new char[nbytes];
- memset(src, 'x', nbytes);
+ const size_t src_alignment = state.range(1);
+ const size_t dst_alignment = state.range(2);
+
+ std::vector<char> src;
+ std::vector<char> dst;
+ char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes, 'x');
+ char* dst_aligned = GetAlignedPtr(&dst, dst_alignment, nbytes);
while (state.KeepRunning()) {
- memcpy(dst, src, nbytes);
+ memcpy(dst_aligned, src_aligned, nbytes);
}
state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
- delete[] src;
- delete[] dst;
}
-BENCHMARK(BM_string_memcpy)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_memcpy)->AT_ALIGNED_TWOBUF;
static void BM_string_memmove_non_overlapping(benchmark::State& state) {
const size_t nbytes = state.range(0);
- std::vector<char> src(nbytes, 'x');
- std::vector<char> dst(nbytes, 'x');
+ const size_t src_alignment = state.range(1);
+ const size_t dst_alignment = state.range(2);
+
+ std::vector<char> src;
+ std::vector<char> dst;
+ char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes, 'x');
+ char* dst_aligned = GetAlignedPtrFilled(&dst, dst_alignment, nbytes, 'y');
while (state.KeepRunning()) {
- memmove(dst.data(), src.data(), nbytes);
+ memmove(dst_aligned, src_aligned, nbytes);
}
state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
}
-BENCHMARK(BM_string_memmove_non_overlapping)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_memmove_non_overlapping)->AT_ALIGNED_TWOBUF;
static void BM_string_memmove_overlap_dst_before_src(benchmark::State& state) {
const size_t nbytes = state.range(0);
- std::vector<char> buf(nbytes + 1, 'x');
+ const size_t alignment = state.range(1);
+
+ std::vector<char> buf(3 * alignment + nbytes + 1, 'x');
+ char* buf_aligned = GetAlignedPtrFilled(&buf, alignment, nbytes + 1, 'x');
while (state.KeepRunning()) {
- memmove(buf.data(), buf.data() + 1, nbytes); // Worst-case overlap.
+ memmove(buf_aligned, buf_aligned + 1, nbytes); // Worst-case overlap.
}
state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
}
-BENCHMARK(BM_string_memmove_overlap_dst_before_src)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_memmove_overlap_dst_before_src)->AT_ALIGNED_ONEBUF;
static void BM_string_memmove_overlap_src_before_dst(benchmark::State& state) {
const size_t nbytes = state.range(0);
- std::vector<char> buf(nbytes + 1, 'x');
+ const size_t alignment = state.range(1);
+
+ std::vector<char> buf;
+ char* buf_aligned = GetAlignedPtrFilled(&buf, alignment, nbytes + 1, 'x');
while (state.KeepRunning()) {
- memmove(buf.data() + 1, buf.data(), nbytes); // Worst-case overlap.
+ memmove(buf_aligned + 1, buf_aligned, nbytes); // Worst-case overlap.
}
state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
}
-BENCHMARK(BM_string_memmove_overlap_src_before_dst)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_memmove_overlap_src_before_dst)->AT_ALIGNED_ONEBUF;
static void BM_string_memset(benchmark::State& state) {
const size_t nbytes = state.range(0);
- char* dst = new char[nbytes];
+ const size_t alignment = state.range(1);
+
+ std::vector<char> buf;
+ char* buf_aligned = GetAlignedPtr(&buf, alignment, nbytes + 1);
while (state.KeepRunning()) {
- memset(dst, 0, nbytes);
+ memset(buf_aligned, 0, nbytes);
}
state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
- delete[] dst;
}
-BENCHMARK(BM_string_memset)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_memset)->AT_ALIGNED_ONEBUF;
static void BM_string_strlen(benchmark::State& state) {
const size_t nbytes = state.range(0);
- char* s = new char[nbytes];
- memset(s, 'x', nbytes);
- s[nbytes - 1] = 0;
+ const size_t alignment = state.range(1);
+
+ std::vector<char> buf;
+ char* buf_aligned = GetAlignedPtrFilled(&buf, alignment, nbytes + 1, 'x');
+ buf_aligned[nbytes - 1] = '\0';
volatile int c __attribute__((unused)) = 0;
while (state.KeepRunning()) {
- c += strlen(s);
+ c += strlen(buf_aligned);
}
state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
- delete[] s;
}
-BENCHMARK(BM_string_strlen)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_strlen)->AT_ALIGNED_ONEBUF;
static void BM_string_strcat_copy_only(benchmark::State& state) {
const size_t nbytes = state.range(0);
- std::vector<char> src(nbytes, 'x');
- std::vector<char> dst(nbytes + 2);
- src[nbytes - 1] = '\0';
- dst[0] = 'y';
- dst[1] = 'y';
- dst[2] = '\0';
+ const size_t src_alignment = state.range(1);
+ const size_t dst_alignment = state.range(2);
+
+ std::vector<char> src;
+ std::vector<char> dst;
+ char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes, 'x');
+ char* dst_aligned = GetAlignedPtr(&dst, dst_alignment, nbytes + 2);
+ src_aligned[nbytes - 1] = '\0';
+ dst_aligned[0] = 'y';
+ dst_aligned[1] = 'y';
+ dst_aligned[2] = '\0';
while (state.KeepRunning()) {
- strcat(dst.data(), src.data());
- dst[2] = '\0';
+ strcat(dst_aligned, src_aligned);
+ dst_aligned[2] = '\0';
}
state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
}
-BENCHMARK(BM_string_strcat_copy_only)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_strcat_copy_only)->AT_ALIGNED_TWOBUF;
static void BM_string_strcat_seek_only(benchmark::State& state) {
const size_t nbytes = state.range(0);
- std::vector<char> src(3, 'x');
- std::vector<char> dst(nbytes + 2, 'y');
- src[2] = '\0';
- dst[nbytes - 1] = '\0';
+ const size_t src_alignment = state.range(1);
+ const size_t dst_alignment = state.range(2);
+
+ std::vector<char> src;
+ std::vector<char> dst;
+ char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, 3, 'x');
+ char* dst_aligned = GetAlignedPtrFilled(&dst, dst_alignment, nbytes + 2, 'y');
+ src_aligned[2] = '\0';
+ dst_aligned[nbytes - 1] = '\0';
while (state.KeepRunning()) {
- strcat(dst.data(), src.data());
- dst[nbytes - 1] = '\0';
+ strcat(dst_aligned, src_aligned);
+ dst_aligned[nbytes - 1] = '\0';
}
state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
}
-BENCHMARK(BM_string_strcat_seek_only)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_strcat_seek_only)->AT_ALIGNED_TWOBUF;
static void BM_string_strcat_half_copy_half_seek(benchmark::State& state) {
const size_t nbytes = state.range(0);
- std::vector<char> src(nbytes / 2, 'x');
- std::vector<char> dst(nbytes / 2, 'y');
- src[nbytes / 2 - 1] = '\0';
- dst[nbytes / 2 - 1] = '\0';
+ const size_t src_alignment = state.range(1);
+ const size_t dst_alignment = state.range(2);
+
+ std::vector<char> src;
+ std::vector<char> dst;
+ char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes / 2, 'x');
+ char* dst_aligned = GetAlignedPtrFilled(&dst, dst_alignment, nbytes, 'y');
+ src_aligned[nbytes / 2 - 1] = '\0';
+ dst_aligned[nbytes / 2 - 1] = '\0';
while (state.KeepRunning()) {
- strcat(dst.data(), src.data());
- dst[nbytes / 2 - 1] = '\0';
+ strcat(dst_aligned, src_aligned);
+ dst_aligned[nbytes / 2 - 1] = '\0';
}
state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
}
-BENCHMARK(BM_string_strcat_half_copy_half_seek)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_strcat_half_copy_half_seek)->AT_ALIGNED_TWOBUF;
static void BM_string_strcpy(benchmark::State& state) {
const size_t nbytes = state.range(0);
- std::vector<char> src(nbytes, 'x');
- std::vector<char> dst(nbytes);
- src[nbytes - 1] = '\0';
+ const size_t src_alignment = state.range(1);
+ const size_t dst_alignment = state.range(2);
+
+ std::vector<char> src;
+ std::vector<char> dst;
+ char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes, 'x');
+ char* dst_aligned = GetAlignedPtr(&dst, dst_alignment, nbytes);
+ src_aligned[nbytes - 1] = '\0';
while (state.KeepRunning()) {
- strcpy(dst.data(), src.data());
+ strcpy(dst_aligned, src_aligned);
}
state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
}
-BENCHMARK(BM_string_strcpy)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_strcpy)->AT_ALIGNED_TWOBUF;
static void BM_string_strcmp(benchmark::State& state) {
const size_t nbytes = state.range(0);
- std::vector<char> s1(nbytes, 'x');
- std::vector<char> s2(nbytes, 'x');
- s1[nbytes - 1] = '\0';
- s2[nbytes - 1] = '\0';
+ const size_t s1_alignment = state.range(1);
+ const size_t s2_alignment = state.range(2);
+
+ std::vector<char> s1;
+ std::vector<char> s2;
+ char* s1_aligned = GetAlignedPtrFilled(&s1, s1_alignment, nbytes, 'x');
+ char* s2_aligned = GetAlignedPtrFilled(&s2, s2_alignment, nbytes, 'x');
+ s1_aligned[nbytes - 1] = '\0';
+ s2_aligned[nbytes - 1] = '\0';
volatile int c __attribute__((unused));
while (state.KeepRunning()) {
- c = strcmp(s1.data(), s2.data());
+ c = strcmp(s1_aligned, s2_aligned);
}
state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
}
-BENCHMARK(BM_string_strcmp)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_strcmp)->AT_ALIGNED_TWOBUF;
diff --git a/benchmarks/tests/benchmark_test.cpp b/benchmarks/tests/benchmark_test.cpp
new file mode 100644
index 0000000..df7b686
--- /dev/null
+++ b/benchmarks/tests/benchmark_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <util.h>
+
+TEST(benchmark, memory_align) {
+ std::vector<char> buf(100);
+ for (size_t alignment = 1; alignment <= 32; alignment *= 2) {
+ for (size_t or_mask = 0; or_mask < alignment; ++or_mask) {
+ uintptr_t aligned_ptr = reinterpret_cast<uintptr_t>(GetAlignedMemory(buf.data(), alignment,
+ or_mask));
+ ASSERT_EQ(aligned_ptr % alignment, or_mask);
+ ASSERT_EQ(aligned_ptr & alignment, alignment);
+ }
+ }
+}
+
+TEST(benchmark, ptr_align) {
+ std::vector<char> buf;
+ for (size_t alignment = 1; alignment <= 2048; alignment *= 2) {
+ uintptr_t aligned_ptr = reinterpret_cast<uintptr_t>(GetAlignedPtr(&buf, alignment, 100));
+ ASSERT_EQ(aligned_ptr & alignment, alignment);
+ ASSERT_EQ(aligned_ptr & (alignment - 1), 0u);
+ }
+}
diff --git a/benchmarks/util.cpp b/benchmarks/util.cpp
new file mode 100644
index 0000000..d9641cf
--- /dev/null
+++ b/benchmarks/util.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util.h"
+
+#include <sched.h>
+#include <stdio.h>
+#include <string.h>
+#include <cstdlib>
+#include <vector>
+
+// This function returns a pointer less than 2 * alignment + or_mask bytes into the array.
+char *GetAlignedMemory(char *orig_ptr, size_t alignment, size_t or_mask) {
+ if ((alignment & (alignment - 1)) != 0) {
+ fprintf(stderr, "warning: alignment passed into GetAlignedMemory is not a power of two.\n");
+ std::abort();
+ }
+ if (or_mask > alignment) {
+ fprintf(stderr, "warning: or_mask passed into GetAlignedMemory is too high.\n");
+ std::abort();
+ }
+ uintptr_t ptr = reinterpret_cast<uintptr_t>(orig_ptr);
+ if (alignment > 0) {
+ // When setting the alignment, set it to exactly the alignment chosen.
+ // The pointer returned will be guaranteed not to be aligned to anything
+ // more than that.
+ ptr += alignment - (ptr & (alignment - 1));
+ ptr |= alignment | or_mask;
+ }
+
+ return reinterpret_cast<char*>(ptr);
+}
+
+char *GetAlignedPtr(std::vector<char>* buf, size_t alignment, size_t nbytes) {
+ buf->resize(nbytes + 3 * alignment);
+ return GetAlignedMemory(buf->data(), alignment, 0);
+}
+
+char *GetAlignedPtrFilled(std::vector<char>* buf, size_t alignment, size_t nbytes, char fill_byte) {
+ char* buf_aligned = GetAlignedPtr(buf, alignment, nbytes);
+ memset(buf_aligned, fill_byte, nbytes);
+ return buf_aligned;
+}
+
+#if defined(__APPLE__)
+
+// Darwin doesn't support this, so do nothing.
+bool LockToCPU(int) {
+ return false;
+}
+
+#else
+
+bool LockToCPU(int cpu_to_lock) {
+ cpu_set_t cpuset;
+
+ CPU_ZERO(&cpuset);
+ if (sched_getaffinity(0, sizeof(cpuset), &cpuset) != 0) {
+ perror("sched_getaffinity failed");
+ return false;
+ }
+
+ if (cpu_to_lock < 0) {
+ // Lock to the last active core we find.
+ for (int i = 0; i < CPU_SETSIZE; i++) {
+ if (CPU_ISSET(i, &cpuset)) {
+ cpu_to_lock = i;
+ }
+ }
+ } else if (!CPU_ISSET(cpu_to_lock, &cpuset)) {
+ printf("Cpu %d does not exist.\n", cpu_to_lock);
+ return false;
+ }
+
+ if (cpu_to_lock < 0) {
+ printf("Cannot find any valid cpu to lock.\n");
+ return false;
+ }
+
+ CPU_ZERO(&cpuset);
+ CPU_SET(cpu_to_lock, &cpuset);
+ if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) {
+ perror("sched_setaffinity failed");
+ return false;
+ }
+
+ return true;
+}
+
+#endif
diff --git a/benchmarks/util.h b/benchmarks/util.h
new file mode 100644
index 0000000..bd3d515
--- /dev/null
+++ b/benchmarks/util.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _BIONIC_BENCHMARKS_UTIL_H_
+#define _BIONIC_BENCHMARKS_UTIL_H_
+
+#include <vector>
+
+// This function returns a pointer less than 2 * alignment + or_mask bytes into the array.
+char *GetAlignedMemory(char *orig_ptr, size_t alignment, size_t or_mask);
+
+char *GetAlignedPtr(std::vector<char>* buf, size_t alignment, size_t nbytes);
+
+char *GetAlignedPtrFilled(std::vector<char>* buf, size_t alignment, size_t nbytes, char fill_byte);
+
+bool LockToCPU(int cpu_to_lock);
+
+#endif // _BIONIC_BENCHMARKS_UTIL_H
diff --git a/libc/Android.bp b/libc/Android.bp
index cd2a727..be1c6f9 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -237,9 +237,11 @@
"upstream-freebsd/lib/libc/string/wcspbrk.c",
"upstream-freebsd/lib/libc/string/wcsrchr.c",
"upstream-freebsd/lib/libc/string/wcsspn.c",
+ "upstream-freebsd/lib/libc/string/wcsstr.c",
"upstream-freebsd/lib/libc/string/wcstok.c",
"upstream-freebsd/lib/libc/string/wmemchr.c",
"upstream-freebsd/lib/libc/string/wmemcmp.c",
+ "upstream-freebsd/lib/libc/string/wmemcpy.c",
"upstream-freebsd/lib/libc/string/wmemmove.c",
"upstream-freebsd/lib/libc/string/wmemset.c",
],
@@ -385,7 +387,6 @@
name: "libc_openbsd_ndk",
defaults: ["libc_defaults"],
srcs: [
- "upstream-openbsd/lib/libc/compat-43/killpg.c",
"upstream-openbsd/lib/libc/gen/alarm.c",
"upstream-openbsd/lib/libc/gen/ctype_.c",
"upstream-openbsd/lib/libc/gen/daemon.c",
@@ -501,9 +502,7 @@
"upstream-openbsd/lib/libc/string/strspn.c",
"upstream-openbsd/lib/libc/string/strstr.c",
"upstream-openbsd/lib/libc/string/strtok.c",
- "upstream-openbsd/lib/libc/string/wmemcpy.c",
"upstream-openbsd/lib/libc/string/wcslcpy.c",
- "upstream-openbsd/lib/libc/string/wcsstr.c",
"upstream-openbsd/lib/libc/string/wcswidth.c",
],
@@ -1330,6 +1329,13 @@
cc_library_static {
defaults: ["libc_defaults"],
srcs: [
+ "bionic/NetdClientDispatch.cpp",
+ "bionic/__cmsg_nxthdr.cpp",
+ "bionic/__errno.cpp",
+ "bionic/__gnu_basename.cpp",
+ "bionic/__libc_current_sigrtmax.cpp",
+ "bionic/__libc_current_sigrtmin.cpp",
+ "bionic/__set_errno.cpp",
"bionic/abort.cpp",
"bionic/accept.cpp",
"bionic/accept4.cpp",
@@ -1352,7 +1358,6 @@
"bionic/clock_nanosleep.cpp",
"bionic/clone.cpp",
"bionic/close.cpp",
- "bionic/__cmsg_nxthdr.cpp",
"bionic/connect.cpp",
"bionic/ctype.cpp",
"bionic/dirent.cpp",
@@ -1361,7 +1366,6 @@
"bionic/epoll_create.cpp",
"bionic/epoll_pwait.cpp",
"bionic/epoll_wait.cpp",
- "bionic/__errno.cpp",
"bionic/error.cpp",
"bionic/eventfd_read.cpp",
"bionic/eventfd_write.cpp",
@@ -1387,16 +1391,14 @@
"bionic/getpid.cpp",
"bionic/getpriority.cpp",
"bionic/gettid.cpp",
- "bionic/__gnu_basename.cpp",
"bionic/grp_pwd.cpp",
"bionic/ifaddrs.cpp",
"bionic/inotify_init.cpp",
"bionic/ioctl.cpp",
+ "bionic/killpg.cpp",
"bionic/langinfo.cpp",
"bionic/lchown.cpp",
"bionic/lfs64_support.cpp",
- "bionic/__libc_current_sigrtmax.cpp",
- "bionic/__libc_current_sigrtmin.cpp",
"bionic/libc_init_common.cpp",
"bionic/libgen.cpp",
"bionic/link.cpp",
@@ -1407,7 +1409,6 @@
"bionic/mblen.cpp",
"bionic/mbrtoc16.cpp",
"bionic/mbrtoc32.cpp",
- "bionic/mbstate.cpp",
"bionic/memmem.cpp",
"bionic/mempcpy.cpp",
"bionic/mkdir.cpp",
@@ -1415,9 +1416,8 @@
"bionic/mknod.cpp",
"bionic/mntent.cpp",
"bionic/mremap.cpp",
- "bionic/netdb.cpp",
- "bionic/NetdClientDispatch.cpp",
"bionic/net_if.cpp",
+ "bionic/netdb.cpp",
"bionic/netinet_in.cpp",
"bionic/nl_types.cpp",
"bionic/open.cpp",
@@ -1444,7 +1444,6 @@
"bionic/semaphore.cpp",
"bionic/send.cpp",
"bionic/setegid.cpp",
- "bionic/__set_errno.cpp",
"bionic/seteuid.cpp",
"bionic/setpgrp.cpp",
"bionic/sigaction.cpp",
@@ -1470,21 +1469,24 @@
"bionic/socket.cpp",
"bionic/stat.cpp",
"bionic/statvfs.cpp",
+ "bionic/stdlib_l.cpp",
"bionic/strchrnul.cpp",
"bionic/strerror.cpp",
"bionic/strerror_r.cpp",
+ "bionic/string_l.cpp",
+ "bionic/strings_l.cpp",
"bionic/strsignal.cpp",
"bionic/strtold.cpp",
"bionic/symlink.cpp",
"bionic/sync_file_range.cpp",
- "bionic/sysinfo.cpp",
- "bionic/syslog.cpp",
"bionic/sys_msg.cpp",
"bionic/sys_sem.cpp",
"bionic/sys_shm.cpp",
"bionic/sys_siglist.c",
"bionic/sys_signame.c",
"bionic/sys_time.cpp",
+ "bionic/sysinfo.cpp",
+ "bionic/syslog.cpp",
"bionic/system_properties.cpp",
"bionic/tdestroy.cpp",
"bionic/termios.cpp",
@@ -1494,6 +1496,7 @@
"bionic/unlink.cpp",
"bionic/wait.cpp",
"bionic/wchar.cpp",
+ "bionic/wchar_l.cpp",
"bionic/wcstod.cpp",
"bionic/wctype.cpp",
"bionic/wmempcpy.cpp",
diff --git a/libc/NOTICE b/libc/NOTICE
index bcc9691..ae98d1d 100644
--- a/libc/NOTICE
+++ b/libc/NOTICE
@@ -862,22 +862,6 @@
http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
--------------------------------------------------------------------
-
-Copyright (C) 2015 The Android Open Source Project
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -5403,32 +5387,6 @@
-------------------------------------------------------------------
-Copyright (c) 2013 David Chisnall
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-2. 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 AUTHOR 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 AUTHOR 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.
-
--------------------------------------------------------------------
-
Copyright (c) 2013 The NetBSD Foundation, Inc.
All rights reserved.
diff --git a/libc/bionic/c16rtomb.cpp b/libc/bionic/c16rtomb.cpp
index 77512be..93749c6 100644
--- a/libc/bionic/c16rtomb.cpp
+++ b/libc/bionic/c16rtomb.cpp
@@ -50,18 +50,18 @@
mbstate_set_byte(state, 2, (c32 & 0x00ff00) >> 8);
return 0;
} else if (is_low_surrogate(c16)) {
- return reset_and_return_illegal(EINVAL, state);
+ return mbstate_reset_and_return_illegal(EINVAL, state);
} else {
return c32rtomb(s, static_cast<char32_t>(c16), state);
}
} else {
if (!is_low_surrogate(c16)) {
- return reset_and_return_illegal(EINVAL, state);
+ return mbstate_reset_and_return_illegal(EINVAL, state);
}
char32_t c32 = ((mbstate_get_byte(state, 3) << 16) |
(mbstate_get_byte(state, 2) << 8) |
(c16 & ~0xdc00)) + 0x10000;
- return reset_and_return(c32rtomb(s, c32, NULL), state);
+ return mbstate_reset_and_return(c32rtomb(s, c32, NULL), state);
}
}
diff --git a/libc/bionic/c32rtomb.cpp b/libc/bionic/c32rtomb.cpp
index d3231c0..ebe9cd3 100644
--- a/libc/bionic/c32rtomb.cpp
+++ b/libc/bionic/c32rtomb.cpp
@@ -38,7 +38,7 @@
if (s == NULL) {
// Equivalent to c32rtomb(buf, U'\0', ps).
- return reset_and_return(1, state);
+ return mbstate_reset_and_return(1, state);
}
// POSIX states that if char32_t is a null wide character, a null byte shall
@@ -47,11 +47,11 @@
// stored.
if (c32 == U'\0') {
*s = '\0';
- reset_and_return(1, state);
+ return mbstate_reset_and_return(1, state);
}
if (!mbsinit(state)) {
- return reset_and_return_illegal(EILSEQ, state);
+ return mbstate_reset_and_return_illegal(EILSEQ, state);
}
if ((c32 & ~0x7f) == 0) {
diff --git a/libc/bionic/getcwd.cpp b/libc/bionic/getcwd.cpp
index c2a7e23..50487ec 100644
--- a/libc/bionic/getcwd.cpp
+++ b/libc/bionic/getcwd.cpp
@@ -26,7 +26,6 @@
* SUCH DAMAGE.
*/
-#undef _FORTIFY_SOURCE
#include <errno.h>
#include <malloc.h>
#include <string.h>
diff --git a/libc/bionic/mbstate.cpp b/libc/bionic/killpg.cpp
similarity index 63%
rename from libc/bionic/mbstate.cpp
rename to libc/bionic/killpg.cpp
index cb327d8..01a58b3 100644
--- a/libc/bionic/mbstate.cpp
+++ b/libc/bionic/killpg.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,32 +26,13 @@
* SUCH DAMAGE.
*/
-#include "private/bionic_mbstate.h"
-
#include <errno.h>
+#include <signal.h>
-__LIBC_HIDDEN__ size_t mbstate_bytes_so_far(const mbstate_t* ps) {
- return
- (ps->__seq[2] != 0) ? 3 :
- (ps->__seq[1] != 0) ? 2 :
- (ps->__seq[0] != 0) ? 1 : 0;
-}
-
-__LIBC_HIDDEN__ void mbstate_set_byte(mbstate_t* ps, int i, char byte) {
- ps->__seq[i] = static_cast<uint8_t>(byte);
-}
-
-__LIBC_HIDDEN__ uint8_t mbstate_get_byte(const mbstate_t* ps, int n) {
- return ps->__seq[n];
-}
-
-__LIBC_HIDDEN__ size_t reset_and_return_illegal(int _errno, mbstate_t* ps) {
- errno = _errno;
- *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
- return __MB_ERR_ILLEGAL_SEQUENCE;
-}
-
-__LIBC_HIDDEN__ size_t reset_and_return(int _return, mbstate_t* ps) {
- *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
- return _return;
+int killpg(pid_t pgrp, int sig) {
+ if (pgrp < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ return kill(-pgrp, sig);
}
diff --git a/libc/bionic/locale.cpp b/libc/bionic/locale.cpp
index 38e15b7..08c9401 100644
--- a/libc/bionic/locale.cpp
+++ b/libc/bionic/locale.cpp
@@ -37,7 +37,15 @@
#include "private/bionic_macros.h"
+#if defined(__BIONIC_BUILD_FOR_ANDROID_SUPPORT)
+#define USE_TLS_SLOT 0
+#else
+#define USE_TLS_SLOT 1
+#endif
+
+#if USE_TLS_SLOT
#include "bionic/pthread_internal.h"
+#endif
// We only support two locales, the "C" locale (also known as "POSIX"),
// and the "C.UTF-8" locale (also known as "en_US.UTF-8").
@@ -70,6 +78,10 @@
}
}
+#if !USE_TLS_SLOT
+static thread_local locale_t g_current_locale;
+#endif
+
static pthread_once_t g_locale_once = PTHREAD_ONCE_INIT;
static lconv g_locale;
@@ -163,9 +175,16 @@
return const_cast<char*>(__bionic_current_locale_is_utf8 ? "C.UTF-8" : "C");
}
+static locale_t* get_current_locale_ptr() {
+#if USE_TLS_SLOT
+ return &__get_bionic_tls().locale;
+#else
+ return &g_current_locale;
+#endif
+}
+
locale_t uselocale(locale_t new_locale) {
- locale_t* locale_storage = &__get_bionic_tls().locale;
- locale_t old_locale = *locale_storage;
+ locale_t old_locale = *get_current_locale_ptr();
// If this is the first call to uselocale(3) on this thread, we return LC_GLOBAL_LOCALE.
if (old_locale == NULL) {
@@ -173,64 +192,8 @@
}
if (new_locale != NULL) {
- *locale_storage = new_locale;
+ *get_current_locale_ptr() = new_locale;
}
return old_locale;
}
-
-int strcasecmp_l(const char* s1, const char* s2, locale_t) {
- return strcasecmp(s1, s2);
-}
-
-int strcoll_l(const char* s1, const char* s2, locale_t) {
- return strcoll(s1, s2);
-}
-
-char* strerror_l(int error, locale_t) {
- return strerror(error);
-}
-
-int strncasecmp_l(const char* s1, const char* s2, size_t n, locale_t) {
- return strncasecmp(s1, s2, n);
-}
-
-double strtod_l(const char* s, char** end_ptr, locale_t) {
- return strtod(s, end_ptr);
-}
-
-float strtof_l(const char* s, char** end_ptr, locale_t) {
- return strtof(s, end_ptr);
-}
-
-long strtol_l(const char* s, char** end_ptr, int base, locale_t) {
- return strtol(s, end_ptr, base);
-}
-
-long double strtold_l(const char* s, char** end_ptr, locale_t) {
- return strtold(s, end_ptr);
-}
-
-long long strtoll_l(const char* s, char** end_ptr, int base, locale_t) {
- return strtoll(s, end_ptr, base);
-}
-
-unsigned long strtoul_l(const char* s, char** end_ptr, int base, locale_t) {
- return strtoul(s, end_ptr, base);
-}
-
-unsigned long long strtoull_l(const char* s, char** end_ptr, int base, locale_t) {
- return strtoull(s, end_ptr, base);
-}
-
-size_t strxfrm_l(char* dst, const char* src, size_t n, locale_t) {
- return strxfrm(dst, src, n);
-}
-
-int wcscasecmp_l(const wchar_t* ws1, const wchar_t* ws2, locale_t) {
- return wcscasecmp(ws1, ws2);
-}
-
-int wcsncasecmp_l(const wchar_t* ws1, const wchar_t* ws2, size_t n, locale_t) {
- return wcsncasecmp(ws1, ws2, n);
-}
diff --git a/libc/bionic/mbrtoc16.cpp b/libc/bionic/mbrtoc16.cpp
index 6878a11..2180516 100644
--- a/libc/bionic/mbrtoc16.cpp
+++ b/libc/bionic/mbrtoc16.cpp
@@ -55,7 +55,7 @@
char16_t trail = mbstate_get_byte(state, 1) << 8 |
mbstate_get_byte(state, 0);
*pc16 = trail;
- return reset_and_return(mbstate_get_byte(state, 3), state);
+ return mbstate_reset_and_return(mbstate_get_byte(state, 3), state);
}
size_t mbrtoc16(char16_t* pc16, const char* s, size_t n, mbstate_t* ps) {
@@ -76,13 +76,13 @@
if (__MB_IS_ERR(nconv)) {
return nconv;
} else if (nconv == 0) {
- return reset_and_return(nconv, state);
+ return mbstate_reset_and_return(nconv, state);
} else if (c32 > 0x10ffff) {
// Input cannot be encoded as UTF-16.
- return reset_and_return_illegal(EILSEQ, state);
+ return mbstate_reset_and_return_illegal(EILSEQ, state);
} else if (c32 < 0x10000) {
*pc16 = static_cast<char16_t>(c32);
- return reset_and_return(nconv, state);
+ return mbstate_reset_and_return(nconv, state);
} else {
return begin_surrogate(c32, pc16, nconv, state);
}
diff --git a/libc/bionic/mbrtoc32.cpp b/libc/bionic/mbrtoc32.cpp
index bd40ecf..f004b78 100644
--- a/libc/bionic/mbrtoc32.cpp
+++ b/libc/bionic/mbrtoc32.cpp
@@ -41,7 +41,7 @@
// Full state verification is done when decoding the sequence (after we have
// all the bytes).
if (mbstate_get_byte(state, 3) != 0) {
- return reset_and_return_illegal(EINVAL, state);
+ return mbstate_reset_and_return_illegal(EINVAL, state);
}
if (s == NULL) {
@@ -98,7 +98,7 @@
lower_bound = 0x10000;
} else {
// Malformed input; input is not UTF-8. See RFC 3629.
- return reset_and_return_illegal(EILSEQ, state);
+ return mbstate_reset_and_return_illegal(EILSEQ, state);
}
// Fill in the state.
@@ -107,7 +107,7 @@
for (i = 0; i < MIN(bytes_wanted, n); i++) {
if (!mbsinit(state) && ((*s & 0xc0) != 0x80)) {
// Malformed input; bad characters in the middle of a character.
- return reset_and_return_illegal(EILSEQ, state);
+ return mbstate_reset_and_return_illegal(EILSEQ, state);
}
mbstate_set_byte(state, bytes_so_far + i, *s++);
}
@@ -125,14 +125,14 @@
if (c32 < lower_bound) {
// Malformed input; redundant encoding.
- return reset_and_return_illegal(EILSEQ, state);
+ return mbstate_reset_and_return_illegal(EILSEQ, state);
}
if ((c32 >= 0xd800 && c32 <= 0xdfff) || c32 == 0xfffe || c32 == 0xffff) {
// Malformed input; invalid code points.
- return reset_and_return_illegal(EILSEQ, state);
+ return mbstate_reset_and_return_illegal(EILSEQ, state);
}
if (pc32 != NULL) {
*pc32 = c32;
}
- return reset_and_return(c32 == U'\0' ? 0 : bytes_wanted, state);
+ return mbstate_reset_and_return(c32 == U'\0' ? 0 : bytes_wanted, state);
}
diff --git a/libc/bionic/poll.cpp b/libc/bionic/poll.cpp
index eded56a..dbc9584 100644
--- a/libc/bionic/poll.cpp
+++ b/libc/bionic/poll.cpp
@@ -26,7 +26,6 @@
* SUCH DAMAGE.
*/
-#undef _FORTIFY_SOURCE
#include <errno.h>
#include <sys/poll.h>
#include <sys/select.h>
diff --git a/libc/bionic/readlink.cpp b/libc/bionic/readlink.cpp
index a53f933..3bb7bc1 100644
--- a/libc/bionic/readlink.cpp
+++ b/libc/bionic/readlink.cpp
@@ -26,8 +26,6 @@
* SUCH DAMAGE.
*/
-#undef _FORTIFY_SOURCE
-
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
diff --git a/libc/bionic/recv.cpp b/libc/bionic/recv.cpp
index 061cd46..60f264d 100644
--- a/libc/bionic/recv.cpp
+++ b/libc/bionic/recv.cpp
@@ -26,7 +26,6 @@
* SUCH DAMAGE.
*/
-#undef _FORTIFY_SOURCE
#include <sys/socket.h>
ssize_t recv(int socket, void *buf, size_t len, int flags) {
diff --git a/libc/bionic/mbstate.cpp b/libc/bionic/stdlib_l.cpp
similarity index 62%
copy from libc/bionic/mbstate.cpp
copy to libc/bionic/stdlib_l.cpp
index cb327d8..18e9f86 100644
--- a/libc/bionic/mbstate.cpp
+++ b/libc/bionic/stdlib_l.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,32 +26,34 @@
* SUCH DAMAGE.
*/
-#include "private/bionic_mbstate.h"
+#include <stdlib.h>
+#include <xlocale.h>
-#include <errno.h>
-
-__LIBC_HIDDEN__ size_t mbstate_bytes_so_far(const mbstate_t* ps) {
- return
- (ps->__seq[2] != 0) ? 3 :
- (ps->__seq[1] != 0) ? 2 :
- (ps->__seq[0] != 0) ? 1 : 0;
+double strtod_l(const char* s, char** end_ptr, locale_t) {
+ return strtod(s, end_ptr);
}
-__LIBC_HIDDEN__ void mbstate_set_byte(mbstate_t* ps, int i, char byte) {
- ps->__seq[i] = static_cast<uint8_t>(byte);
+float strtof_l(const char* s, char** end_ptr, locale_t) {
+ return strtof(s, end_ptr);
}
-__LIBC_HIDDEN__ uint8_t mbstate_get_byte(const mbstate_t* ps, int n) {
- return ps->__seq[n];
+long strtol_l(const char* s, char** end_ptr, int base, locale_t) {
+ return strtol(s, end_ptr, base);
}
-__LIBC_HIDDEN__ size_t reset_and_return_illegal(int _errno, mbstate_t* ps) {
- errno = _errno;
- *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
- return __MB_ERR_ILLEGAL_SEQUENCE;
+long double strtold_l(const char* s, char** end_ptr, locale_t) {
+ return strtold(s, end_ptr);
}
-__LIBC_HIDDEN__ size_t reset_and_return(int _return, mbstate_t* ps) {
- *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
- return _return;
+long long strtoll_l(const char* s, char** end_ptr, int base, locale_t) {
+ return strtoll(s, end_ptr, base);
}
+
+unsigned long strtoul_l(const char* s, char** end_ptr, int base, locale_t) {
+ return strtoul(s, end_ptr, base);
+}
+
+unsigned long long strtoull_l(const char* s, char** end_ptr, int base, locale_t) {
+ return strtoull(s, end_ptr, base);
+}
+
diff --git a/libc/bionic/strchr.cpp b/libc/bionic/strchr.cpp
index 5bd3f19..fd8a924 100644
--- a/libc/bionic/strchr.cpp
+++ b/libc/bionic/strchr.cpp
@@ -27,7 +27,6 @@
* SUCH DAMAGE.
*/
-#undef _FORTIFY_SOURCE
#include <string.h>
char* strchr(const char* p, int ch) {
diff --git a/libc/bionic/mbstate.cpp b/libc/bionic/string_l.cpp
similarity index 62%
copy from libc/bionic/mbstate.cpp
copy to libc/bionic/string_l.cpp
index cb327d8..66bfb0e 100644
--- a/libc/bionic/mbstate.cpp
+++ b/libc/bionic/string_l.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,32 +26,17 @@
* SUCH DAMAGE.
*/
-#include "private/bionic_mbstate.h"
+#include <string.h>
+#include <xlocale.h>
-#include <errno.h>
-
-__LIBC_HIDDEN__ size_t mbstate_bytes_so_far(const mbstate_t* ps) {
- return
- (ps->__seq[2] != 0) ? 3 :
- (ps->__seq[1] != 0) ? 2 :
- (ps->__seq[0] != 0) ? 1 : 0;
+int strcoll_l(const char* s1, const char* s2, locale_t) {
+ return strcoll(s1, s2);
}
-__LIBC_HIDDEN__ void mbstate_set_byte(mbstate_t* ps, int i, char byte) {
- ps->__seq[i] = static_cast<uint8_t>(byte);
+char* strerror_l(int error, locale_t) {
+ return strerror(error);
}
-__LIBC_HIDDEN__ uint8_t mbstate_get_byte(const mbstate_t* ps, int n) {
- return ps->__seq[n];
-}
-
-__LIBC_HIDDEN__ size_t reset_and_return_illegal(int _errno, mbstate_t* ps) {
- errno = _errno;
- *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
- return __MB_ERR_ILLEGAL_SEQUENCE;
-}
-
-__LIBC_HIDDEN__ size_t reset_and_return(int _return, mbstate_t* ps) {
- *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
- return _return;
+size_t strxfrm_l(char* dst, const char* src, size_t n, locale_t) {
+ return strxfrm(dst, src, n);
}
diff --git a/libc/bionic/mbstate.cpp b/libc/bionic/strings_l.cpp
similarity index 62%
copy from libc/bionic/mbstate.cpp
copy to libc/bionic/strings_l.cpp
index cb327d8..0983ab1 100644
--- a/libc/bionic/mbstate.cpp
+++ b/libc/bionic/strings_l.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,32 +26,13 @@
* SUCH DAMAGE.
*/
-#include "private/bionic_mbstate.h"
+#include <strings.h>
+#include <xlocale.h>
-#include <errno.h>
-
-__LIBC_HIDDEN__ size_t mbstate_bytes_so_far(const mbstate_t* ps) {
- return
- (ps->__seq[2] != 0) ? 3 :
- (ps->__seq[1] != 0) ? 2 :
- (ps->__seq[0] != 0) ? 1 : 0;
+int strcasecmp_l(const char* s1, const char* s2, locale_t) {
+ return strcasecmp(s1, s2);
}
-__LIBC_HIDDEN__ void mbstate_set_byte(mbstate_t* ps, int i, char byte) {
- ps->__seq[i] = static_cast<uint8_t>(byte);
-}
-
-__LIBC_HIDDEN__ uint8_t mbstate_get_byte(const mbstate_t* ps, int n) {
- return ps->__seq[n];
-}
-
-__LIBC_HIDDEN__ size_t reset_and_return_illegal(int _errno, mbstate_t* ps) {
- errno = _errno;
- *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
- return __MB_ERR_ILLEGAL_SEQUENCE;
-}
-
-__LIBC_HIDDEN__ size_t reset_and_return(int _return, mbstate_t* ps) {
- *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
- return _return;
+int strncasecmp_l(const char* s1, const char* s2, size_t n, locale_t) {
+ return strncasecmp(s1, s2, n);
}
diff --git a/libc/bionic/strrchr.cpp b/libc/bionic/strrchr.cpp
index 3fdb47c..b6c40f4 100644
--- a/libc/bionic/strrchr.cpp
+++ b/libc/bionic/strrchr.cpp
@@ -27,7 +27,6 @@
* SUCH DAMAGE.
*/
-#undef _FORTIFY_SOURCE
#include <string.h>
char* strrchr(const char* p, int ch) {
diff --git a/libc/bionic/wchar.cpp b/libc/bionic/wchar.cpp
index 7717e10..62023d6 100644
--- a/libc/bionic/wchar.cpp
+++ b/libc/bionic/wchar.cpp
@@ -74,7 +74,7 @@
// character appears as anything but the first byte of a
// multibyte sequence. Check now to avoid doing it in the loops.
if (nmc > 0 && mbstate_bytes_so_far(state) > 0 && static_cast<uint8_t>((*src)[0]) < 0x80) {
- return reset_and_return_illegal(EILSEQ, state);
+ return mbstate_reset_and_return_illegal(EILSEQ, state);
}
// Measure only?
@@ -83,23 +83,23 @@
if (static_cast<uint8_t>((*src)[i]) < 0x80) {
// Fast path for plain ASCII characters.
if ((*src)[i] == '\0') {
- return reset_and_return(o, state);
+ return mbstate_reset_and_return(o, state);
}
r = 1;
} else {
r = mbrtowc(NULL, *src + i, nmc - i, state);
if (r == __MB_ERR_ILLEGAL_SEQUENCE) {
- return reset_and_return_illegal(EILSEQ, state);
+ return mbstate_reset_and_return_illegal(EILSEQ, state);
}
if (r == __MB_ERR_INCOMPLETE_SEQUENCE) {
- return reset_and_return_illegal(EILSEQ, state);
+ return mbstate_reset_and_return_illegal(EILSEQ, state);
}
if (r == 0) {
- return reset_and_return(o, state);
+ return mbstate_reset_and_return(o, state);
}
}
}
- return reset_and_return(o, state);
+ return mbstate_reset_and_return(o, state);
}
// Actually convert, updating `dst` and `src`.
@@ -110,26 +110,26 @@
r = 1;
if ((*src)[i] == '\0') {
*src = nullptr;
- return reset_and_return(o, state);
+ return mbstate_reset_and_return(o, state);
}
} else {
r = mbrtowc(dst + o, *src + i, nmc - i, state);
if (r == __MB_ERR_ILLEGAL_SEQUENCE) {
*src += i;
- return reset_and_return_illegal(EILSEQ, state);
+ return mbstate_reset_and_return_illegal(EILSEQ, state);
}
if (r == __MB_ERR_INCOMPLETE_SEQUENCE) {
*src += nmc;
- return reset_and_return(EILSEQ, state);
+ return mbstate_reset_and_return_illegal(EILSEQ, state);
}
if (r == 0) {
*src = NULL;
- return reset_and_return(o, state);
+ return mbstate_reset_and_return(o, state);
}
}
}
*src += i;
- return reset_and_return(o, state);
+ return mbstate_reset_and_return(o, state);
}
size_t mbsrtowcs(wchar_t* dst, const char** src, size_t len, mbstate_t* ps) {
@@ -149,7 +149,7 @@
mbstate_t* state = (ps == NULL) ? &__private_state : ps;
if (!mbsinit(state)) {
- return reset_and_return_illegal(EILSEQ, state);
+ return mbstate_reset_and_return_illegal(EILSEQ, state);
}
char buf[MB_LEN_MAX];
@@ -210,25 +210,3 @@
size_t wcsrtombs(char* dst, const wchar_t** src, size_t len, mbstate_t* ps) {
return wcsnrtombs(dst, src, SIZE_MAX, len, ps);
}
-
-int wcscoll_l(const wchar_t *ws1, const wchar_t *ws2, locale_t) {
- return wcscoll(ws1, ws2);
-}
-
-size_t wcsxfrm_l(wchar_t *dest, const wchar_t *src, size_t n, locale_t) {
- return wcsxfrm(dest, src, n);
-}
-
-long long wcstoll_l(const wchar_t *nptr, wchar_t **endptr, int base,
- locale_t) {
- return wcstoll(nptr, endptr, base);
-}
-
-unsigned long long wcstoull_l(const wchar_t *nptr, wchar_t **endptr,
- int base, locale_t) {
- return wcstoull(nptr, endptr, base);
-}
-
-long double wcstold_l(const wchar_t *nptr, wchar_t **endptr, locale_t) {
- return wcstold(nptr, endptr);
-}
diff --git a/libc/bionic/wchar_l.cpp b/libc/bionic/wchar_l.cpp
new file mode 100644
index 0000000..6c39e8d
--- /dev/null
+++ b/libc/bionic/wchar_l.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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 <xlocale.h>
+
+int wcscasecmp_l(const wchar_t* ws1, const wchar_t* ws2, locale_t) {
+ return wcscasecmp(ws1, ws2);
+}
+
+int wcsncasecmp_l(const wchar_t* ws1, const wchar_t* ws2, size_t n, locale_t) {
+ return wcsncasecmp(ws1, ws2, n);
+}
+
+int wcscoll_l(const wchar_t *ws1, const wchar_t *ws2, locale_t) {
+ return wcscoll(ws1, ws2);
+}
+
+size_t wcsxfrm_l(wchar_t *dest, const wchar_t *src, size_t n, locale_t) {
+ return wcsxfrm(dest, src, n);
+}
+
+long long wcstoll_l(const wchar_t *nptr, wchar_t **endptr, int base,
+ locale_t) {
+ return wcstoll(nptr, endptr, base);
+}
+
+unsigned long long wcstoull_l(const wchar_t *nptr, wchar_t **endptr,
+ int base, locale_t) {
+ return wcstoull(nptr, endptr, base);
+}
+
+long double wcstold_l(const wchar_t *nptr, wchar_t **endptr, locale_t) {
+ return wcstold(nptr, endptr);
+}
diff --git a/libc/include/bits/lockf.h b/libc/include/bits/lockf.h
index c24f18b..a8e273e 100644
--- a/libc/include/bits/lockf.h
+++ b/libc/include/bits/lockf.h
@@ -39,11 +39,7 @@
__BEGIN_DECLS
-#if defined(__USE_FILE_OFFSET64)
-int lockf(int, int, off_t) __RENAME(lockf64) __INTRODUCED_IN(24);
-#else
-int lockf(int, int, off_t) __INTRODUCED_IN(24);
-#endif
+int lockf(int, int, off_t) __RENAME_IF_FILE_OFFSET64(lockf64) __INTRODUCED_IN(24);
int lockf64(int, int, off64_t) __INTRODUCED_IN(24);
__END_DECLS
diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h
index c98022c..f27efdf 100644
--- a/libc/include/fcntl.h
+++ b/libc/include/fcntl.h
@@ -71,8 +71,7 @@
int creat(const char*, mode_t);
int creat64(const char*, mode_t) __INTRODUCED_IN(21);
-int openat(int, const char*, int, ...) __overloadable
- __RENAME_CLANG(openat);
+int openat(int, const char*, int, ...) __overloadable __RENAME_CLANG(openat);
int openat64(int, const char*, int, ...) __INTRODUCED_IN(21);
int open(const char*, int, ...) __overloadable __RENAME_CLANG(open);
int open64(const char*, int, ...) __INTRODUCED_IN(21);
@@ -80,17 +79,11 @@
ssize_t tee(int, int, size_t, unsigned int) __INTRODUCED_IN(21);
ssize_t vmsplice(int, const struct iovec*, size_t, unsigned int) __INTRODUCED_IN(21);
-#if defined(__USE_FILE_OFFSET64)
-int fallocate(int, int, off_t, off_t) __RENAME(fallocate64) __INTRODUCED_IN(21);
-int posix_fadvise(int, off_t, off_t, int) __RENAME(posix_fadvise64) __INTRODUCED_IN(21);
-int posix_fallocate(int, off_t, off_t) __RENAME(posix_fallocate64) __INTRODUCED_IN(21);
-#else
-int fallocate(int, int, off_t, off_t) __INTRODUCED_IN(21);
-int posix_fadvise(int, off_t, off_t, int) __INTRODUCED_IN(21);
-int posix_fallocate(int, off_t, off_t) __INTRODUCED_IN(21);
-#endif
+int fallocate(int, int, off_t, off_t) __RENAME_IF_FILE_OFFSET64(fallocate64) __INTRODUCED_IN(21);
int fallocate64(int, int, off64_t, off64_t) __INTRODUCED_IN(21);
+int posix_fadvise(int, off_t, off_t, int) __RENAME_IF_FILE_OFFSET64(posix_fadvise64) __INTRODUCED_IN(21);
int posix_fadvise64(int, off64_t, off64_t, int) __INTRODUCED_IN(21);
+int posix_fallocate(int, off_t, off_t) __RENAME_IF_FILE_OFFSET64(posix_fallocate64) __INTRODUCED_IN(21);
int posix_fallocate64(int, off64_t, off64_t) __INTRODUCED_IN(21);
#if defined(__USE_GNU)
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index d62206d..dd5b345 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -235,10 +235,16 @@
#endif
/* _FILE_OFFSET_BITS 64 support. */
-#if !defined(__LP64__) && defined(_FILE_OFFSET_BITS)
-#if _FILE_OFFSET_BITS == 64
+#if !defined(__LP64__) && defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64
#define __USE_FILE_OFFSET64 1
-#endif
+/*
+ * Note that __RENAME_IF_FILE_OFFSET64 is only valid if the off_t and off64_t
+ * functions were both added at the same API level because if you use this,
+ * you only have one declaration to attach __INTRODUCED_IN to.
+ */
+#define __RENAME_IF_FILE_OFFSET64(func) __RENAME(func)
+#else
+#define __RENAME_IF_FILE_OFFSET64(func)
#endif
#define __BIONIC__ 1
diff --git a/libc/include/sys/uio.h b/libc/include/sys/uio.h
index 2611774..b166277 100644
--- a/libc/include/sys/uio.h
+++ b/libc/include/sys/uio.h
@@ -38,13 +38,8 @@
ssize_t writev(int, const struct iovec*, int);
#if defined(__USE_GNU)
-#if defined(__USE_FILE_OFFSET64)
-ssize_t preadv(int, const struct iovec*, int, off_t) __RENAME(preadv64) __INTRODUCED_IN(24);
-ssize_t pwritev(int, const struct iovec*, int, off_t) __RENAME(pwritev64) __INTRODUCED_IN(24);
-#else
-ssize_t preadv(int, const struct iovec*, int, off_t) __INTRODUCED_IN(24);
-ssize_t pwritev(int, const struct iovec*, int, off_t) __INTRODUCED_IN(24);
-#endif
+ssize_t preadv(int, const struct iovec*, int, off_t) __RENAME_IF_FILE_OFFSET64(preadv64) __INTRODUCED_IN(24);
+ssize_t pwritev(int, const struct iovec*, int, off_t) __RENAME_IF_FILE_OFFSET64(pwritev64) __INTRODUCED_IN(24);
ssize_t preadv64(int, const struct iovec*, int, off64_t) __INTRODUCED_IN(24);
ssize_t pwritev64(int, const struct iovec*, int, off64_t) __INTRODUCED_IN(24);
#endif
diff --git a/libc/private/bionic_mbstate.h b/libc/private/bionic_mbstate.h
index 018b47c..292959a 100644
--- a/libc/private/bionic_mbstate.h
+++ b/libc/private/bionic_mbstate.h
@@ -43,11 +43,31 @@
#define __MB_IS_ERR(rv) (rv == __MB_ERR_ILLEGAL_SEQUENCE || \
rv == __MB_ERR_INCOMPLETE_SEQUENCE)
-size_t mbstate_bytes_so_far(const mbstate_t* ps);
-void mbstate_set_byte(mbstate_t* ps, int i, char byte);
-uint8_t mbstate_get_byte(const mbstate_t* ps, int n);
-size_t reset_and_return_illegal(int _errno, mbstate_t* ps);
-size_t reset_and_return(int _return, mbstate_t* ps);
+static inline __wur size_t mbstate_bytes_so_far(const mbstate_t* ps) {
+ return
+ (ps->__seq[2] != 0) ? 3 :
+ (ps->__seq[1] != 0) ? 2 :
+ (ps->__seq[0] != 0) ? 1 : 0;
+}
+
+static inline void mbstate_set_byte(mbstate_t* ps, int i, char byte) {
+ ps->__seq[i] = static_cast<uint8_t>(byte);
+}
+
+static inline __wur uint8_t mbstate_get_byte(const mbstate_t* ps, int n) {
+ return ps->__seq[n];
+}
+
+static inline __wur size_t mbstate_reset_and_return_illegal(int _errno, mbstate_t* ps) {
+ errno = _errno;
+ *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
+ return __MB_ERR_ILLEGAL_SEQUENCE;
+}
+
+static inline __wur size_t mbstate_reset_and_return(int _return, mbstate_t* ps) {
+ *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
+ return _return;
+}
__END_DECLS
diff --git a/libc/tools/generate-NOTICE.py b/libc/tools/generate-NOTICE.py
index 6573644..d40891c 100755
--- a/libc/tools/generate-NOTICE.py
+++ b/libc/tools/generate-NOTICE.py
@@ -14,17 +14,33 @@
import tarfile
import tempfile
-def IsUninteresting(path):
- path = path.lower()
- if path.endswith(".mk") or path.endswith(".py") or path.endswith(".pyc") or path.endswith(".txt") or path.endswith(".3") or path.endswith(".swp"):
- return True
- if path.endswith("/notice") or path.endswith("/readme") or path.endswith("/caveats"):
- return True
- if path.endswith("/tzdata") or path.endswith("/zoneinfo/generate"):
- return True
- return False
+VERBOSE = False
-def IsAutoGenerated(content):
+def warn(s):
+ sys.stderr.write("warning: %s\n" % s)
+
+def warn_verbose(s):
+ if VERBOSE:
+ warn(s)
+
+def is_interesting(path):
+ path = path.lower()
+ uninteresting_extensions = [
+ ".bp",
+ ".map",
+ ".mk",
+ ".py",
+ ".pyc",
+ ".swp",
+ ".txt",
+ ]
+ if os.path.splitext(path)[1] in uninteresting_extensions:
+ return False
+ if path.endswith("/notice") or path.endswith("/readme"):
+ return False
+ return True
+
+def is_auto_generated(content):
if "Generated by gensyscalls.py" in content or "generated by genserv.py" in content:
return True
if "This header was automatically generated from a Linux kernel header" in content:
@@ -33,7 +49,7 @@
copyrights = set()
-def ExtractCopyrightAt(lines, i):
+def extract_copyright_at(lines, i):
hash = lines[i].startswith("#")
# Do we need to back up to find the start of the copyright header?
@@ -100,13 +116,42 @@
return i
-args = sys.argv[1:]
-if len(args) == 0:
- args = [ "." ]
-for arg in args:
- sys.stderr.write('Searching for source files in "%s"...\n' % arg)
+def do_file(path):
+ with open(path, "r") as the_file:
+ try:
+ content = open(path, "r").read().decode("utf-8")
+ except UnicodeDecodeError:
+ warn("bad UTF-8 in %s" % path)
+ content = open(path, "r").read().decode("iso-8859-1")
+ lines = content.split("\n")
+
+ if len(lines) <= 4:
+ warn_verbose("ignoring short file %s" % path)
+ return
+
+ if is_auto_generated(content):
+ warn_verbose("ignoring auto-generated file %s" % path)
+ return
+
+ if not "Copyright" in content:
+ if "public domain" in content.lower():
+ warn("ignoring public domain file %s" % path)
+ return
+ warn('no copyright notice found in "%s" (%d lines)' % (path, len(lines)))
+ return
+
+ # Manually iterate because extract_copyright_at tells us how many lines to skip.
+ i = 0
+ while i < len(lines):
+ if "Copyright" in lines[i] and not "@(#) Copyright" in lines[i]:
+ i = extract_copyright_at(lines, i)
+ else:
+ i += 1
+
+
+def do_dir(path):
for directory, sub_directories, filenames in os.walk(arg):
if ".git" in sub_directories:
sub_directories.remove(".git")
@@ -114,45 +159,24 @@
for filename in sorted(filenames):
path = os.path.join(directory, filename)
- if IsUninteresting(path):
- #print "ignoring uninteresting file %s" % path
- continue
+ if is_interesting(path):
+ do_file(path)
- try:
- content = open(path, 'r').read().decode('utf-8')
- except:
- sys.stderr.write('warning: bad UTF-8 in %s\n' % path)
- content = open(path, 'r').read().decode('iso-8859-1')
- lines = content.split("\n")
+args = sys.argv[1:]
+if len(args) == 0:
+ args = [ "." ]
- if len(lines) <= 4:
- #print "ignoring short file %s" % path
- continue
-
- if IsAutoGenerated(content):
- #print "ignoring auto-generated file %s" % path
- continue
-
- if not "Copyright" in content:
- if "public domain" in content.lower():
- #print "ignoring public domain file %s" % path
- continue
- sys.stderr.write('warning: no copyright notice found in "%s" (%d lines)\n' % (path, len(lines)))
- continue
-
- i = 0
- while i < len(lines):
- if "Copyright" in lines[i] and not "@(#) Copyright" in lines[i]:
- i = ExtractCopyrightAt(lines, i)
- i += 1
-
- #print path
+for arg in args:
+ if os.path.isdir(arg):
+ do_dir(arg)
+ else:
+ do_file(arg)
for copyright in sorted(copyrights):
- print copyright.encode('utf-8')
+ print copyright.encode("utf-8")
print
- print '-------------------------------------------------------------------'
+ print "-------------------------------------------------------------------"
print
sys.exit(0)
diff --git a/libc/upstream-openbsd/lib/libc/compat-43/killpg.c b/libc/upstream-freebsd/lib/libc/string/wcsstr.c
similarity index 65%
rename from libc/upstream-openbsd/lib/libc/compat-43/killpg.c
rename to libc/upstream-freebsd/lib/libc/string/wcsstr.c
index 75b1ad9..ce598a6 100644
--- a/libc/upstream-openbsd/lib/libc/compat-43/killpg.c
+++ b/libc/upstream-freebsd/lib/libc/string/wcsstr.c
@@ -1,6 +1,9 @@
-/*
- * Copyright (c) 1989 The Regents of the University of California.
- * All rights reserved.
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,19 +30,34 @@
* SUCH DAMAGE.
*/
-#include <sys/types.h>
-#include <signal.h>
-#include <errno.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strstr.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
/*
- * Backwards-compatible killpg().
+ * Find the first occurrence of find in s.
*/
-int
-killpg(pid_t pgid, int sig)
+wchar_t *
+wcsstr(const wchar_t * __restrict s, const wchar_t * __restrict find)
{
- if (pgid == 1) {
- errno = ESRCH;
- return (-1);
+ wchar_t c, sc;
+ size_t len;
+
+ if ((c = *find++) != L'\0') {
+ len = wcslen(find);
+ do {
+ do {
+ if ((sc = *s++) == L'\0')
+ return (NULL);
+ } while (sc != c);
+ } while (wcsncmp(s, find, len) != 0);
+ s--;
}
- return (kill(-pgid, sig));
+ return ((wchar_t *)s);
}
diff --git a/libc/upstream-openbsd/lib/libc/string/wmemcpy.c b/libc/upstream-freebsd/lib/libc/string/wmemcpy.c
similarity index 84%
rename from libc/upstream-openbsd/lib/libc/string/wmemcpy.c
rename to libc/upstream-freebsd/lib/libc/string/wmemcpy.c
index cf02ab9..c10770c 100644
--- a/libc/upstream-openbsd/lib/libc/string/wmemcpy.c
+++ b/libc/upstream-freebsd/lib/libc/string/wmemcpy.c
@@ -1,6 +1,3 @@
-/* $OpenBSD: wmemcpy.c,v 1.4 2015/09/12 16:23:14 guenther Exp $ */
-/* $NetBSD: wmemcpy.c,v 1.2 2001/01/03 14:29:37 lukem Exp $ */
-
/*-
* Copyright (c)1999 Citrus Project,
* All rights reserved.
@@ -29,13 +26,19 @@
* citrus Id: wmemcpy.c,v 1.2 2000/12/20 14:08:31 itojun Exp
*/
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: wmemcpy.c,v 1.1 2000/12/23 23:14:37 itojun Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
#include <string.h>
#include <wchar.h>
wchar_t *
-wmemcpy(wchar_t *d, const wchar_t *s, size_t n)
+wmemcpy(wchar_t * __restrict d, const wchar_t * __restrict s, size_t n)
{
-
return (wchar_t *)memcpy(d, s, n * sizeof(wchar_t));
}
-DEF_STRONG(wmemcpy);
diff --git a/libc/upstream-openbsd/lib/libc/string/wcsstr.c b/libc/upstream-openbsd/lib/libc/string/wcsstr.c
deleted file mode 100644
index 6a7b0da..0000000
--- a/libc/upstream-openbsd/lib/libc/string/wcsstr.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/* $OpenBSD: wcsstr.c,v 1.5 2015/10/01 02:32:07 guenther Exp $ */
-/* $NetBSD: wcsstr.c,v 1.3 2003/03/05 20:18:17 tshiozak Exp $ */
-
-/*-
- * Copyright (c)1999 Citrus 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:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. 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 AUTHOR 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 AUTHOR 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.
- *
- * citrus Id: wcsstr.c,v 1.2 2000/12/21 05:07:25 itojun Exp
- */
-
-#include <wchar.h>
-
-wchar_t *
-#ifdef WCSWCS
-wcswcs(const wchar_t *big, const wchar_t *little)
-#else
-wcsstr(const wchar_t *big, const wchar_t *little)
-#endif
-{
- const wchar_t *p;
- const wchar_t *q;
- const wchar_t *r;
-
- if (!*little) {
- return (wchar_t *)big;
- }
- if (wcslen(big) < wcslen(little))
- return NULL;
-
- p = big;
- q = little;
- while (*p) {
- q = little;
- r = p;
- while (*q) {
- if (*r != *q)
- break;
- q++;
- r++;
- }
- if (!*q) {
- return (wchar_t *)p;
- }
- p++;
- }
- return NULL;
-}
-#ifndef WCSWCS
-DEF_STRONG(wcsstr);
-#endif
diff --git a/libdl/libdl.arm.map b/libdl/libdl.arm.map
index 668f008..292bd97 100644
--- a/libdl/libdl.arm.map
+++ b/libdl/libdl.arm.map
@@ -34,11 +34,15 @@
dlvsym; # introduced=24
} LIBC;
+LIBC_OMR1 { # future
+ global:
+ __cfi_slowpath; # future
+ __cfi_slowpath_diag; # future
+} LIBC_N;
+
LIBC_PLATFORM {
global:
__cfi_init;
- __cfi_slowpath;
- __cfi_slowpath_diag;
android_dlwarning;
android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
@@ -48,4 +52,4 @@
android_create_namespace;
android_link_namespaces;
android_get_exported_namespace;
-} LIBC_N;
+} LIBC_OMR1;
diff --git a/libdl/libdl.arm64.map b/libdl/libdl.arm64.map
index 8270fe9..2fe2c7b 100644
--- a/libdl/libdl.arm64.map
+++ b/libdl/libdl.arm64.map
@@ -33,11 +33,15 @@
dlvsym; # introduced=24
} LIBC;
+LIBC_OMR1 { # future
+ global:
+ __cfi_slowpath; # future
+ __cfi_slowpath_diag; # future
+} LIBC_N;
+
LIBC_PLATFORM {
global:
__cfi_init;
- __cfi_slowpath;
- __cfi_slowpath_diag;
android_dlwarning;
android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
@@ -47,4 +51,4 @@
android_create_namespace;
android_link_namespaces;
android_get_exported_namespace;
-} LIBC_N;
+} LIBC_OMR1;
diff --git a/libdl/libdl.map.txt b/libdl/libdl.map.txt
index a4c6483..408d4dc 100644
--- a/libdl/libdl.map.txt
+++ b/libdl/libdl.map.txt
@@ -33,11 +33,15 @@
dlvsym; # introduced=24
} LIBC;
+LIBC_OMR1 { # future
+ global:
+ __cfi_slowpath; # future
+ __cfi_slowpath_diag; # future
+} LIBC_N;
+
LIBC_PLATFORM {
global:
__cfi_init;
- __cfi_slowpath;
- __cfi_slowpath_diag;
android_dlwarning;
android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
@@ -47,4 +51,4 @@
android_create_namespace;
android_link_namespaces;
android_get_exported_namespace;
-} LIBC_N;
+} LIBC_OMR1;
diff --git a/libdl/libdl.mips.map b/libdl/libdl.mips.map
index 8270fe9..2fe2c7b 100644
--- a/libdl/libdl.mips.map
+++ b/libdl/libdl.mips.map
@@ -33,11 +33,15 @@
dlvsym; # introduced=24
} LIBC;
+LIBC_OMR1 { # future
+ global:
+ __cfi_slowpath; # future
+ __cfi_slowpath_diag; # future
+} LIBC_N;
+
LIBC_PLATFORM {
global:
__cfi_init;
- __cfi_slowpath;
- __cfi_slowpath_diag;
android_dlwarning;
android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
@@ -47,4 +51,4 @@
android_create_namespace;
android_link_namespaces;
android_get_exported_namespace;
-} LIBC_N;
+} LIBC_OMR1;
diff --git a/libdl/libdl.mips64.map b/libdl/libdl.mips64.map
index 8270fe9..2fe2c7b 100644
--- a/libdl/libdl.mips64.map
+++ b/libdl/libdl.mips64.map
@@ -33,11 +33,15 @@
dlvsym; # introduced=24
} LIBC;
+LIBC_OMR1 { # future
+ global:
+ __cfi_slowpath; # future
+ __cfi_slowpath_diag; # future
+} LIBC_N;
+
LIBC_PLATFORM {
global:
__cfi_init;
- __cfi_slowpath;
- __cfi_slowpath_diag;
android_dlwarning;
android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
@@ -47,4 +51,4 @@
android_create_namespace;
android_link_namespaces;
android_get_exported_namespace;
-} LIBC_N;
+} LIBC_OMR1;
diff --git a/libdl/libdl.x86.map b/libdl/libdl.x86.map
index 8270fe9..2fe2c7b 100644
--- a/libdl/libdl.x86.map
+++ b/libdl/libdl.x86.map
@@ -33,11 +33,15 @@
dlvsym; # introduced=24
} LIBC;
+LIBC_OMR1 { # future
+ global:
+ __cfi_slowpath; # future
+ __cfi_slowpath_diag; # future
+} LIBC_N;
+
LIBC_PLATFORM {
global:
__cfi_init;
- __cfi_slowpath;
- __cfi_slowpath_diag;
android_dlwarning;
android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
@@ -47,4 +51,4 @@
android_create_namespace;
android_link_namespaces;
android_get_exported_namespace;
-} LIBC_N;
+} LIBC_OMR1;
diff --git a/libdl/libdl.x86_64.map b/libdl/libdl.x86_64.map
index 8270fe9..2fe2c7b 100644
--- a/libdl/libdl.x86_64.map
+++ b/libdl/libdl.x86_64.map
@@ -33,11 +33,15 @@
dlvsym; # introduced=24
} LIBC;
+LIBC_OMR1 { # future
+ global:
+ __cfi_slowpath; # future
+ __cfi_slowpath_diag; # future
+} LIBC_N;
+
LIBC_PLATFORM {
global:
__cfi_init;
- __cfi_slowpath;
- __cfi_slowpath_diag;
android_dlwarning;
android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
@@ -47,4 +51,4 @@
android_create_namespace;
android_link_namespaces;
android_get_exported_namespace;
-} LIBC_N;
+} LIBC_OMR1;
diff --git a/libm/Android.bp b/libm/Android.bp
index 8947f4d..75e8957 100644
--- a/libm/Android.bp
+++ b/libm/Android.bp
@@ -63,7 +63,6 @@
"upstream-freebsd/lib/msun/src/e_sinhf.c",
"upstream-freebsd/lib/msun/src/e_sqrt.c",
"upstream-freebsd/lib/msun/src/e_sqrtf.c",
- "upstream-freebsd/lib/msun/src/imprecise.c",
"upstream-freebsd/lib/msun/src/k_cos.c",
"upstream-freebsd/lib/msun/src/k_cosf.c",
"upstream-freebsd/lib/msun/src/k_exp.c",
@@ -209,6 +208,7 @@
// Functionality not in the BSDs.
"significandl.c",
"sincos.c",
+ "fake_long_double.c",
// Modified versions of BSD code.
"signbit.c",
@@ -218,10 +218,6 @@
],
multilib: {
- lib32: {
- srcs: ["fake_long_double.c"],
- },
-
lib64: {
srcs: [
"upstream-freebsd/lib/msun/src/e_acosl.c",
diff --git a/libm/fake_long_double.c b/libm/fake_long_double.c
index 20148a3..fd983ed 100644
--- a/libm/fake_long_double.c
+++ b/libm/fake_long_double.c
@@ -17,12 +17,11 @@
#include <float.h>
#include <math.h>
-#ifndef __LP64__
-/*
- * The BSD "long double" functions are broken when sizeof(long double) == sizeof(double).
- * Android works around those cases by replacing the broken functions with our own trivial stubs
- * that call the regular "double" function.
- */
+#if !defined(__LP64__)
+
+// The BSD "long double" functions are broken when sizeof(long double) == sizeof(double).
+// Android works around those cases by replacing the broken functions with our own trivial stubs
+// that call the regular "double" function.
long double copysignl(long double a1, long double a2) { return copysign(a1, a2); }
long double fmaxl(long double a1, long double a2) { return fmax(a1, a2); }
@@ -40,3 +39,7 @@
long double roundl(long double a1) { return round(a1); }
#endif // __LP64__
+
+// FreeBSD doesn't have ld128 implementations of powl or tgammal, so both LP32 and LP64 need these.
+long double powl(long double x, long double y) { return pow(x, y); }
+long double tgammal(long double x) { return tgamma(x); }
diff --git a/libm/freebsd-compat.h b/libm/freebsd-compat.h
index a4dd6c2..ee41e45 100644
--- a/libm/freebsd-compat.h
+++ b/libm/freebsd-compat.h
@@ -28,7 +28,15 @@
#define __warn_references(sym,msg) /* ignored */
-/* digittoint is in BSD's <ctype.h>. */
+// digittoint is in BSD's <ctype.h>, but not ours, so we have a secret
+// implementation in libm. We reuse parts of libm in the NDK's
+// libandroid_support, where it's a static library, so we want all our
+// "hidden" functions start with a double underscore --- being HIDDEN
+// in the ELF sense is not sufficient.
+#define digittoint __libm_digittoint
int digittoint(char ch);
+// Similarly rename _scan_nan.
+#define _scan_nan __libm_scan_nan
+
#endif
diff --git a/libm/upstream-freebsd/lib/msun/src/imprecise.c b/libm/upstream-freebsd/lib/msun/src/imprecise.c
deleted file mode 100644
index 08cd239..0000000
--- a/libm/upstream-freebsd/lib/msun/src/imprecise.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*-
- * Copyright (c) 2013 David Chisnall
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. 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 AUTHOR 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 AUTHOR 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.
- *
- * $FreeBSD$
- */
-
-#include <float.h>
-#include <math.h>
-
-/*
- * If long double is not the same size as double, then these will lose
- * precision and we should emit a warning whenever something links against
- * them.
- */
-#if (LDBL_MANT_DIG > 53)
-#define WARN_IMPRECISE(x) \
- __warn_references(x, # x " has lower than advertised precision");
-#else
-#define WARN_IMPRECISE(x)
-#endif
-/*
- * Declare the functions as weak variants so that other libraries providing
- * real versions can override them.
- */
-#define DECLARE_WEAK(x)\
- __weak_reference(imprecise_## x, x);\
- WARN_IMPRECISE(x)
-
-long double
-imprecise_powl(long double x, long double y)
-{
-
- return pow(x, y);
-}
-DECLARE_WEAK(powl);
-
-#define DECLARE_IMPRECISE(f) \
- long double imprecise_ ## f ## l(long double v) { return f(v); }\
- DECLARE_WEAK(f ## l)
-
-DECLARE_IMPRECISE(tgamma);
diff --git a/tests/signal_test.cpp b/tests/signal_test.cpp
index 36ac690..207c156 100644
--- a/tests/signal_test.cpp
+++ b/tests/signal_test.cpp
@@ -527,3 +527,11 @@
ASSERT_EQ(0, sigprocmask(SIG_BLOCK, nullptr, &set));
EXPECT_TRUE(sigismember(&set, SIGALRM));
}
+
+TEST(signal, killpg_EINVAL) {
+ // POSIX leaves pgrp <= 1 undefined, but glibc fails with EINVAL for < 0
+ // and passes 0 through to kill(2).
+ errno = 0;
+ ASSERT_EQ(-1, killpg(-1, SIGKILL));
+ ASSERT_EQ(EINVAL, errno);
+}
diff --git a/tests/uchar_test.cpp b/tests/uchar_test.cpp
index c887f8a..8b29667 100644
--- a/tests/uchar_test.cpp
+++ b/tests/uchar_test.cpp
@@ -280,7 +280,10 @@
char bytes[MB_LEN_MAX];
+ memset(bytes, 1, sizeof(bytes));
EXPECT_EQ(1U, c32rtomb(bytes, L'\0', NULL));
+ EXPECT_EQ('\0', bytes[0]);
+ EXPECT_EQ('\x01', bytes[1]);
memset(bytes, 0, sizeof(bytes));
EXPECT_EQ(1U, c32rtomb(bytes, L'h', NULL));
@@ -408,4 +411,3 @@
GTEST_LOG_(INFO) << "uchar.h is unavailable.\n";
#endif
}
-
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 109b92c..a81f112 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -759,6 +759,7 @@
EXPECT_GT(_POSIX_TZNAME_MAX, 0);
EXPECT_NE(-1, _POSIX_VDISABLE);
+ EXPECT_EQ(_POSIX_VERSION, _POSIX2_VERSION);
EXPECT_GT(_POSIX2_BC_BASE_MAX, 0);
EXPECT_GT(_POSIX2_BC_DIM_MAX, 0);
EXPECT_GT(_POSIX2_BC_SCALE_MAX, 0);
@@ -784,7 +785,6 @@
EXPECT_EQ(-1, _POSIX_SPAWN);
EXPECT_EQ(-1, _POSIX_THREAD_ROBUST_PRIO_INHERIT);
- EXPECT_EQ(-1, _POSIX2_VERSION);
EXPECT_EQ(-1, _POSIX2_CHAR_TERM);
EXPECT_EQ(-1, _POSIX2_C_DEV);
EXPECT_EQ(-1, _POSIX2_LOCALEDEF);
diff --git a/tests/wchar_test.cpp b/tests/wchar_test.cpp
index 830eb70..097647f 100644
--- a/tests/wchar_test.cpp
+++ b/tests/wchar_test.cpp
@@ -445,6 +445,18 @@
ASSERT_EQ(L'e', dst[1]);
ASSERT_EQ(L'l', dst[2]);
ASSERT_EQ(&s[3], src);
+
+ memset(dst, 0, sizeof(dst));
+ const char* incomplete = "\xc2"; // Incomplete UTF-8 sequence.
+ src = incomplete;
+ errno = 0;
+ ASSERT_EQ(static_cast<size_t>(-1), mbsnrtowcs(dst, &src, SIZE_MAX, 3, nullptr));
+ ASSERT_EQ(EILSEQ, errno);
+
+ src = incomplete;
+ errno = 0;
+ ASSERT_EQ(static_cast<size_t>(-1), mbsnrtowcs(nullptr, &src, SIZE_MAX, 3, nullptr));
+ ASSERT_EQ(EILSEQ, errno);
}
TEST(wchar, wcsftime) {