Merge "Nullability check for spawn module"
diff --git a/benchmarks/malloc_benchmark.cpp b/benchmarks/malloc_benchmark.cpp
index 18ba523..e733cd0 100644
--- a/benchmarks/malloc_benchmark.cpp
+++ b/benchmarks/malloc_benchmark.cpp
@@ -36,11 +36,11 @@
#if defined(__BIONIC__)
-static void BM_mallopt_purge(benchmark::State& state) {
+static void RunMalloptPurge(benchmark::State& state, int purge_value) {
static size_t sizes[] = {8, 16, 32, 64, 128, 1024, 4096, 16384, 65536, 131072, 1048576};
static int pagesize = getpagesize();
mallopt(M_DECAY_TIME, 1);
- mallopt(M_PURGE, 0);
+ mallopt(M_PURGE_ALL, 0);
for (auto _ : state) {
state.PauseTiming();
std::vector<void*> ptrs;
@@ -63,10 +63,19 @@
ptrs.clear();
state.ResumeTiming();
- mallopt(M_PURGE, 0);
+ mallopt(purge_value, 0);
}
mallopt(M_DECAY_TIME, 0);
}
+
+static void BM_mallopt_purge(benchmark::State& state) {
+ RunMalloptPurge(state, M_PURGE);
+}
BIONIC_BENCHMARK(BM_mallopt_purge);
+static void BM_mallopt_purge_all(benchmark::State& state) {
+ RunMalloptPurge(state, M_PURGE_ALL);
+}
+BIONIC_BENCHMARK(BM_mallopt_purge_all);
+
#endif
diff --git a/benchmarks/malloc_map_benchmark.cpp b/benchmarks/malloc_map_benchmark.cpp
index ba4d62c..5757325 100644
--- a/benchmarks/malloc_map_benchmark.cpp
+++ b/benchmarks/malloc_map_benchmark.cpp
@@ -69,7 +69,7 @@
for (auto _ : state) {
#if defined(__BIONIC__)
state.PauseTiming();
- mallopt(M_PURGE, 0);
+ mallopt(M_PURGE_ALL, 0);
uint64_t rss_bytes_before = 0;
Gather(&rss_bytes_before);
state.ResumeTiming();
@@ -80,7 +80,7 @@
}
#if defined(__BIONIC__)
state.PauseTiming();
- mallopt(M_PURGE, 0);
+ mallopt(M_PURGE_ALL, 0);
Gather(&rss_bytes);
// Try and record only the memory used in the map.
rss_bytes -= rss_bytes_before;
diff --git a/benchmarks/malloc_rss_benchmark.cpp b/benchmarks/malloc_rss_benchmark.cpp
index 58f61d9..4b34e72 100644
--- a/benchmarks/malloc_rss_benchmark.cpp
+++ b/benchmarks/malloc_rss_benchmark.cpp
@@ -112,7 +112,7 @@
// Do an explicit purge to ensure we will be more likely to get the actual
// in-use memory.
- mallopt(M_PURGE, 0);
+ mallopt(M_PURGE_ALL, 0);
android::meminfo::ProcMemInfo proc_mem(getpid());
const std::vector<android::meminfo::Vma>& maps = proc_mem.MapsWithoutUsageStats();
diff --git a/libc/Android.bp b/libc/Android.bp
index c101f45..93f9ce9 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -827,6 +827,7 @@
riscv64: {
srcs: [
"arch-riscv64/string/__memset_chk.S",
+ "arch-riscv64/string/__memcpy_chk.S",
],
},
},
@@ -2146,6 +2147,10 @@
name: "crt_defaults",
defaults: ["crt_and_memtag_defaults"],
system_shared_libs: [],
+
+ conlyflags: [
+ "-mllvm -disable-check-noreturn-call",
+ ]
}
cc_defaults {
@@ -2307,6 +2312,11 @@
"arch-arm64/string/__memcpy_chk.S",
],
},
+ riscv64: {
+ srcs: [
+ "arch-riscv64/string/__memcpy_chk.S",
+ ],
+ },
},
whole_static_libs: [
"libarm-optimized-routines-mem",
diff --git a/libc/arch-arm64/bionic/setjmp.S b/libc/arch-arm64/bionic/setjmp.S
index 8e00b56..d787a56 100644
--- a/libc/arch-arm64/bionic/setjmp.S
+++ b/libc/arch-arm64/bionic/setjmp.S
@@ -46,8 +46,6 @@
// 0 sigflag/cookie setjmp cookie in top 31 bits, signal mask flag in low bit
// 1 sigmask signal mask (not used with _setjmp / _longjmp)
// 2 core_base base of core registers (x18-x30, sp)
-// (We only store the low bits of x18 to avoid leaking the
-// shadow call stack address into memory.)
// 16 float_base base of float registers (d8-d15)
// 24 checksum checksum of core registers
// 25 reserved reserved entries (room to grow)
@@ -68,8 +66,6 @@
#define _JB_D8_D9 (_JB_D10_D11 + 2)
#define _JB_CHECKSUM (_JB_D8_D9 + 2)
-#define SCS_MASK (SCS_SIZE - 1)
-
.macro m_mangle_registers reg, sp_reg
eor x3, x3, \reg
eor x19, x19, \reg
@@ -155,6 +151,9 @@
bic x1, x1, #1
// Mask off the high bits of the shadow call stack pointer.
+ // We only store the low bits of x18 to avoid leaking the
+ // shadow call stack address into memory.
+ // See the SCS commentary in pthread_internal.h for more detail.
and x3, x18, #SCS_MASK
// Save core registers.
diff --git a/libc/arch-riscv64/bionic/__bionic_clone.S b/libc/arch-riscv64/bionic/__bionic_clone.S
index d535095..2827857 100644
--- a/libc/arch-riscv64/bionic/__bionic_clone.S
+++ b/libc/arch-riscv64/bionic/__bionic_clone.S
@@ -51,7 +51,7 @@
.L_bc_failure:
# Set errno if something went wrong.
neg a0, a0
- j __set_errno_internal
+ tail __set_errno_internal
.L_bc_child:
# We're in the child now. Set the end of the frame record chain.
@@ -62,5 +62,5 @@
ld a0, 0(sp)
ld a1, 8(sp)
addi sp, sp, 16
- j __start_thread
+ tail __start_thread
END(__bionic_clone)
diff --git a/libc/arch-riscv64/bionic/setjmp.S b/libc/arch-riscv64/bionic/setjmp.S
index eea2978..ba3cacf 100644
--- a/libc/arch-riscv64/bionic/setjmp.S
+++ b/libc/arch-riscv64/bionic/setjmp.S
@@ -79,7 +79,7 @@
.macro m_mangle_registers reg, sp_reg
xor s0, s0, \reg
xor s1, s1, \reg
- xor s2, s2, \reg
+ xor a4, a4, \reg // a4 is the masked s2 (x18) for SCS.
xor s3, s3, \reg
xor s4, s4, \reg
xor s5, s5, \reg
@@ -151,13 +151,20 @@
ld a1, _JB_SIGFLAG(a0)
andi a1, a1, -2
+ // Mask off the high bits of the shadow call stack pointer.
+ // We only store the low bits of x18 to avoid leaking the
+ // shadow call stack address into memory.
+ // See the SCS commentary in pthread_internal.h for more detail.
+ li a4, SCS_MASK
+ and a4, a4, x18
+
// Save core registers.
mv a2, sp
m_mangle_registers a1, sp_reg=a2
sd ra, _JB_RA(a0)
sd s0, _JB_S0(a0)
sd s1, _JB_S1(a0)
- sd s2, _JB_S2(a0)
+ sd a4, _JB_S2(a0) // a4 is the masked s2 (x18) for SCS.
sd s3, _JB_S3(a0)
sd s4, _JB_S4(a0)
sd s5, _JB_S5(a0)
@@ -231,7 +238,7 @@
ld ra, _JB_RA(a0)
ld s0, _JB_S0(a0)
ld s1, _JB_S1(a0)
- ld s2, _JB_S2(a0)
+ ld a4, _JB_S2(a0) // Don't clobber s2 (x18) used for SCS yet.
ld s3, _JB_S3(a0)
ld s4, _JB_S4(a0)
ld s5, _JB_S5(a0)
@@ -245,6 +252,11 @@
m_unmangle_registers a2, sp_reg=a3
mv sp, a3
+ // Restore the low bits of the shadow call stack pointer.
+ li a5, ~SCS_MASK
+ and x18, x18, a5
+ or x18, a4, x18
+
addi sp, sp, -24
sd ra, 0(sp)
sd a0, 8(sp)
diff --git a/libc/arch-riscv64/bionic/syscall.S b/libc/arch-riscv64/bionic/syscall.S
index 7b9d3ca..1a6e60a 100644
--- a/libc/arch-riscv64/bionic/syscall.S
+++ b/libc/arch-riscv64/bionic/syscall.S
@@ -49,5 +49,5 @@
ret
1:
neg a0, a0
- j __set_errno_internal
+ tail __set_errno_internal
END(syscall)
diff --git a/libc/arch-riscv64/bionic/vfork.S b/libc/arch-riscv64/bionic/vfork.S
index 0eff9e9..29ab405 100644
--- a/libc/arch-riscv64/bionic/vfork.S
+++ b/libc/arch-riscv64/bionic/vfork.S
@@ -62,5 +62,5 @@
.L_failure:
neg a0, a0
- j __set_errno_internal
+ tail __set_errno_internal
END(vfork)
diff --git a/libc/arch-riscv64/string/__memcpy_chk.S b/libc/arch-riscv64/string/__memcpy_chk.S
new file mode 100644
index 0000000..4a2d13d
--- /dev/null
+++ b/libc/arch-riscv64/string/__memcpy_chk.S
@@ -0,0 +1,9 @@
+#include <private/bionic_asm.h>
+
+ENTRY(__memcpy_chk)
+ bleu a2, a3, 1f
+ call __memcpy_chk_fail
+
+1:
+ tail memcpy
+END(__memcpy_chk)
diff --git a/libc/async_safe/async_safe_log.cpp b/libc/async_safe/async_safe_log.cpp
index 2380e68..420560f 100644
--- a/libc/async_safe/async_safe_log.cpp
+++ b/libc/async_safe/async_safe_log.cpp
@@ -254,7 +254,7 @@
bool alternate = false;
size_t bytelen = sizeof(int);
int slen;
- char buffer[32]; /* temporary buffer used to format numbers */
+ char buffer[64]; // temporary buffer used to format numbers/format errno string
char c;
@@ -359,8 +359,7 @@
buffer[1] = 'x';
format_integer(buffer + 2, sizeof(buffer) - 2, value, 'x');
} else if (c == 'm') {
- char buf[256];
- str = strerror_r(errno, buf, sizeof(buf));
+ strerror_r(errno, buffer, sizeof(buffer));
} else if (c == 'd' || c == 'i' || c == 'o' || c == 'u' || c == 'x' || c == 'X') {
/* integers - first read value from stack */
uint64_t value;
diff --git a/libc/bionic/fortify.cpp b/libc/bionic/fortify.cpp
index 73cf973..7dee5e3 100644
--- a/libc/bionic/fortify.cpp
+++ b/libc/bionic/fortify.cpp
@@ -489,9 +489,9 @@
return strcpy(dst, src);
}
-#if !defined(__arm__) && !defined(__aarch64__)
+#if !defined(__arm__) && !defined(__aarch64__) && !defined(__riscv)
// Runtime implementation of __memcpy_chk (used directly by compiler, not in headers).
-// arm32 and arm64 have assembler implementations, and don't need this C fallback.
+// arm32,arm64,riscv have assembler implementations, and don't need this C fallback.
extern "C" void* __memcpy_chk(void* dst, const void* src, size_t count, size_t dst_len) {
__check_count("memcpy", "count", count);
__check_buffer_access("memcpy", "write into", count, dst_len);
diff --git a/libc/bionic/gwp_asan_wrappers.cpp b/libc/bionic/gwp_asan_wrappers.cpp
index 251633d..fab29ef 100644
--- a/libc/bionic/gwp_asan_wrappers.cpp
+++ b/libc/bionic/gwp_asan_wrappers.cpp
@@ -307,8 +307,10 @@
sysprop_names[3] = persist_default_sysprop;
}
+ // TODO(mitchp): Log overrides using this.
+ const char* source;
return get_config_from_env_or_sysprops(env_var, sysprop_names, arraysize(sysprop_names),
- value_out, PROP_VALUE_MAX);
+ value_out, PROP_VALUE_MAX, &source);
}
bool GetGwpAsanIntegerOption(unsigned long long* result,
diff --git a/libc/bionic/jemalloc_wrapper.cpp b/libc/bionic/jemalloc_wrapper.cpp
index ef488ee..ce3f314 100644
--- a/libc/bionic/jemalloc_wrapper.cpp
+++ b/libc/bionic/jemalloc_wrapper.cpp
@@ -102,7 +102,7 @@
}
}
return 1;
- } else if (param == M_PURGE) {
+ } else if (param == M_PURGE || param == M_PURGE_ALL) {
// Only clear the current thread cache since there is no easy way to
// clear the caches of other threads.
// This must be done first so that cleared allocations get purged
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index d64d402..0935cd6 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -217,16 +217,13 @@
// Returns true if there's an environment setting (either sysprop or env var)
// that should overwrite the ELF note, and places the equivalent heap tagging
// level into *level.
-static bool get_environment_memtag_setting(HeapTaggingLevel* level) {
+static bool get_environment_memtag_setting(const char* basename, HeapTaggingLevel* level) {
static const char kMemtagPrognameSyspropPrefix[] = "arm64.memtag.process.";
static const char kMemtagGlobalSysprop[] = "persist.arm64.memtag.default";
static const char kMemtagOverrideSyspropPrefix[] =
"persist.device_config.memory_safety_native.mode_override.process.";
- const char* progname = __libc_shared_globals()->init_progname;
- if (progname == nullptr) return false;
-
- const char* basename = __gnu_basename(progname);
+ if (basename == nullptr) return false;
char options_str[PROP_VALUE_MAX];
char sysprop_name[512];
@@ -237,8 +234,9 @@
kMemtagOverrideSyspropPrefix, basename);
const char* sys_prop_names[] = {sysprop_name, remote_sysprop_name, kMemtagGlobalSysprop};
+ const char* source = nullptr;
if (!get_config_from_env_or_sysprops("MEMTAG_OPTIONS", sys_prop_names, arraysize(sys_prop_names),
- options_str, sizeof(options_str))) {
+ options_str, sizeof(options_str), &source)) {
return false;
}
@@ -249,27 +247,35 @@
} else if (strcmp("off", options_str) == 0) {
*level = M_HEAP_TAGGING_LEVEL_TBI;
} else {
- async_safe_format_log(
- ANDROID_LOG_ERROR, "libc",
- "unrecognized memtag level: \"%s\" (options are \"sync\", \"async\", or \"off\").",
- options_str);
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+ "%s: unrecognized memtag level in %s: \"%s\" (options are \"sync\", "
+ "\"async\", or \"off\").",
+ basename, source, options_str);
return false;
}
-
+ async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "%s: chose memtag level \"%s\" from %s.",
+ basename, options_str, source);
return true;
}
+static void log_elf_memtag_level(const char* basename, const char* level) {
+ async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "%s: chose memtag level \"%s\" from ELF note",
+ basename ?: "<unknown>", level);
+}
+
// Returns the initial heap tagging level. Note: This function will never return
// M_HEAP_TAGGING_LEVEL_NONE, if MTE isn't enabled for this process we enable
// M_HEAP_TAGGING_LEVEL_TBI.
static HeapTaggingLevel __get_heap_tagging_level(const void* phdr_start, size_t phdr_ct,
uintptr_t load_bias, bool* stack) {
+ const char* progname = __libc_shared_globals()->init_progname;
+ const char* basename = progname ? __gnu_basename(progname) : nullptr;
unsigned note_val =
__get_memtag_note(reinterpret_cast<const ElfW(Phdr)*>(phdr_start), phdr_ct, load_bias);
*stack = note_val & NT_MEMTAG_STACK;
HeapTaggingLevel level;
- if (get_environment_memtag_setting(&level)) return level;
+ if (get_environment_memtag_setting(basename, &level)) return level;
// Note, previously (in Android 12), any value outside of bits [0..3] resulted
// in a check-fail. In order to be permissive of further extensions, we
@@ -284,14 +290,17 @@
// by anyone, but we note it (heh) here for posterity, in case the zero
// level becomes meaningful, and binaries with this note can be executed
// on Android 12 devices.
+ log_elf_memtag_level(basename, "off");
return M_HEAP_TAGGING_LEVEL_TBI;
case NT_MEMTAG_LEVEL_ASYNC:
+ log_elf_memtag_level(basename, "async");
return M_HEAP_TAGGING_LEVEL_ASYNC;
case NT_MEMTAG_LEVEL_SYNC:
default:
// We allow future extensions to specify mode 3 (currently unused), with
// the idea that it might be used for ASYMM mode or something else. On
// this version of Android, it falls back to SYNC mode.
+ log_elf_memtag_level(basename, "sync");
return M_HEAP_TAGGING_LEVEL_SYNC;
}
}
diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp
index 417ce76..15d6d6d 100644
--- a/libc/bionic/pthread_create.cpp
+++ b/libc/bionic/pthread_create.cpp
@@ -116,14 +116,14 @@
}
static void __init_shadow_call_stack(pthread_internal_t* thread __unused) {
-#ifdef __aarch64__
+#if defined(__aarch64__) || defined(__riscv)
// Allocate the stack and the guard region.
char* scs_guard_region = reinterpret_cast<char*>(
mmap(nullptr, SCS_GUARD_REGION_SIZE, 0, MAP_PRIVATE | MAP_ANON, -1, 0));
thread->shadow_call_stack_guard_region = scs_guard_region;
// The address is aligned to SCS_SIZE so that we only need to store the lower log2(SCS_SIZE) bits
- // in jmp_buf.
+ // in jmp_buf. See the SCS commentary in pthread_internal.h for more detail.
char* scs_aligned_guard_region =
reinterpret_cast<char*>(align_up(reinterpret_cast<uintptr_t>(scs_guard_region), SCS_SIZE));
@@ -133,11 +133,15 @@
size_t scs_offset =
(getpid() == 1) ? 0 : (arc4random_uniform(SCS_GUARD_REGION_SIZE / SCS_SIZE - 1) * SCS_SIZE);
- // Make the stack readable and writable and store its address in register x18. This is
- // deliberately the only place where the address is stored.
- char *scs = scs_aligned_guard_region + scs_offset;
+ // Make the stack readable and writable and store its address in x18.
+ // This is deliberately the only place where the address is stored.
+ char* scs = scs_aligned_guard_region + scs_offset;
mprotect(scs, SCS_SIZE, PROT_READ | PROT_WRITE);
+#if defined(__aarch64__)
__asm__ __volatile__("mov x18, %0" ::"r"(scs));
+#elif defined(__riscv)
+ __asm__ __volatile__("mv x18, %0" ::"r"(scs));
+#endif
#endif
}
diff --git a/libc/bionic/pthread_exit.cpp b/libc/bionic/pthread_exit.cpp
index bde95ec..f584b27 100644
--- a/libc/bionic/pthread_exit.cpp
+++ b/libc/bionic/pthread_exit.cpp
@@ -117,7 +117,7 @@
__rt_sigprocmask(SIG_BLOCK, &set, nullptr, sizeof(sigset64_t));
}
-#ifdef __aarch64__
+#if defined(__aarch64__) || defined(__riscv)
// Free the shadow call stack and guard pages.
munmap(thread->shadow_call_stack_guard_region, SCS_GUARD_REGION_SIZE);
#endif
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index 7222b62..083c2ed 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -105,9 +105,13 @@
void* alternate_signal_stack;
- // The start address of the shadow call stack's guard region (arm64 only).
+ // The start address of the shadow call stack's guard region (arm64/riscv64).
+ // This region is SCS_GUARD_REGION_SIZE bytes large, but only SCS_SIZE bytes
+ // are actually used.
+ //
// This address is only used to deallocate the shadow call stack on thread
// exit; the address of the stack itself is stored only in the x18 register.
+ //
// Because the protection offered by SCS relies on the secrecy of the stack
// address, storing the address here weakens the protection, but only
// slightly, because it is relatively easy for an attacker to discover the
@@ -115,13 +119,22 @@
// to other allocations), but not the stack itself, which is <0.1% of the size
// of the guard region.
//
+ // longjmp()/setjmp() don't store all the bits of x18, only the bottom bits
+ // covered by SCS_MASK. Since longjmp()/setjmp() between different threads is
+ // undefined behavior (and unsupported on Android), we can retrieve the high
+ // bits of x18 from the current value in x18 --- all the jmp_buf needs to store
+ // is where exactly the shadow stack pointer is in the thread's shadow stack:
+ // the bottom bits of x18.
+ //
// There are at least two other options for discovering the start address of
// the guard region on thread exit, but they are not as simple as storing in
// TLS.
+ //
// 1) Derive it from the value of the x18 register. This is only possible in
// processes that do not contain legacy code that might clobber x18,
// therefore each process must declare early during process startup whether
// it might load legacy code.
+ // TODO: riscv64 has no legacy code, so we can actually go this route there!
// 2) Mark the guard region as such using prctl(PR_SET_VMA_ANON_NAME) and
// discover its address by reading /proc/self/maps. One issue with this is
// that reading /proc/self/maps can race with allocations, so we may need
diff --git a/libc/bionic/scandir.cpp b/libc/bionic/scandir.cpp
index f528286..0acef36 100644
--- a/libc/bionic/scandir.cpp
+++ b/libc/bionic/scandir.cpp
@@ -69,11 +69,8 @@
}
void Sort(int (*comparator)(const dirent**, const dirent**)) {
- // If we have entries and a comparator, sort them.
- if (size_ > 0 && comparator != nullptr) {
- qsort(names_, size_, sizeof(dirent*),
- reinterpret_cast<int (*)(const void*, const void*)>(comparator));
- }
+ qsort(names_, size_, sizeof(dirent*),
+ reinterpret_cast<int (*)(const void*, const void*)>(comparator));
}
private:
@@ -120,7 +117,9 @@
names.Add(entry);
}
- names.Sort(comparator);
+ if (comparator != nullptr) {
+ names.Sort(comparator);
+ }
size_t size = names.size();
*name_list = names.release();
diff --git a/libc/bionic/spawn.cpp b/libc/bionic/spawn.cpp
index 7e80ef6..5cf95d8 100644
--- a/libc/bionic/spawn.cpp
+++ b/libc/bionic/spawn.cpp
@@ -340,7 +340,7 @@
if (action == nullptr) return errno;
action->next = nullptr;
- if (path != nullptr) {
+ if (what == kOpen) {
action->path = strdup(path);
if (action->path == nullptr) {
free(action);
diff --git a/libc/bionic/sysprop_helpers.cpp b/libc/bionic/sysprop_helpers.cpp
index 5627034..2051330 100644
--- a/libc/bionic/sysprop_helpers.cpp
+++ b/libc/bionic/sysprop_helpers.cpp
@@ -57,18 +57,22 @@
}
bool get_config_from_env_or_sysprops(const char* env_var_name, const char* const* sys_prop_names,
- size_t sys_prop_names_size, char* options,
- size_t options_size) {
+ size_t sys_prop_names_size, char* options, size_t options_size,
+ const char** chosen_source) {
const char* env = getenv(env_var_name);
if (env && *env != '\0') {
strncpy(options, env, options_size);
options[options_size - 1] = '\0'; // Ensure null-termination.
+ *chosen_source = env_var_name;
return true;
}
for (size_t i = 0; i < sys_prop_names_size; ++i) {
if (sys_prop_names[i] == nullptr) continue;
- if (get_property_value(sys_prop_names[i], options, options_size)) return true;
+ if (get_property_value(sys_prop_names[i], options, options_size)) {
+ *chosen_source = sys_prop_names[i];
+ return true;
+ }
}
return false;
}
diff --git a/libc/bionic/sysprop_helpers.h b/libc/bionic/sysprop_helpers.h
index a02c2dc..84e7af1 100644
--- a/libc/bionic/sysprop_helpers.h
+++ b/libc/bionic/sysprop_helpers.h
@@ -36,10 +36,13 @@
// 2. System properties, in the order they're specified in sys_prop_names.
// If neither of these options are specified (or they're both an empty string),
// this function returns false. Otherwise, it returns true, and the presiding
-// options string is written to the `options` buffer of size `size`. If this
-// function returns true, `options` is guaranteed to be null-terminated.
+// options string is written to the `options` buffer of size `size`. It will
+// store a pointer to either env_var_name, or into the relevant entry of
+// sys_prop_names into choicen_source, indiciating which value was used. If
+// this function returns true, `options` is guaranteed to be null-terminated.
// `options_size` should be at least PROP_VALUE_MAX.
__LIBC_HIDDEN__ bool get_config_from_env_or_sysprops(const char* env_var_name,
const char* const* sys_prop_names,
size_t sys_prop_names_size, char* options,
- size_t options_size);
+ size_t options_size,
+ const char** chosen_source);
diff --git a/libc/include/android/api-level.h b/libc/include/android/api-level.h
index 79085d1..6602e5d 100644
--- a/libc/include/android/api-level.h
+++ b/libc/include/android/api-level.h
@@ -162,9 +162,15 @@
*/
#define __ANDROID_API_T__ 33
-/** Names the "U" API level (34), for comparison against `__ANDROID_API__`. */
+/**
+ * Names the Android 14 (aka "U" or "UpsideDownCake") API level (34),
+ * for comparison against `__ANDROID_API__`.
+ */
#define __ANDROID_API_U__ 34
+/** Names the "V" API level (35), for comparison against `__ANDROID_API__`. */
+#define __ANDROID_API_V__ 35
+
/* This file is included in <features.h>, and might be used from .S files. */
#if !defined(__ASSEMBLY__)
diff --git a/libc/include/assert.h b/libc/include/assert.h
index 79e7b86..8db970b 100644
--- a/libc/include/assert.h
+++ b/libc/include/assert.h
@@ -75,12 +75,12 @@
* __assert() is called by assert() on failure. Most users want assert()
* instead, but this can be useful for reporting other failures.
*/
-void __assert(const char* __file, int __line, const char* __msg) __noreturn;
+void __assert(const char* _Nonnull __file, int __line, const char* _Nonnull __msg) __noreturn;
/**
* __assert2() is called by assert() on failure. Most users want assert()
* instead, but this can be useful for reporting other failures.
*/
-void __assert2(const char* __file, int __line, const char* __function, const char* __msg) __noreturn;
+void __assert2(const char* _Nonnull __file, int __line, const char* _Nonnull __function, const char* _Nonnull __msg) __noreturn;
__END_DECLS
diff --git a/libc/include/bits/elf_common.h b/libc/include/bits/elf_common.h
index ea833f4..b3c57a2 100644
--- a/libc/include/bits/elf_common.h
+++ b/libc/include/bits/elf_common.h
@@ -418,12 +418,12 @@
#define SHT_HIOS 0x6fffffff /* Last of OS specific semantics */
#define SHT_LOPROC 0x70000000 /* reserved range for processor */
#define SHT_X86_64_UNWIND 0x70000001 /* unwind information */
-#define SHT_AMD64_UNWIND SHT_X86_64_UNWIND
+#define SHT_AMD64_UNWIND SHT_X86_64_UNWIND
#define SHT_ARM_EXIDX 0x70000001 /* Exception index table. */
-#define SHT_ARM_PREEMPTMAP 0x70000002 /* BPABI DLL dynamic linking
+#define SHT_ARM_PREEMPTMAP 0x70000002 /* BPABI DLL dynamic linking
pre-emption map. */
-#define SHT_ARM_ATTRIBUTES 0x70000003 /* Object file compatibility
+#define SHT_ARM_ATTRIBUTES 0x70000003 /* Object file compatibility
attributes. */
#define SHT_ARM_DEBUGOVERLAY 0x70000004 /* See DBGOVL for details. */
#define SHT_ARM_OVERLAYSECTION 0x70000005 /* See DBGOVL for details. */
@@ -648,6 +648,11 @@
#define DT_AARCH64_BTI_PLT 0x70000001
#define DT_AARCH64_PAC_PLT 0x70000003
#define DT_AARCH64_VARIANT_PCS 0x70000005
+#define DT_AARCH64_MEMTAG_MODE 0x70000009
+#define DT_AARCH64_MEMTAG_HEAP 0x7000000b
+#define DT_AARCH64_MEMTAG_STACK 0x7000000c
+#define DT_AARCH64_MEMTAG_GLOBALS 0x7000000d
+#define DT_AARCH64_MEMTAG_GLOBALSSZ 0x7000000f
#define DT_ARM_SYMTABSZ 0x70000001
#define DT_ARM_PREEMPTMAP 0x70000002
diff --git a/libc/include/dirent.h b/libc/include/dirent.h
index 2328b1a..2751b9e 100644
--- a/libc/include/dirent.h
+++ b/libc/include/dirent.h
@@ -95,7 +95,7 @@
*
* Returns null and sets `errno` on failure.
*/
-DIR* opendir(const char* __path);
+DIR* _Nullable opendir(const char* _Nonnull __path);
/**
* [fopendir(3)](http://man7.org/linux/man-pages/man3/opendir.3.html)
@@ -103,7 +103,7 @@
*
* Returns null and sets `errno` on failure.
*/
-DIR* fdopendir(int __dir_fd);
+DIR* _Nullable fdopendir(int __dir_fd);
/**
* [readdir(3)](http://man7.org/linux/man-pages/man3/readdir.3.html)
@@ -113,7 +113,7 @@
* or returns null and leaves `errno` unchanged at the end of the directory,
* or returns null and sets `errno` on failure.
*/
-struct dirent* readdir(DIR* __dir);
+struct dirent* _Nullable readdir(DIR* _Nonnull __dir);
/**
* [readdir64(3)](http://man7.org/linux/man-pages/man3/readdir.3.html)
@@ -123,10 +123,10 @@
* or returns null and leaves `errno` unchanged at the end of the directory,
* or returns null and sets `errno` on failure.
*/
-struct dirent64* readdir64(DIR* __dir) __INTRODUCED_IN(21);
+struct dirent64* _Nullable readdir64(DIR* _Nonnull __dir) __INTRODUCED_IN(21);
-int readdir_r(DIR* __dir, struct dirent* __entry, struct dirent** __buffer) __attribute__((__deprecated__("readdir_r is deprecated; use readdir instead")));
-int readdir64_r(DIR* __dir, struct dirent64* __entry, struct dirent64** __buffer) __INTRODUCED_IN(21) __attribute__((__deprecated__("readdir64_r is deprecated; use readdir64 instead")));
+int readdir_r(DIR* _Nonnull __dir, struct dirent* _Nonnull __entry, struct dirent* _Nullable * _Nonnull __buffer) __attribute__((__deprecated__("readdir_r is deprecated; use readdir instead")));
+int readdir64_r(DIR* _Nonnull __dir, struct dirent64* _Nonnull __entry, struct dirent64* _Nullable * _Nonnull __buffer) __INTRODUCED_IN(21) __attribute__((__deprecated__("readdir64_r is deprecated; use readdir64 instead")));
/**
* [closedir(3)](http://man7.org/linux/man-pages/man3/closedir.3.html)
@@ -134,13 +134,13 @@
*
* Returns 0 on success and returns -1 and sets `errno` on failure.
*/
-int closedir(DIR* __dir);
+int closedir(DIR* _Nonnull __dir);
/**
* [rewinddir(3)](http://man7.org/linux/man-pages/man3/rewinddir.3.html)
* rewinds a directory stream to the first entry.
*/
-void rewinddir(DIR* __dir);
+void rewinddir(DIR* _Nonnull __dir);
/**
* [seekdir(3)](http://man7.org/linux/man-pages/man3/seekdir.3.html)
@@ -149,7 +149,7 @@
*
* Available since API level 23.
*/
-void seekdir(DIR* __dir, long __location) __INTRODUCED_IN(23);
+void seekdir(DIR* _Nonnull __dir, long __location) __INTRODUCED_IN(23);
/**
* [telldir(3)](http://man7.org/linux/man-pages/man3/telldir.3.html)
@@ -160,7 +160,7 @@
*
* Available since API level 23.
*/
-long telldir(DIR* __dir) __INTRODUCED_IN(23);
+long telldir(DIR* _Nonnull __dir) __INTRODUCED_IN(23);
/**
* [dirfd(3)](http://man7.org/linux/man-pages/man3/dirfd.3.html)
@@ -168,13 +168,13 @@
*
* Returns a file descriptor on success and returns -1 and sets `errno` on failure.
*/
-int dirfd(DIR* __dir);
+int dirfd(DIR* _Nonnull __dir);
/**
* [alphasort](http://man7.org/linux/man-pages/man3/alphasort.3.html) is a
* comparator for use with scandir() that uses strcoll().
*/
-int alphasort(const struct dirent** __lhs, const struct dirent** __rhs);
+int alphasort(const struct dirent* _Nonnull * _Nonnull __lhs, const struct dirent* _Nonnull * _Nonnull __rhs);
/**
* [alphasort64](http://man7.org/linux/man-pages/man3/alphasort.3.html) is a
@@ -182,31 +182,33 @@
*
* Available since API level 21.
*/
-int alphasort64(const struct dirent64** __lhs, const struct dirent64** __rhs) __INTRODUCED_IN(21);
+int alphasort64(const struct dirent64* _Nonnull * _Nonnull __lhs, const struct dirent64* _Nonnull * _Nonnull __rhs) __INTRODUCED_IN(21);
/**
* [scandir(3)](http://man7.org/linux/man-pages/man3/scandir.3.html)
* scans all the directory `__path`, filtering entries with `__filter` and
* sorting them with qsort() using the given `__comparator`, and storing them
* into `__name_list`. Passing NULL as the filter accepts all entries.
+ * Passing NULL as the comparator skips sorting.
*
* Returns the number of entries returned in the list on success,
* and returns -1 and sets `errno` on failure.
*/
-int scandir(const char* __path, struct dirent*** __name_list, int (*__filter)(const struct dirent*), int (*__comparator)(const struct dirent**, const struct dirent**));
+int scandir(const char* _Nonnull __path, struct dirent* _Nonnull * _Nonnull * _Nonnull __name_list, int (* _Nullable __filter)(const struct dirent* _Nonnull), int (* _Nullable __comparator)(const struct dirent* _Nonnull * _Nonnull, const struct dirent* _Nonnull * _Nonnull));
/**
* [scandir64(3)](http://man7.org/linux/man-pages/man3/scandir.3.html)
* scans all the directory `__path`, filtering entries with `__filter` and
* sorting them with qsort() using the given `__comparator`, and storing them
* into `__name_list`. Passing NULL as the filter accepts all entries.
+ * Passing NULL as the comparator skips sorting.
*
* Returns the number of entries returned in the list on success,
* and returns -1 and sets `errno` on failure.
*
* Available since API level 21.
*/
-int scandir64(const char* __path, struct dirent64*** __name_list, int (*__filter)(const struct dirent64*), int (*__comparator)(const struct dirent64**, const struct dirent64**)) __INTRODUCED_IN(21);
+int scandir64(const char* _Nonnull __path, struct dirent64* _Nonnull * _Nonnull * _Nonnull __name_list, int (* _Nullable __filter)(const struct dirent64* _Nonnull), int (* _Nullable __comparator)(const struct dirent64* _Nonnull * _Nonnull, const struct dirent64* _Nonnull * _Nonnull)) __INTRODUCED_IN(21);
#if defined(__USE_GNU)
@@ -216,13 +218,14 @@
* filtering entries with `__filter` and sorting them with qsort() using the
* given `__comparator`, and storing them into `__name_list`. Passing NULL as
* the filter accepts all entries.
+ * Passing NULL as the comparator skips sorting.
*
* Returns the number of entries returned in the list on success,
* and returns -1 and sets `errno` on failure.
*
* Available since API level 24.
*/
-int scandirat64(int __dir_fd, const char* __path, struct dirent64*** __name_list, int (*__filter)(const struct dirent64*), int (*__comparator)(const struct dirent64**, const struct dirent64**)) __INTRODUCED_IN(24);
+int scandirat64(int __dir_fd, const char* _Nonnull __path, struct dirent64* _Nonnull * _Nonnull * _Nonnull __name_list, int (* _Nullable __filter)(const struct dirent64* _Nonnull), int (* _Nullable __comparator)(const struct dirent64* _Nonnull * _Nonnull, const struct dirent64* _Nonnull * _Nonnull)) __INTRODUCED_IN(24);
/**
* [scandirat(3)](http://man7.org/linux/man-pages/man3/scandirat.3.html)
@@ -230,13 +233,14 @@
* filtering entries with `__filter` and sorting them with qsort() using the
* given `__comparator`, and storing them into `__name_list`. Passing NULL as
* the filter accepts all entries.
+ * Passing NULL as the comparator skips sorting.
*
* Returns the number of entries returned in the list on success,
* and returns -1 and sets `errno` on failure.
*
* Available since API level 24.
*/
-int scandirat(int __dir_fd, const char* __path, struct dirent*** __name_list, int (*__filter)(const struct dirent*), int (*__comparator)(const struct dirent**, const struct dirent**)) __INTRODUCED_IN(24);
+int scandirat(int __dir_fd, const char* _Nonnull __path, struct dirent* _Nonnull * _Nonnull * _Nonnull __name_list, int (* _Nullable __filter)(const struct dirent* _Nonnull), int (* _Nullable __comparator)(const struct dirent* _Nonnull * _Nonnull, const struct dirent* _Nonnull * _Nonnull)) __INTRODUCED_IN(24);
#endif
diff --git a/libc/include/fts.h b/libc/include/fts.h
index 7e63111..bae2615 100644
--- a/libc/include/fts.h
+++ b/libc/include/fts.h
@@ -39,15 +39,15 @@
#include <sys/types.h>
typedef struct {
- struct _ftsent *fts_cur; /* current node */
- struct _ftsent *fts_child; /* linked list of children */
- struct _ftsent **fts_array; /* sort array */
+ struct _ftsent * _Nullable fts_cur; /* current node */
+ struct _ftsent * _Nullable fts_child; /* linked list of children */
+ struct _ftsent * _Nullable * _Nullable fts_array; /* sort array */
dev_t fts_dev; /* starting device # */
- char *fts_path; /* path for this descent */
+ char * _Nullable fts_path; /* path for this descent */
int fts_rfd; /* fd for root */
size_t fts_pathlen; /* sizeof(path) */
int fts_nitems; /* elements in the sort array */
- int (*fts_compar)(); /* compare function */
+ int (* _Nullable fts_compar)(); /* compare function */
#define FTS_COMFOLLOW 0x0001 /* follow command line symlinks */
#define FTS_LOGICAL 0x0002 /* logical walk */
@@ -65,13 +65,13 @@
} FTS;
typedef struct _ftsent {
- struct _ftsent *fts_cycle; /* cycle node */
- struct _ftsent *fts_parent; /* parent directory */
- struct _ftsent *fts_link; /* next file in directory */
+ struct _ftsent * _Nullable fts_cycle; /* cycle node */
+ struct _ftsent * _Nullable fts_parent; /* parent directory */
+ struct _ftsent * _Nullable fts_link; /* next file in directory */
long fts_number; /* local numeric value */
- void *fts_pointer; /* local address value */
- char *fts_accpath; /* access path */
- char *fts_path; /* root path */
+ void * _Nullable fts_pointer; /* local address value */
+ char * _Nullable fts_accpath; /* access path */
+ char * _Nullable fts_path; /* root path */
int fts_errno; /* errno for this node */
int fts_symfd; /* fd for symlink */
size_t fts_pathlen; /* strlen(fts_path) */
@@ -111,7 +111,7 @@
#define FTS_SKIP 4 /* discard node */
unsigned short fts_instr; /* fts_set() instructions */
- struct stat *fts_statp; /* stat(2) information */
+ struct stat * _Nullable fts_statp; /* stat(2) information */
char fts_name[1]; /* file name */
} FTSENT;
@@ -122,11 +122,11 @@
* breakage in 21 that means you can't write code that runs on current devices and pre-21 devices,
* so we break the tie in favor of current and future devices.
*/
-FTSENT* fts_children(FTS* __fts, int __options) __INTRODUCED_IN(21);
-int fts_close(FTS* __fts) __INTRODUCED_IN(21);
-FTS* fts_open(char* const* __path, int __options, int (*__comparator)(const FTSENT** __lhs, const FTSENT** __rhs)) __INTRODUCED_IN(21);
-FTSENT* fts_read(FTS* __fts) __INTRODUCED_IN(21);
-int fts_set(FTS* __fts, FTSENT* __entry, int __options) __INTRODUCED_IN(21);
+FTSENT* _Nullable fts_children(FTS* _Nonnull __fts, int __options) __INTRODUCED_IN(21);
+int fts_close(FTS* _Nonnull __fts) __INTRODUCED_IN(21);
+FTS* _Nullable fts_open(char* _Nonnull const* _Nonnull __path, int __options, int (* _Nullable __comparator)(const FTSENT* _Nonnull * _Nonnull __lhs, const FTSENT* _Nonnull * _Nonnull __rhs)) __INTRODUCED_IN(21);
+FTSENT* _Nullable fts_read(FTS* _Nonnull __fts) __INTRODUCED_IN(21);
+int fts_set(FTS* _Nonnull __fts, FTSENT* _Nonnull __entry, int __options) __INTRODUCED_IN(21);
__END_DECLS
diff --git a/libc/include/getopt.h b/libc/include/getopt.h
index 014226a..c1c0442 100644
--- a/libc/include/getopt.h
+++ b/libc/include/getopt.h
@@ -49,8 +49,11 @@
#define optional_argument 2
struct option {
- /** Name of long option. */
- const char *name;
+ /**
+ * Name of long option. Options must have a non-NULL name.
+ * A NULL name signals the end of the options array.
+ */
+ const char * _Nullable name;
/**
* One of `no_argument`, `required_argument`, or `optional_argument`.
@@ -58,7 +61,7 @@
int has_arg;
/** If not NULL, set `*flag` to val when option found. */
- int* flag;
+ int* _Nullable flag;
/** If `flag` not NULL, the value to assign to `*flag`; otherwise the return value. */
int val;
@@ -69,12 +72,12 @@
/**
* [getopt_long(3)](http://man7.org/linux/man-pages/man3/getopt.3.html) parses command-line options.
*/
-int getopt_long(int __argc, char* const* __argv, const char* __options, const struct option* __long_options, int* __long_index);
+int getopt_long(int __argc, char* _Nonnull const* _Nonnull __argv, const char* _Nonnull __options, const struct option* _Nonnull __long_options, int* _Nullable __long_index);
/**
* [getopt_long_only(3)](http://man7.org/linux/man-pages/man3/getopt.3.html) parses command-line options.
*/
-int getopt_long_only(int __argc, char* const* __argv, const char* __options, const struct option* __long_options, int* __long_index);
+int getopt_long_only(int __argc, char* _Nonnull const* _Nonnull __argv, const char* _Nonnull __options, const struct option* _Nonnull __long_options, int* _Nullable __long_index);
#ifndef _OPTRESET_DECLARED
#define _OPTRESET_DECLARED
diff --git a/libc/include/grp.h b/libc/include/grp.h
index 9d67adf..2451db5 100644
--- a/libc/include/grp.h
+++ b/libc/include/grp.h
@@ -39,26 +39,26 @@
#include <sys/types.h>
struct group {
- char* gr_name; /* group name */
- char* gr_passwd; /* group password */
+ char* _Nullable gr_name; /* group name */
+ char* _Nullable gr_passwd; /* group password */
gid_t gr_gid; /* group id */
- char** gr_mem; /* group members */
+ char* _Nullable * _Nullable gr_mem; /* group members */
};
__BEGIN_DECLS
-struct group* getgrgid(gid_t __gid);
-struct group* getgrnam(const char* __name);
+struct group* _Nullable getgrgid(gid_t __gid);
+struct group* _Nullable getgrnam(const char* _Nonnull __name);
/* Note: Android has thousands and thousands of ids to iterate through. */
-struct group* getgrent(void) __INTRODUCED_IN(26);
+struct group* _Nullable getgrent(void) __INTRODUCED_IN(26);
void setgrent(void) __INTRODUCED_IN(26);
void endgrent(void) __INTRODUCED_IN(26);
-int getgrgid_r(gid_t __gid, struct group* __group, char* __buf, size_t __n, struct group** __result) __INTRODUCED_IN(24);
-int getgrnam_r(const char* __name, struct group* __group, char* __buf, size_t __n, struct group** __result) __INTRODUCED_IN(24);
-int getgrouplist(const char* __user, gid_t __group, gid_t* __groups, int* __group_count);
-int initgroups(const char* __user, gid_t __group);
+int getgrgid_r(gid_t __gid, struct group* __BIONIC_COMPLICATED_NULLNESS __group, char* _Nonnull __buf, size_t __n, struct group* _Nullable * _Nonnull __result) __INTRODUCED_IN(24);
+int getgrnam_r(const char* _Nonnull __name, struct group* __BIONIC_COMPLICATED_NULLNESS __group, char* _Nonnull __buf, size_t __n, struct group* _Nullable *_Nonnull __result) __INTRODUCED_IN(24);
+int getgrouplist(const char* _Nonnull __user, gid_t __group, gid_t* __BIONIC_COMPLICATED_NULLNESS __groups, int* _Nonnull __group_count);
+int initgroups(const char* _Nonnull __user, gid_t __group);
__END_DECLS
diff --git a/libc/include/inttypes.h b/libc/include/inttypes.h
index f8b7f7d..76aee38 100644
--- a/libc/include/inttypes.h
+++ b/libc/include/inttypes.h
@@ -85,6 +85,42 @@
#define PRIiPTR __PRI_PTR_prefix"i" /* intptr_t */
/* fprintf macros for unsigned integers */
+#define PRIb8 "b" /* int8_t */
+#define PRIb16 "b" /* int16_t */
+#define PRIb32 "b" /* int32_t */
+#define PRIb64 __PRI_64_prefix"b" /* int64_t */
+
+#define PRIbLEAST8 "b" /* int_least8_t */
+#define PRIbLEAST16 "b" /* int_least16_t */
+#define PRIbLEAST32 "b" /* int_least32_t */
+#define PRIbLEAST64 __PRI_64_prefix"b" /* int_least64_t */
+
+#define PRIbFAST8 "b" /* int_fast8_t */
+#define PRIbFAST16 __PRI_FAST_prefix"b" /* int_fast16_t */
+#define PRIbFAST32 __PRI_FAST_prefix"b" /* int_fast32_t */
+#define PRIbFAST64 __PRI_64_prefix"b" /* int_fast64_t */
+
+#define PRIbMAX "jb" /* intmax_t */
+#define PRIbPTR __PRI_PTR_prefix"b" /* intptr_t */
+
+#define PRIB8 "B" /* int8_t */
+#define PRIB16 "B" /* int16_t */
+#define PRIB32 "B" /* int32_t */
+#define PRIB64 __PRI_64_prefix"B" /* int64_t */
+
+#define PRIBLEAST8 "B" /* int_least8_t */
+#define PRIBLEAST16 "B" /* int_least16_t */
+#define PRIBLEAST32 "B" /* int_least32_t */
+#define PRIBLEAST64 __PRI_64_prefix"B" /* int_least64_t */
+
+#define PRIBFAST8 "B" /* int_fast8_t */
+#define PRIBFAST16 __PRI_FAST_prefix"B" /* int_fast16_t */
+#define PRIBFAST32 __PRI_FAST_prefix"B" /* int_fast32_t */
+#define PRIBFAST64 __PRI_64_prefix"B" /* int_fast64_t */
+
+#define PRIBMAX "jB" /* intmax_t */
+#define PRIBPTR __PRI_PTR_prefix"B" /* intptr_t */
+
#define PRIo8 "o" /* int8_t */
#define PRIo16 "o" /* int16_t */
#define PRIo32 "o" /* int32_t */
@@ -195,6 +231,42 @@
#define SCNiPTR __PRI_PTR_prefix"i" /* intptr_t */
/* fscanf macros for unsigned integers */
+#define SCNb8 "hhb" /* uint8_t */
+#define SCNb16 "hb" /* uint16_t */
+#define SCNb32 "b" /* uint32_t */
+#define SCNb64 __PRI_64_prefix"b" /* uint64_t */
+
+#define SCNbLEAST8 "hhb" /* uint_least8_t */
+#define SCNbLEAST16 "hb" /* uint_least16_t */
+#define SCNbLEAST32 "b" /* uint_least32_t */
+#define SCNbLEAST64 __PRI_64_prefix"b" /* uint_least64_t */
+
+#define SCNbFAST8 "hhb" /* uint_fast8_t */
+#define SCNbFAST16 __PRI_FAST_prefix"b" /* uint_fast16_t */
+#define SCNbFAST32 __PRI_FAST_prefix"b" /* uint_fast32_t */
+#define SCNbFAST64 __PRI_64_prefix"b" /* uint_fast64_t */
+
+#define SCNbMAX "jb" /* uintmax_t */
+#define SCNbPTR __PRI_PTR_prefix"b" /* uintptr_t */
+
+#define SCNB8 "hhB" /* uint8_t */
+#define SCNB16 "hB" /* uint16_t */
+#define SCNB32 "B" /* uint32_t */
+#define SCNB64 __PRI_64_prefix"B" /* uint64_t */
+
+#define SCNBLEAST8 "hhB" /* uint_least8_t */
+#define SCNBLEAST16 "hB" /* uint_least16_t */
+#define SCNBLEAST32 "B" /* uint_least32_t */
+#define SCNBLEAST64 __PRI_64_prefix"B" /* uint_least64_t */
+
+#define SCNBFAST8 "hhB" /* uint_fast8_t */
+#define SCNBFAST16 __PRI_FAST_prefix"B" /* uint_fast16_t */
+#define SCNBFAST32 __PRI_FAST_prefix"B" /* uint_fast32_t */
+#define SCNBFAST64 __PRI_64_prefix"B" /* uint_fast64_t */
+
+#define SCNBMAX "jB" /* uintmax_t */
+#define SCNBPTR __PRI_PTR_prefix"B" /* uintptr_t */
+
#define SCNo8 "hho" /* uint8_t */
#define SCNo16 "ho" /* uint16_t */
#define SCNo32 "o" /* uint32_t */
diff --git a/libc/include/link.h b/libc/include/link.h
index bd430f5..a0a3d60 100644
--- a/libc/include/link.h
+++ b/libc/include/link.h
@@ -44,41 +44,41 @@
struct dl_phdr_info {
ElfW(Addr) dlpi_addr;
- const char* dlpi_name;
- const ElfW(Phdr)* dlpi_phdr;
+ const char* _Nullable dlpi_name;
+ const ElfW(Phdr)* _Nullable dlpi_phdr;
ElfW(Half) dlpi_phnum;
// These fields were added in Android R.
unsigned long long dlpi_adds;
unsigned long long dlpi_subs;
size_t dlpi_tls_modid;
- void* dlpi_tls_data;
+ void* _Nullable dlpi_tls_data;
};
#if defined(__arm__)
-int dl_iterate_phdr(int (*__callback)(struct dl_phdr_info*, size_t, void*), void* __data) __INTRODUCED_IN(21);
+int dl_iterate_phdr(int (* _Nonnull __callback)(struct dl_phdr_info* _Nonnull, size_t, void* _Nullable), void* _Nullable __data) __INTRODUCED_IN(21);
#else
-int dl_iterate_phdr(int (*__callback)(struct dl_phdr_info*, size_t, void*), void* __data);
+int dl_iterate_phdr(int (* _Nonnull __callback)(struct dl_phdr_info* _Nonnull, size_t, void*_Nullable ), void* _Nullable __data);
#endif
#ifdef __arm__
typedef uintptr_t _Unwind_Ptr;
-_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr, int*);
+_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr, int* _Nonnull);
#endif
/* Used by the dynamic linker to communicate with the debugger. */
struct link_map {
ElfW(Addr) l_addr;
- char* l_name;
- ElfW(Dyn)* l_ld;
- struct link_map* l_next;
- struct link_map* l_prev;
+ char* _Nullable l_name;
+ ElfW(Dyn)* _Nullable l_ld;
+ struct link_map* _Nullable l_next;
+ struct link_map* _Nullable l_prev;
};
/* Used by the dynamic linker to communicate with the debugger. */
struct r_debug {
int32_t r_version;
- struct link_map* r_map;
+ struct link_map* _Nullable r_map;
ElfW(Addr) r_brk;
enum {
RT_CONSISTENT,
diff --git a/libc/include/locale.h b/libc/include/locale.h
index 8785b24..27f2a3f 100644
--- a/libc/include/locale.h
+++ b/libc/include/locale.h
@@ -70,16 +70,16 @@
LC_IDENTIFICATION_MASK)
struct lconv {
- char* decimal_point;
- char* thousands_sep;
- char* grouping;
- char* int_curr_symbol;
- char* currency_symbol;
- char* mon_decimal_point;
- char* mon_thousands_sep;
- char* mon_grouping;
- char* positive_sign;
- char* negative_sign;
+ char* _Nonnull decimal_point;
+ char* _Nonnull thousands_sep;
+ char* _Nonnull grouping;
+ char* _Nonnull int_curr_symbol;
+ char* _Nonnull currency_symbol;
+ char* _Nonnull mon_decimal_point;
+ char* _Nonnull mon_thousands_sep;
+ char* _Nonnull mon_grouping;
+ char* _Nonnull positive_sign;
+ char* _Nonnull negative_sign;
char int_frac_digits;
char frac_digits;
char p_cs_precedes;
@@ -96,13 +96,13 @@
char int_n_sign_posn;
};
-struct lconv* localeconv(void) __INTRODUCED_IN_NO_GUARD_FOR_NDK(21);
+struct lconv* _Nonnull localeconv(void) __INTRODUCED_IN_NO_GUARD_FOR_NDK(21);
-locale_t duplocale(locale_t __l) __INTRODUCED_IN(21);
-void freelocale(locale_t __l) __INTRODUCED_IN(21);
-locale_t newlocale(int __category_mask, const char* __locale_name, locale_t __base) __INTRODUCED_IN(21);
-char* setlocale(int __category, const char* __locale_name);
-locale_t uselocale(locale_t __l) __INTRODUCED_IN(21);
+locale_t _Nullable duplocale(locale_t _Nonnull __l) __INTRODUCED_IN(21);
+void freelocale(locale_t _Nonnull __l) __INTRODUCED_IN(21);
+locale_t _Nullable newlocale(int __category_mask, const char* _Nonnull __locale_name, locale_t _Nullable __base) __INTRODUCED_IN(21);
+char* _Nullable setlocale(int __category, const char* _Nullable __locale_name);
+locale_t _Nullable uselocale(locale_t _Nullable __l) __INTRODUCED_IN(21);
#define LC_GLOBAL_LOCALE __BIONIC_CAST(reinterpret_cast, locale_t, -1L)
diff --git a/libc/include/malloc.h b/libc/include/malloc.h
index 02bda60..6a2d380 100644
--- a/libc/include/malloc.h
+++ b/libc/include/malloc.h
@@ -183,7 +183,15 @@
* Available since API level 28.
*/
#define M_PURGE (-101)
-
+/**
+ * mallopt() option to immediately purge all possible memory back to
+ * the kernel. This call can take longer than a normal purge since it
+ * examines everything. In some cases, it can take more than twice the
+ * time of a M_PURGE call. The value is ignored.
+ *
+ * Available since API level 34.
+ */
+#define M_PURGE_ALL (-104)
/**
* mallopt() option to tune the allocator's choice of memory tags to
diff --git a/libc/include/mntent.h b/libc/include/mntent.h
index d5987dc..43cab1f 100644
--- a/libc/include/mntent.h
+++ b/libc/include/mntent.h
@@ -47,21 +47,21 @@
#define MNTOPT_SUID "suid"
struct mntent {
- char* mnt_fsname;
- char* mnt_dir;
- char* mnt_type;
- char* mnt_opts;
+ char* _Nullable mnt_fsname;
+ char* _Nullable mnt_dir;
+ char* _Nullable mnt_type;
+ char* _Nullable mnt_opts;
int mnt_freq;
int mnt_passno;
};
__BEGIN_DECLS
-int endmntent(FILE* __fp) __INTRODUCED_IN(21);
-struct mntent* getmntent(FILE* __fp);
-struct mntent* getmntent_r(FILE* __fp, struct mntent* __entry, char* __buf, int __size) __INTRODUCED_IN(21);
-FILE* setmntent(const char* __filename, const char* __type) __INTRODUCED_IN(21);
-char* hasmntopt(const struct mntent* __entry, const char* __option) __INTRODUCED_IN(26);
+int endmntent(FILE* _Nullable __fp) __INTRODUCED_IN(21);
+struct mntent* _Nullable getmntent(FILE* _Nonnull __fp);
+struct mntent* _Nullable getmntent_r(FILE* _Nonnull __fp, struct mntent* _Nonnull __entry, char* _Nonnull __buf, int __size) __INTRODUCED_IN(21);
+FILE* _Nullable setmntent(const char* _Nonnull __filename, const char* _Nonnull __type) __INTRODUCED_IN(21);
+char* _Nullable hasmntopt(const struct mntent* _Nonnull __entry, const char* _Nonnull __option) __INTRODUCED_IN(26);
__END_DECLS
diff --git a/libc/include/pwd.h b/libc/include/pwd.h
index d481aac..2b17fbf 100644
--- a/libc/include/pwd.h
+++ b/libc/include/pwd.h
@@ -66,31 +66,31 @@
__BEGIN_DECLS
struct passwd {
- char* pw_name;
- char* pw_passwd;
+ char* _Nullable pw_name;
+ char* _Nullable pw_passwd;
uid_t pw_uid;
gid_t pw_gid;
#ifdef __LP64__
- char* pw_gecos;
+ char* _Nullable pw_gecos;
#else
/* Note: On LP32, we define pw_gecos to pw_passwd since they're both NULL. */
# define pw_gecos pw_passwd
#endif
- char* pw_dir;
- char* pw_shell;
+ char* _Nullable pw_dir;
+ char* _Nullable pw_shell;
};
-struct passwd* getpwnam(const char* __name);
-struct passwd* getpwuid(uid_t __uid);
+struct passwd* _Nullable getpwnam(const char* _Nonnull __name);
+struct passwd* _Nullable getpwuid(uid_t __uid);
/* Note: Android has thousands and thousands of ids to iterate through */
-struct passwd* getpwent(void) __INTRODUCED_IN(26);
+struct passwd* _Nullable getpwent(void) __INTRODUCED_IN(26);
void setpwent(void) __INTRODUCED_IN(26);
void endpwent(void) __INTRODUCED_IN(26);
-int getpwnam_r(const char* __name, struct passwd* __pwd, char* __buf, size_t __n, struct passwd** __result);
-int getpwuid_r(uid_t __uid, struct passwd* __pwd, char* __buf, size_t __n, struct passwd** __result);
+int getpwnam_r(const char* _Nonnull __name, struct passwd* _Nonnull __pwd, char* _Nonnull __buf, size_t __n, struct passwd* _Nullable * _Nonnull __result);
+int getpwuid_r(uid_t __uid, struct passwd* _Nonnull __pwd, char* _Nonnull __buf, size_t __n, struct passwd* _Nullable * _Nonnull __result);
__END_DECLS
diff --git a/libc/include/resolv.h b/libc/include/resolv.h
index 6318d00..f25484a 100644
--- a/libc/include/resolv.h
+++ b/libc/include/resolv.h
@@ -40,24 +40,24 @@
__BEGIN_DECLS
#define b64_ntop __b64_ntop
-int b64_ntop(u_char const* __src, size_t __src_size, char* __dst, size_t __dst_size);
+int b64_ntop(u_char const* _Nonnull __src, size_t __src_size, char* _Nonnull __dst, size_t __dst_size);
#define b64_pton __b64_pton
-int b64_pton(char const* __src, u_char* __dst, size_t __dst_size);
+int b64_pton(char const* _Nonnull __src, u_char* _Nonnull __dst, size_t __dst_size);
#define dn_comp __dn_comp
-int dn_comp(const char* __src, u_char* __dst, int __dst_size, u_char** __dn_ptrs , u_char** __last_dn_ptr);
+int dn_comp(const char* _Nonnull __src, u_char* _Nonnull __dst, int __dst_size, u_char* _Nullable * _Nullable __dn_ptrs , u_char* _Nullable * _Nullable __last_dn_ptr);
-int dn_expand(const u_char* __msg, const u_char* __eom, const u_char* __src, char* __dst, int __dst_size);
+int dn_expand(const u_char* _Nonnull __msg, const u_char* _Nonnull __eom, const u_char* _Nonnull __src, char* _Nonnull __dst, int __dst_size);
#define p_class __p_class
-const char* p_class(int __class);
+const char* _Nonnull p_class(int __class);
#define p_type __p_type
-const char* p_type(int __type);
+const char* _Nonnull p_type(int __type);
int res_init(void);
-int res_mkquery(int __opcode, const char* __domain_name, int __class, int __type, const u_char* __data, int __data_size, const u_char* __new_rr_in, u_char* __buf, int __buf_size);
-int res_query(const char* __name, int __class, int __type, u_char* __answer, int __answer_size);
-int res_search(const char* __name, int __class, int __type, u_char* __answer, int __answer_size);
+int res_mkquery(int __opcode, const char* _Nonnull __domain_name, int __class, int __type, const u_char* _Nullable __data, int __data_size, const u_char* _Nullable __new_rr_in, u_char* _Nonnull __buf, int __buf_size);
+int res_query(const char* _Nonnull __name, int __class, int __type, u_char* _Nonnull __answer, int __answer_size);
+int res_search(const char* _Nonnull __name, int __class, int __type, u_char* _Nonnull __answer, int __answer_size);
#define res_randomid __res_randomid
u_int __res_randomid(void) __INTRODUCED_IN(29);
diff --git a/libc/include/sched.h b/libc/include/sched.h
index 364ca10..26bc742 100644
--- a/libc/include/sched.h
+++ b/libc/include/sched.h
@@ -104,7 +104,7 @@
*
* Returns 0 on success and returns -1 and sets `errno` on failure.
*/
-int sched_setscheduler(pid_t __pid, int __policy, const struct sched_param* __param);
+int sched_setscheduler(pid_t __pid, int __policy, const struct sched_param* _Nonnull __param);
/**
* [sched_getscheduler(2)](http://man7.org/linux/man-pages/man2/sched_getcpu.2.html)
@@ -145,7 +145,7 @@
*
* Returns 0 on success and returns -1 and sets `errno` on failure.
*/
-int sched_setparam(pid_t __pid, const struct sched_param* __param);
+int sched_setparam(pid_t __pid, const struct sched_param* _Nonnull __param);
/**
* [sched_getparam(2)](http://man7.org/linux/man-pages/man2/sched_getparam.2.html)
@@ -153,7 +153,7 @@
*
* Returns 0 on success and returns -1 and sets `errno` on failure.
*/
-int sched_getparam(pid_t __pid, struct sched_param* __param);
+int sched_getparam(pid_t __pid, struct sched_param* _Nonnull __param);
/**
* [sched_rr_get_interval(2)](http://man7.org/linux/man-pages/man2/sched_rr_get_interval.2.html)
@@ -161,7 +161,7 @@
*
* Returns 0 on success and returns -1 and sets `errno` on failure.
*/
-int sched_rr_get_interval(pid_t __pid, struct timespec* __quantum);
+int sched_rr_get_interval(pid_t __pid, struct timespec* _Nonnull __quantum);
#if defined(__USE_GNU)
@@ -172,7 +172,7 @@
* Returns the pid of the child to the caller on success and
* returns -1 and sets `errno` on failure.
*/
-int clone(int (*__fn)(void*), void* __child_stack, int __flags, void* __arg, ...) __INTRODUCED_IN_ARM(9) __INTRODUCED_IN_X86(17);
+int clone(int (* __BIONIC_COMPLICATED_NULLNESS __fn)(void* __BIONIC_COMPLICATED_NULLNESS ), void* __BIONIC_COMPLICATED_NULLNESS __child_stack, int __flags, void* _Nullable __arg, ...) __INTRODUCED_IN_ARM(9) __INTRODUCED_IN_X86(17);
/**
* [unshare(2)](http://man7.org/linux/man-pages/man2/unshare.2.html)
@@ -228,7 +228,7 @@
*
* Returns 0 on success and returns -1 and sets `errno` on failure.
*/
-int sched_setaffinity(pid_t __pid, size_t __set_size, const cpu_set_t* __set);
+int sched_setaffinity(pid_t __pid, size_t __set_size, const cpu_set_t* _Nonnull __set);
/**
* [sched_getaffinity(2)](http://man7.org/linux/man-pages/man2/sched_getaffinity.2.html)
@@ -236,7 +236,7 @@
*
* Returns 0 on success and returns -1 and sets `errno` on failure.
*/
-int sched_getaffinity(pid_t __pid, size_t __set_size, cpu_set_t* __set);
+int sched_getaffinity(pid_t __pid, size_t __set_size, cpu_set_t* _Nonnull __set);
/**
* [CPU_ZERO](https://man7.org/linux/man-pages/man3/CPU_SET.3.html) clears all
@@ -308,7 +308,7 @@
* how many bits are set in a dynamic CPU set allocated by `CPU_ALLOC`.
*/
#define CPU_COUNT_S(setsize, set) __sched_cpucount((setsize), (set))
-int __sched_cpucount(size_t __set_size, const cpu_set_t* __set);
+int __sched_cpucount(size_t __set_size, const cpu_set_t* _Nonnull __set);
/**
* [CPU_EQUAL](https://man7.org/linux/man-pages/man3/CPU_SET.3.html) tests
@@ -379,14 +379,14 @@
* allocates a CPU set large enough for CPUs in the range 0..count-1.
*/
#define CPU_ALLOC(count) __sched_cpualloc((count))
-cpu_set_t* __sched_cpualloc(size_t __count);
+cpu_set_t* _Nullable __sched_cpualloc(size_t __count);
/**
* [CPU_FREE](https://man7.org/linux/man-pages/man3/CPU_SET.3.html)
* deallocates a CPU set allocated by `CPU_ALLOC`.
*/
#define CPU_FREE(set) __sched_cpufree((set))
-void __sched_cpufree(cpu_set_t* __set);
+void __sched_cpufree(cpu_set_t* _Nonnull __set);
#endif /* __USE_GNU */
diff --git a/libc/include/stdio.h b/libc/include/stdio.h
index f4b2911..e748faa 100644
--- a/libc/include/stdio.h
+++ b/libc/include/stdio.h
@@ -59,9 +59,9 @@
typedef struct __sFILE FILE;
#if __ANDROID_API__ >= 23
-extern FILE* stdin __INTRODUCED_IN(23);
-extern FILE* stdout __INTRODUCED_IN(23);
-extern FILE* stderr __INTRODUCED_IN(23);
+extern FILE* _Nonnull stdin __INTRODUCED_IN(23);
+extern FILE* _Nonnull stdout __INTRODUCED_IN(23);
+extern FILE* _Nonnull stderr __INTRODUCED_IN(23);
/* C99 and earlier plus current C++ standards say these must be macros. */
#define stdin stdin
@@ -103,54 +103,54 @@
#define L_tmpnam 4096
#define TMP_MAX 308915776
-void clearerr(FILE* __fp);
-int fclose(FILE* __fp);
-int feof(FILE* __fp);
-int ferror(FILE* __fp);
-int fflush(FILE* __fp);
-int fgetc(FILE* __fp);
-char* fgets(char* __buf, int __size, FILE* __fp);
-int fprintf(FILE* __fp , const char* __fmt, ...) __printflike(2, 3);
-int fputc(int __ch, FILE* __fp);
-int fputs(const char* __s, FILE* __fp);
-size_t fread(void* __buf, size_t __size, size_t __count, FILE* __fp);
-int fscanf(FILE* __fp, const char* __fmt, ...) __scanflike(2, 3);
-size_t fwrite(const void* __buf, size_t __size, size_t __count, FILE* __fp);
-int getc(FILE* __fp);
+void clearerr(FILE* _Nonnull __fp);
+int fclose(FILE* _Nonnull __fp);
+int feof(FILE* _Nonnull __fp);
+int ferror(FILE* _Nonnull __fp);
+int fflush(FILE* _Nullable __fp);
+int fgetc(FILE* _Nonnull __fp);
+char* _Nullable fgets(char* _Nonnull __buf, int __size, FILE* _Nonnull __fp);
+int fprintf(FILE* _Nonnull __fp , const char* _Nonnull __fmt, ...) __printflike(2, 3);
+int fputc(int __ch, FILE* _Nonnull __fp);
+int fputs(const char* _Nonnull __s, FILE* _Nonnull __fp);
+size_t fread(void* _Nonnull __buf, size_t __size, size_t __count, FILE* _Nonnull __fp);
+int fscanf(FILE* _Nonnull __fp, const char* _Nonnull __fmt, ...) __scanflike(2, 3);
+size_t fwrite(const void* _Nonnull __buf, size_t __size, size_t __count, FILE* _Nonnull __fp);
+int getc(FILE* _Nonnull __fp);
int getchar(void);
-ssize_t getdelim(char** __line_ptr, size_t* __line_length_ptr, int __delimiter, FILE* __fp) __INTRODUCED_IN(18);
-ssize_t getline(char** __line_ptr, size_t* __line_length_ptr, FILE* __fp) __INTRODUCED_IN(18);
+ssize_t getdelim(char* _Nullable * _Nonnull __line_ptr, size_t* _Nonnull __line_length_ptr, int __delimiter, FILE* _Nonnull __fp) __INTRODUCED_IN(18);
+ssize_t getline(char* _Nullable * _Nonnull __line_ptr, size_t* _Nonnull __line_length_ptr, FILE* _Nonnull __fp) __INTRODUCED_IN(18);
-void perror(const char* __msg);
-int printf(const char* __fmt, ...) __printflike(1, 2);
-int putc(int __ch, FILE* __fp);
+void perror(const char* _Nullable __msg);
+int printf(const char* _Nonnull __fmt, ...) __printflike(1, 2);
+int putc(int __ch, FILE* _Nonnull __fp);
int putchar(int __ch);
-int puts(const char* __s);
-int remove(const char* __path);
-void rewind(FILE* __fp);
-int scanf(const char* __fmt, ...) __scanflike(1, 2);
-void setbuf(FILE* __fp, char* __buf);
-int setvbuf(FILE* __fp, char* __buf, int __mode, size_t __size);
-int sscanf(const char* __s, const char* __fmt, ...) __scanflike(2, 3);
-int ungetc(int __ch, FILE* __fp);
-int vfprintf(FILE* __fp, const char* __fmt, va_list __args) __printflike(2, 0);
-int vprintf(const char* __fp, va_list __args) __printflike(1, 0);
+int puts(const char* _Nonnull __s);
+int remove(const char* _Nonnull __path);
+void rewind(FILE* _Nonnull __fp);
+int scanf(const char* _Nonnull __fmt, ...) __scanflike(1, 2);
+void setbuf(FILE* _Nonnull __fp, char* _Nullable __buf);
+int setvbuf(FILE* _Nonnull __fp, char* _Nullable __buf, int __mode, size_t __size);
+int sscanf(const char* _Nonnull __s, const char* _Nonnull __fmt, ...) __scanflike(2, 3);
+int ungetc(int __ch, FILE* _Nonnull __fp);
+int vfprintf(FILE* _Nonnull __fp, const char* _Nonnull __fmt, va_list __args) __printflike(2, 0);
+int vprintf(const char* _Nonnull __fp, va_list __args) __printflike(1, 0);
-int dprintf(int __fd, const char* __fmt, ...) __printflike(2, 3) __INTRODUCED_IN(21);
-int vdprintf(int __fd, const char* __fmt, va_list __args) __printflike(2, 0) __INTRODUCED_IN(21);
+int dprintf(int __fd, const char* _Nonnull __fmt, ...) __printflike(2, 3) __INTRODUCED_IN(21);
+int vdprintf(int __fd, const char* _Nonnull __fmt, va_list __args) __printflike(2, 0) __INTRODUCED_IN(21);
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ < 201112L) || \
(defined(__cplusplus) && __cplusplus <= 201103L)
-char* gets(char* __buf) __attribute__((deprecated("gets is unsafe, use fgets instead")));
+char* _Nullable gets(char* _Nonnull __buf) __attribute__((deprecated("gets is unsafe, use fgets instead")));
#endif
-int sprintf(char* __s, const char* __fmt, ...)
+int sprintf(char* _Nonnull __s, const char* _Nonnull __fmt, ...)
__printflike(2, 3) __warnattr_strict("sprintf is often misused; please use snprintf");
-int vsprintf(char* __s, const char* __fmt, va_list __args)
+int vsprintf(char* _Nonnull __s, const char* _Nonnull __fmt, va_list __args)
__printflike(2, 0) __warnattr_strict("vsprintf is often misused; please use vsnprintf");
-char* tmpnam(char* __s)
+char* _Nullable tmpnam(char* _Nullable __s)
__warnattr("tmpnam is unsafe, use mkstemp or tmpfile instead");
#define P_tmpdir "/tmp/" /* deprecated */
-char* tempnam(const char* __dir, const char* __prefix)
+char* _Nullable tempnam(const char* _Nullable __dir, const char* _Nullable __prefix)
__warnattr("tempnam is unsafe, use mkstemp or tmpfile instead");
/**
@@ -159,7 +159,7 @@
*
* Returns 0 on success, and returns -1 and sets `errno` on failure.
*/
-int rename(const char* __old_path, const char* __new_path);
+int rename(const char* _Nonnull __old_path, const char* _Nonnull __new_path);
/**
* [renameat(2)](http://man7.org/linux/man-pages/man2/renameat.2.html) changes
@@ -167,7 +167,7 @@
*
* Returns 0 on success, and returns -1 and sets `errno` on failure.
*/
-int renameat(int __old_dir_fd, const char* __old_path, int __new_dir_fd, const char* __new_path);
+int renameat(int __old_dir_fd, const char* _Nonnull __old_path, int __new_dir_fd, const char* _Nonnull __new_path);
#if defined(__USE_GNU)
@@ -196,108 +196,111 @@
*
* Returns 0 on success, and returns -1 and sets `errno` on failure.
*/
-int renameat2(int __old_dir_fd, const char* __old_path, int __new_dir_fd, const char* __new_path, unsigned __flags) __INTRODUCED_IN(30);
+int renameat2(int __old_dir_fd, const char* _Nonnull __old_path, int __new_dir_fd, const char* _Nonnull __new_path, unsigned __flags) __INTRODUCED_IN(30);
#endif
-int fseek(FILE* __fp, long __offset, int __whence);
-long ftell(FILE* __fp);
+int fseek(FILE* _Nonnull __fp, long __offset, int __whence);
+long ftell(FILE* _Nonnull __fp);
/* See https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md */
#if defined(__USE_FILE_OFFSET64)
-int fgetpos(FILE* __fp, fpos_t* __pos) __RENAME(fgetpos64) __INTRODUCED_IN(24);
-int fsetpos(FILE* __fp, const fpos_t* __pos) __RENAME(fsetpos64) __INTRODUCED_IN(24);
-int fseeko(FILE* __fp, off_t __offset, int __whence) __RENAME(fseeko64) __INTRODUCED_IN(24);
-off_t ftello(FILE* __fp) __RENAME(ftello64) __INTRODUCED_IN(24);
+int fgetpos(FILE* _Nonnull __fp, fpos_t* _Nonnull __pos) __RENAME(fgetpos64) __INTRODUCED_IN(24);
+int fsetpos(FILE* _Nonnull __fp, const fpos_t* _Nonnull __pos) __RENAME(fsetpos64) __INTRODUCED_IN(24);
+int fseeko(FILE* _Nonnull __fp, off_t __offset, int __whence) __RENAME(fseeko64) __INTRODUCED_IN(24);
+off_t ftello(FILE* _Nonnull __fp) __RENAME(ftello64) __INTRODUCED_IN(24);
# if defined(__USE_BSD)
-FILE* funopen(const void* __cookie,
- int (*__read_fn)(void*, char*, int),
- int (*__write_fn)(void*, const char*, int),
- fpos_t (*__seek_fn)(void*, fpos_t, int),
- int (*__close_fn)(void*)) __RENAME(funopen64) __INTRODUCED_IN(24);
+/* If __read_fn and __write_fn are both nullptr, it will cause EINVAL */
+FILE* _Nullable funopen(const void* _Nullable __cookie,
+ int (* __BIONIC_COMPLICATED_NULLNESS __read_fn)(void* _Nonnull, char* _Nonnull, int),
+ int (* __BIONIC_COMPLICATED_NULLNESS __write_fn)(void* _Nonnull, const char* _Nonnull, int),
+ fpos_t (* _Nullable __seek_fn)(void* _Nonnull, fpos_t, int),
+ int (* _Nullable __close_fn)(void* _Nonnull)) __RENAME(funopen64) __INTRODUCED_IN(24);
# endif
#else
-int fgetpos(FILE* __fp, fpos_t* __pos);
-int fsetpos(FILE* __fp, const fpos_t* __pos);
-int fseeko(FILE* __fp, off_t __offset, int __whence);
-off_t ftello(FILE* __fp);
+int fgetpos(FILE* _Nonnull __fp, fpos_t* _Nonnull __pos);
+int fsetpos(FILE* _Nonnull __fp, const fpos_t* _Nonnull __pos);
+int fseeko(FILE* _Nonnull __fp, off_t __offset, int __whence);
+off_t ftello(FILE* _Nonnull __fp);
# if defined(__USE_BSD)
-FILE* funopen(const void* __cookie,
- int (*__read_fn)(void*, char*, int),
- int (*__write_fn)(void*, const char*, int),
- fpos_t (*__seek_fn)(void*, fpos_t, int),
- int (*__close_fn)(void*));
+/* If __read_fn and __write_fn are both nullptr, it will cause EINVAL */
+FILE* _Nullable funopen(const void* _Nullable __cookie,
+ int (* __BIONIC_COMPLICATED_NULLNESS __read_fn)(void* _Nonnull, char* _Nonnull, int),
+ int (* __BIONIC_COMPLICATED_NULLNESS __write_fn)(void* _Nonnull, const char* _Nonnull, int),
+ fpos_t (* _Nullable __seek_fn)(void* _Nonnull, fpos_t, int),
+ int (* _Nullable __close_fn)(void* _Nonnull));
# endif
#endif
-int fgetpos64(FILE* __fp, fpos64_t* __pos) __INTRODUCED_IN(24);
-int fsetpos64(FILE* __fp, const fpos64_t* __pos) __INTRODUCED_IN(24);
-int fseeko64(FILE* __fp, off64_t __offset, int __whence) __INTRODUCED_IN(24);
-off64_t ftello64(FILE* __fp) __INTRODUCED_IN(24);
+int fgetpos64(FILE* _Nonnull __fp, fpos64_t* _Nonnull __pos) __INTRODUCED_IN(24);
+int fsetpos64(FILE* _Nonnull __fp, const fpos64_t* _Nonnull __pos) __INTRODUCED_IN(24);
+int fseeko64(FILE* _Nonnull __fp, off64_t __offset, int __whence) __INTRODUCED_IN(24);
+off64_t ftello64(FILE* _Nonnull __fp) __INTRODUCED_IN(24);
#if defined(__USE_BSD)
-FILE* funopen64(const void* __cookie,
- int (*__read_fn)(void*, char*, int),
- int (*__write_fn)(void*, const char*, int),
- fpos64_t (*__seek_fn)(void*, fpos64_t, int),
- int (*__close_fn)(void*)) __INTRODUCED_IN(24);
+/* If __read_fn and __write_fn are both nullptr, it will cause EINVAL */
+FILE* _Nullable funopen64(const void* _Nullable __cookie,
+ int (* __BIONIC_COMPLICATED_NULLNESS __read_fn)(void* _Nonnull, char* _Nonnull, int),
+ int (* __BIONIC_COMPLICATED_NULLNESS __write_fn)(void* _Nonnull, const char* _Nonnull, int),
+ fpos64_t (* _Nullable __seek_fn)(void* _Nonnull, fpos64_t, int),
+ int (* _Nullable __close_fn)(void* _Nonnull)) __INTRODUCED_IN(24);
#endif
-FILE* fopen(const char* __path, const char* __mode);
-FILE* fopen64(const char* __path, const char* __mode) __INTRODUCED_IN(24);
-FILE* freopen(const char* __path, const char* __mode, FILE* __fp);
-FILE* freopen64(const char* __path, const char* __mode, FILE* __fp) __INTRODUCED_IN(24);
-FILE* tmpfile(void);
-FILE* tmpfile64(void) __INTRODUCED_IN(24);
+FILE* _Nullable fopen(const char* _Nonnull __path, const char* _Nonnull __mode);
+FILE* _Nullable fopen64(const char* _Nonnull __path, const char* _Nonnull __mode) __INTRODUCED_IN(24);
+FILE* _Nullable freopen(const char* _Nullable __path, const char* _Nonnull __mode, FILE* _Nonnull __fp);
+FILE* _Nullable freopen64(const char* _Nullable __path, const char* _Nonnull __mode, FILE* _Nonnull __fp) __INTRODUCED_IN(24);
+FILE* _Nullable tmpfile(void);
+FILE* _Nullable tmpfile64(void) __INTRODUCED_IN(24);
-int snprintf(char* __buf, size_t __size, const char* __fmt, ...) __printflike(3, 4);
-int vfscanf(FILE* __fp, const char* __fmt, va_list __args) __scanflike(2, 0);
-int vscanf(const char* __fmt , va_list __args) __scanflike(1, 0);
-int vsnprintf(char* __buf, size_t __size, const char* __fmt, va_list __args) __printflike(3, 0);
-int vsscanf(const char* __s, const char* __fmt, va_list __args) __scanflike(2, 0);
+int snprintf(char* _Nullable __buf, size_t __size, const char* _Nonnull __fmt, ...) __printflike(3, 4);
+int vfscanf(FILE* _Nonnull __fp, const char* _Nonnull __fmt, va_list __args) __scanflike(2, 0);
+int vscanf(const char* _Nonnull __fmt , va_list __args) __scanflike(1, 0);
+int vsnprintf(char* _Nullable __buf, size_t __size, const char* _Nonnull __fmt, va_list __args) __printflike(3, 0);
+int vsscanf(const char* _Nonnull __s, const char* _Nonnull __fmt, va_list __args) __scanflike(2, 0);
#define L_ctermid 1024 /* size for ctermid() */
-char* ctermid(char* __buf) __INTRODUCED_IN(26);
+char* _Nonnull ctermid(char* _Nullable __buf) __INTRODUCED_IN(26);
-FILE* fdopen(int __fd, const char* __mode);
-int fileno(FILE* __fp);
-int pclose(FILE* __fp);
-FILE* popen(const char* __command, const char* __mode);
-void flockfile(FILE* __fp);
-int ftrylockfile(FILE* __fp);
-void funlockfile(FILE* __fp);
-int getc_unlocked(FILE* __fp);
+FILE* _Nullable fdopen(int __fd, const char* _Nonnull __mode);
+int fileno(FILE* _Nonnull __fp);
+int pclose(FILE* _Nonnull __fp);
+FILE* _Nullable popen(const char* _Nonnull __command, const char* _Nonnull __mode);
+void flockfile(FILE* _Nonnull __fp);
+int ftrylockfile(FILE* _Nonnull __fp);
+void funlockfile(FILE* _Nonnull __fp);
+int getc_unlocked(FILE* _Nonnull __fp);
int getchar_unlocked(void);
-int putc_unlocked(int __ch, FILE* __fp);
+int putc_unlocked(int __ch, FILE* _Nonnull __fp);
int putchar_unlocked(int __ch);
-FILE* fmemopen(void* __buf, size_t __size, const char* __mode) __INTRODUCED_IN(23);
-FILE* open_memstream(char** __ptr, size_t* __size_ptr) __INTRODUCED_IN(23);
+FILE* _Nullable fmemopen(void* _Nullable __buf, size_t __size, const char* _Nonnull __mode) __INTRODUCED_IN(23);
+FILE* _Nullable open_memstream(char* _Nonnull * _Nonnull __ptr, size_t* _Nonnull __size_ptr) __INTRODUCED_IN(23);
#if defined(__USE_BSD) || defined(__BIONIC__) /* Historically bionic exposed these. */
-int asprintf(char** __s_ptr, const char* __fmt, ...) __printflike(2, 3);
-char* fgetln(FILE* __fp, size_t* __length_ptr);
-int fpurge(FILE* __fp);
-void setbuffer(FILE* __fp, char* __buf, int __size);
-int setlinebuf(FILE* __fp);
-int vasprintf(char** __s_ptr, const char* __fmt, va_list __args) __printflike(2, 0);
-void clearerr_unlocked(FILE* __fp) __INTRODUCED_IN(23);
-int feof_unlocked(FILE* __fp) __INTRODUCED_IN(23);
-int ferror_unlocked(FILE* __fp) __INTRODUCED_IN(23);
-int fileno_unlocked(FILE* __fp) __INTRODUCED_IN(24);
+int asprintf(char* _Nullable * _Nonnull __s_ptr, const char* _Nonnull __fmt, ...) __printflike(2, 3);
+char* _Nullable fgetln(FILE* _Nonnull __fp, size_t* _Nonnull __length_ptr);
+int fpurge(FILE* _Nonnull __fp);
+void setbuffer(FILE* _Nonnull __fp, char* _Nullable __buf, int __size);
+int setlinebuf(FILE* _Nonnull __fp);
+int vasprintf(char* _Nullable * _Nonnull __s_ptr, const char* _Nonnull __fmt, va_list __args) __printflike(2, 0);
+void clearerr_unlocked(FILE* _Nonnull __fp) __INTRODUCED_IN(23);
+int feof_unlocked(FILE* _Nonnull __fp) __INTRODUCED_IN(23);
+int ferror_unlocked(FILE* _Nonnull __fp) __INTRODUCED_IN(23);
+int fileno_unlocked(FILE* _Nonnull __fp) __INTRODUCED_IN(24);
#define fropen(cookie, fn) funopen(cookie, fn, 0, 0, 0)
#define fwopen(cookie, fn) funopen(cookie, 0, fn, 0, 0)
#endif
#if defined(__USE_BSD)
-int fflush_unlocked(FILE* __fp) __INTRODUCED_IN(28);
-int fgetc_unlocked(FILE* __fp) __INTRODUCED_IN(28);
-int fputc_unlocked(int __ch, FILE* __fp) __INTRODUCED_IN(28);
-size_t fread_unlocked(void* __buf, size_t __size, size_t __count, FILE* __fp) __INTRODUCED_IN(28);
-size_t fwrite_unlocked(const void* __buf, size_t __size, size_t __count, FILE* __fp) __INTRODUCED_IN(28);
+int fflush_unlocked(FILE* _Nullable __fp) __INTRODUCED_IN(28);
+int fgetc_unlocked(FILE* _Nonnull __fp) __INTRODUCED_IN(28);
+int fputc_unlocked(int __ch, FILE* _Nonnull __fp) __INTRODUCED_IN(28);
+size_t fread_unlocked(void* _Nonnull __buf, size_t __size, size_t __count, FILE* _Nonnull __fp) __INTRODUCED_IN(28);
+size_t fwrite_unlocked(const void* _Nonnull __buf, size_t __size, size_t __count, FILE* _Nonnull __fp) __INTRODUCED_IN(28);
#endif
#if defined(__USE_GNU)
-int fputs_unlocked(const char* __s, FILE* __fp) __INTRODUCED_IN(28);
-char* fgets_unlocked(char* __buf, int __size, FILE* __fp) __INTRODUCED_IN(28);
+int fputs_unlocked(const char* _Nonnull __s, FILE* _Nonnull __fp) __INTRODUCED_IN(28);
+char* _Nullable fgets_unlocked(char* _Nonnull __buf, int __size, FILE* _Nonnull __fp) __INTRODUCED_IN(28);
#endif
#if defined(__BIONIC_INCLUDE_FORTIFY_HEADERS)
diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h
index b416f62..2bcb870 100644
--- a/libc/include/stdlib.h
+++ b/libc/include/stdlib.h
@@ -91,7 +91,7 @@
void* _Nullable bsearch(const void* _Nonnull __key, const void* _Nullable __base, size_t __nmemb, size_t __size, int (* _Nonnull __comparator)(const void* _Nonnull __lhs, const void* _Nonnull __rhs));
-void qsort(void* _Nullable __base, size_t __nmemb, size_t __size, int (* _Nonnull __comparator)(const void* _Nonnull __lhs, const void* _Nonnull __rhs));
+void qsort(void* _Nullable __base, size_t __nmemb, size_t __size, int (* _Nonnull __comparator)(const void* _Nullable __lhs, const void* _Nullable __rhs));
uint32_t arc4random(void);
uint32_t arc4random_uniform(uint32_t __upper_bound);
diff --git a/libc/include/sys/pidfd.h b/libc/include/sys/pidfd.h
index 6d0e809..30455bb 100644
--- a/libc/include/sys/pidfd.h
+++ b/libc/include/sys/pidfd.h
@@ -71,6 +71,6 @@
*
* Available since API level 31.
*/
-int pidfd_send_signal(int __pidfd, int __sig, siginfo_t *__info, unsigned int __flags) __INTRODUCED_IN(31);
+int pidfd_send_signal(int __pidfd, int __sig, siginfo_t * _Nullable __info, unsigned int __flags) __INTRODUCED_IN(31);
__END_DECLS
diff --git a/libc/include/sys/signalfd.h b/libc/include/sys/signalfd.h
index bd911f7..f669cc8 100644
--- a/libc/include/sys/signalfd.h
+++ b/libc/include/sys/signalfd.h
@@ -48,11 +48,11 @@
*
* Available since API level 18.
*/
-int signalfd(int __fd, const sigset_t* __mask, int __flags) __INTRODUCED_IN(18);
+int signalfd(int __fd, const sigset_t* _Nonnull __mask, int __flags) __INTRODUCED_IN(18);
/**
* Like signalfd() but allows setting a signal mask with RT signals even from a 32-bit process.
*/
-int signalfd64(int __fd, const sigset64_t* __mask, int __flags) __INTRODUCED_IN(28);
+int signalfd64(int __fd, const sigset64_t* _Nonnull __mask, int __flags) __INTRODUCED_IN(28);
__END_DECLS
diff --git a/libc/include/sys/ucontext.h b/libc/include/sys/ucontext.h
index 8e5873d..bb6443b 100644
--- a/libc/include/sys/ucontext.h
+++ b/libc/include/sys/ucontext.h
@@ -316,6 +316,8 @@
#define NGREG 32
+#if defined(__USE_GNU)
+
#define REG_PC 0
#define REG_RA 1
#define REG_SP 2
@@ -323,6 +325,8 @@
#define REG_S0 8
#define REG_A0 10
+#endif // defined(__USE_GNU)
+
typedef unsigned long __riscv_mc_gp_state[NGREG];
typedef unsigned long greg_t;
@@ -362,9 +366,9 @@
/* This matches the kernel <asm/ucontext.h> but using mcontext_t. */
-typedef struct ucontext_t {
+typedef struct ucontext {
unsigned long uc_flags;
- struct ucontext_t* uc_link;
+ struct ucontext* uc_link;
stack_t uc_stack;
union {
sigset_t uc_sigmask;
diff --git a/libc/include/sys/utsname.h b/libc/include/sys/utsname.h
index 1fa3187..aa8c1a0 100644
--- a/libc/include/sys/utsname.h
+++ b/libc/include/sys/utsname.h
@@ -62,6 +62,6 @@
*
* Returns 0 on success, and returns -1 and sets `errno` on failure.
*/
-int uname(struct utsname* __buf);
+int uname(struct utsname* _Nonnull __buf);
__END_DECLS
diff --git a/libc/include/threads.h b/libc/include/threads.h
index 1b00b8f..b1008de 100644
--- a/libc/include/threads.h
+++ b/libc/include/threads.h
@@ -51,9 +51,9 @@
typedef pthread_mutex_t mtx_t;
/** The type for a thread-specific storage destructor. */
-typedef void (*tss_dtor_t)(void*);
+typedef void (*tss_dtor_t)(void* _Nullable);
/** The type of the function passed to thrd_create() to create a new thread. */
-typedef int (*thrd_start_t)(void*);
+typedef int (*thrd_start_t)(void* _Nullable);
/** The type used by call_once(). */
typedef pthread_once_t once_flag;
@@ -82,72 +82,72 @@
// This file is implemented as static inlines before API level 30.
/** Uses `__flag` to ensure that `__function` is called exactly once. */
-void call_once(once_flag* __flag, void (*__function)(void)) __INTRODUCED_IN(30);
+void call_once(once_flag* _Nonnull __flag, void (* _Nonnull __function)(void)) __INTRODUCED_IN(30);
/**
* Unblocks all threads blocked on `__cond`.
*/
-int cnd_broadcast(cnd_t* __cond) __INTRODUCED_IN(30);
+int cnd_broadcast(cnd_t* _Nonnull __cond) __INTRODUCED_IN(30);
/**
* Destroys a condition variable.
*/
-void cnd_destroy(cnd_t* __cond) __INTRODUCED_IN(30);
+void cnd_destroy(cnd_t* _Nonnull __cond) __INTRODUCED_IN(30);
/**
* Creates a condition variable.
*/
-int cnd_init(cnd_t* __cond) __INTRODUCED_IN(30);
+int cnd_init(cnd_t* _Nonnull __cond) __INTRODUCED_IN(30);
/**
* Unblocks one thread blocked on `__cond`.
*/
-int cnd_signal(cnd_t* __cond) __INTRODUCED_IN(30);
+int cnd_signal(cnd_t* _Nonnull __cond) __INTRODUCED_IN(30);
/**
* Unlocks `__mutex` and blocks until `__cond` is signaled or `__timeout` occurs.
*/
-int cnd_timedwait(cnd_t* __cond, mtx_t* __mutex, const struct timespec* __timeout)
+int cnd_timedwait(cnd_t* _Nonnull __cond, mtx_t* _Nonnull __mutex, const struct timespec* _Nonnull __timeout)
__INTRODUCED_IN(30);
/**
* Unlocks `__mutex` and blocks until `__cond` is signaled.
*/
-int cnd_wait(cnd_t* __cond, mtx_t* __mutex) __INTRODUCED_IN(30);
+int cnd_wait(cnd_t* _Nonnull __cond, mtx_t* _Nonnull __mutex) __INTRODUCED_IN(30);
/**
* Destroys a mutex.
*/
-void mtx_destroy(mtx_t* __mutex) __INTRODUCED_IN(30);
+void mtx_destroy(mtx_t* _Nonnull __mutex) __INTRODUCED_IN(30);
/**
* Creates a mutex.
*/
-int mtx_init(mtx_t* __mutex, int __type) __INTRODUCED_IN(30);
+int mtx_init(mtx_t* _Nonnull __mutex, int __type) __INTRODUCED_IN(30);
/**
* Blocks until `__mutex` is acquired.
*/
-int mtx_lock(mtx_t* __mutex) __INTRODUCED_IN(30);
+int mtx_lock(mtx_t* _Nonnull __mutex) __INTRODUCED_IN(30);
/**
* Blocks until `__mutex` is acquired or `__timeout` expires.
*/
-int mtx_timedlock(mtx_t* __mutex, const struct timespec* __timeout) __INTRODUCED_IN(30);
+int mtx_timedlock(mtx_t* _Nonnull __mutex, const struct timespec* _Nonnull __timeout) __INTRODUCED_IN(30);
/**
* Acquires `__mutex` or returns `thrd_busy`.
*/
-int mtx_trylock(mtx_t* __mutex) __INTRODUCED_IN(30);
+int mtx_trylock(mtx_t* _Nonnull __mutex) __INTRODUCED_IN(30);
/**
* Unlocks `__mutex`.
*/
-int mtx_unlock(mtx_t* __mutex) __INTRODUCED_IN(30);
+int mtx_unlock(mtx_t* _Nonnull __mutex) __INTRODUCED_IN(30);
@@ -155,7 +155,7 @@
* Creates a new thread running `__function(__arg)`, and sets `*__thrd` to
* the new thread.
*/
-int thrd_create(thrd_t* __thrd, thrd_start_t __function, void* __arg) __INTRODUCED_IN(30);
+int thrd_create(thrd_t* _Nonnull __thrd, thrd_start_t _Nonnull __function, void* _Nullable __arg) __INTRODUCED_IN(30);
/**
* Returns the `thrd_t` corresponding to the caller.
@@ -181,7 +181,7 @@
* Blocks until `__thrd` terminates. If `__result` is not null, `*__result`
* is set to the exiting thread's result.
*/
-int thrd_join(thrd_t __thrd, int* __result) __INTRODUCED_IN(30);
+int thrd_join(thrd_t __thrd, int* _Nullable __result) __INTRODUCED_IN(30);
/**
* Blocks the caller for at least `__duration` unless a signal is delivered.
@@ -190,7 +190,7 @@
*
* Returns 0 on success, or -1 if a signal was delivered.
*/
-int thrd_sleep(const struct timespec* __duration, struct timespec* __remaining) __INTRODUCED_IN(30);
+int thrd_sleep(const struct timespec* _Nonnull __duration, struct timespec* _Nullable __remaining) __INTRODUCED_IN(30);
/**
* Request that other threads should be scheduled.
@@ -203,7 +203,7 @@
* Creates a thread-specific storage key with the associated destructor (which
* may be null).
*/
-int tss_create(tss_t* __key, tss_dtor_t __dtor) __INTRODUCED_IN(30);
+int tss_create(tss_t* _Nonnull __key, tss_dtor_t _Nullable __dtor) __INTRODUCED_IN(30);
/**
* Destroys a thread-specific storage key.
@@ -214,13 +214,13 @@
* Returns the value for the current thread held in the thread-specific storage
* identified by `__key`.
*/
-void* tss_get(tss_t __key) __INTRODUCED_IN(30);
+void* _Nullable tss_get(tss_t __key) __INTRODUCED_IN(30);
/**
* Sets the current thread's value for the thread-specific storage identified
* by `__key` to `__value`.
*/
-int tss_set(tss_t __key, void* __value) __INTRODUCED_IN(30);
+int tss_set(tss_t __key, void* _Nonnull __value) __INTRODUCED_IN(30);
#endif
diff --git a/libc/kernel/tools/defaults.py b/libc/kernel/tools/defaults.py
index d0fe157..c9c0a22 100644
--- a/libc/kernel/tools/defaults.py
+++ b/libc/kernel/tools/defaults.py
@@ -48,6 +48,7 @@
"in_addr": False,
"ip_mreq_source": False,
"ip_msfilter": False,
+ "timespec": False,
}
# define to true if you want to remove all defined(CONFIG_FOO) tests
diff --git a/libc/kernel/uapi/linux/time.h b/libc/kernel/uapi/linux/time.h
index df52295..55d0e6e 100644
--- a/libc/kernel/uapi/linux/time.h
+++ b/libc/kernel/uapi/linux/time.h
@@ -18,14 +18,11 @@
****************************************************************************/
#ifndef _UAPI_LINUX_TIME_H
#define _UAPI_LINUX_TIME_H
+#include <bits/timespec.h>
#include <linux/types.h>
#include <linux/time_types.h>
#ifndef _STRUCT_TIMESPEC
#define _STRUCT_TIMESPEC
-struct timespec {
- __kernel_old_time_t tv_sec;
- long tv_nsec;
-};
#endif
struct timeval {
__kernel_old_time_t tv_sec;
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index 7b0f599..b06ec9e 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -496,7 +496,7 @@
g_dispatch->free(info);
// Purge the memory that was freed since a significant amount of
// memory could have been allocated and freed.
- g_dispatch->mallopt(M_PURGE, 0);
+ g_dispatch->mallopt(M_PURGE_ALL, 0);
}
size_t debug_malloc_usable_size(void* pointer) {
@@ -1123,7 +1123,7 @@
// Purge the memory that was allocated and freed during this operation
// since it can be large enough to expand the RSS significantly.
- g_dispatch->mallopt(M_PURGE, 0);
+ g_dispatch->mallopt(M_PURGE_ALL, 0);
}
bool debug_write_malloc_leak_info(FILE* fp) {
diff --git a/libc/private/bionic_constants.h b/libc/private/bionic_constants.h
index 09294b6..d7f4474 100644
--- a/libc/private/bionic_constants.h
+++ b/libc/private/bionic_constants.h
@@ -14,18 +14,18 @@
* limitations under the License.
*/
-#ifndef _BIONIC_CONSTANTS_H_
-#define _BIONIC_CONSTANTS_H_
+#pragma once
#define NS_PER_S 1000000000
-// Size of the shadow call stack. This must be a power of 2.
+// Size of the shadow call stack. This can be small because these stacks only
+// contain return addresses. This must be a power of 2 so the mask trick works.
+// See the SCS commentary in pthread_internal.h for more detail.
#define SCS_SIZE (8 * 1024)
+#define SCS_MASK (SCS_SIZE - 1)
// The shadow call stack is allocated at an aligned address within a guard region of this size. The
// guard region must be large enough that we can allocate an SCS_SIZE-aligned SCS while ensuring
// that there is at least one guard page after the SCS so that a stack overflow results in a SIGSEGV
// instead of corrupting the allocation that comes after it.
#define SCS_GUARD_REGION_SIZE (16 * 1024 * 1024)
-
-#endif // _BIONIC_CONSTANTS_H_
diff --git a/libc/tools/gensyscalls.py b/libc/tools/gensyscalls.py
index a525a98..558b004 100755
--- a/libc/tools/gensyscalls.py
+++ b/libc/tools/gensyscalls.py
@@ -93,7 +93,7 @@
ret
1:
neg a0, a0
- j __set_errno_internal
+ tail __set_errno_internal
END(%(func)s)
"""
diff --git a/libc/tzcode/strptime.c b/libc/tzcode/strptime.c
index fe9e10f..d31a501 100644
--- a/libc/tzcode/strptime.c
+++ b/libc/tzcode/strptime.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: strptime.c,v 1.30 2019/05/12 12:49:52 schwarze Exp $ */
+/* $OpenBSD: strptime.c,v 1.31 2023/03/02 16:21:51 millert Exp $ */
/* $NetBSD: strptime.c,v 1.12 1998/01/20 21:39:40 mycroft Exp $ */
/*-
* Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.
@@ -29,8 +29,10 @@
*/
#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
#include <locale.h>
-#include <stdint.h>
+#include <stdlib.h>
#include <string.h>
#include <time.h>
@@ -43,6 +45,8 @@
// Android: this code is not pointer-sign clean.
#pragma clang diagnostic ignored "-Wpointer-sign"
#pragma clang diagnostic ignored "-Wunused-function"
+// Android: clang thinks people don't know && has higher precedence than ||.
+#pragma clang diagnostic ignored "-Wlogical-op-parentheses"
#define _ctloc(x) (_CurrentTimeLocale->x)
@@ -78,8 +82,8 @@
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
-static int _conv_num64(const unsigned char **, int64_t *, int64_t, int64_t);
static int _conv_num(const unsigned char **, int *, int, int);
+static int epoch_to_tm(const unsigned char **, struct tm *);
static int leaps_thru_end_of(const int y);
static char *_strptime(const char *, const char *, struct tm *, int);
static const u_char *_find_string(const u_char *, int *, const char * const *,
@@ -351,27 +355,10 @@
if (!(_conv_num(&bp, &tm->tm_sec, 0, 60)))
return (NULL);
break;
- case 's': /* Seconds since epoch */
- {
- // Android change based on FreeBSD's implementation.
- int saved_errno = errno;
- errno = 0;
- const unsigned char* old_bp = bp;
- long n = strtol((const char*) bp, (char**) &bp, 10);
- errno = saved_errno;
- time_t t = n;
- if (bp == old_bp || errno == ERANGE ||
- ((long) t) != n) return NULL;
-
- if (localtime_r(&t, tm) == NULL) return NULL;
-
- //int64_t i64;
- //if (!(_conv_num64(&bp, &i64, 0, INT64_MAX)))
- // return (NULL);
- //if (!gmtime_r(&i64, tm))
- // return (NULL);
- fields = 0xffff; /* everything */
- }
+ case 's': /* Seconds since epoch. */
+ if (!(epoch_to_tm(&bp, tm)))
+ return (NULL);
+ fields = 0xffff; /* everything */
break;
case 'U': /* The week of year, beginning on sunday. */
case 'W': /* The week of year, beginning on monday. */
@@ -635,26 +622,27 @@
}
static int
-_conv_num64(const unsigned char **buf, int64_t *dest, int64_t llim, int64_t ulim)
+epoch_to_tm(const unsigned char **buf, struct tm *tm)
{
- int result = 0;
- int64_t rulim = ulim;
+ int saved_errno = errno;
+ int ret = 0;
+ time_t secs;
+ char *ep;
- if (**buf < '0' || **buf > '9')
- return (0);
-
- /* we use rulim to break out of the loop when we run out of digits */
- do {
- result *= 10;
- result += *(*buf)++ - '0';
- rulim /= 10;
- } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');
-
- if (result < llim || result > ulim)
- return (0);
-
- *dest = result;
- return (1);
+ errno = 0;
+ secs = strtoll(*buf, &ep, 10);
+ if (*buf == (unsigned char *)ep)
+ goto done;
+ if (secs < 0 ||
+ secs == LLONG_MAX && errno == ERANGE)
+ goto done;
+ if (localtime_r(&secs, tm) == NULL)
+ goto done;
+ ret = 1;
+done:
+ *buf = ep;
+ errno = saved_errno;
+ return (ret);
}
static const u_char *
diff --git a/libc/upstream-openbsd/lib/libc/gdtoa/gdtoaimp.h b/libc/upstream-openbsd/lib/libc/gdtoa/gdtoaimp.h
index 823f2a9..f853045 100644
--- a/libc/upstream-openbsd/lib/libc/gdtoa/gdtoaimp.h
+++ b/libc/upstream-openbsd/lib/libc/gdtoa/gdtoaimp.h
@@ -26,7 +26,7 @@
****************************************************************/
-/* This is a variation on dtoa.c that converts arbitary binary
+/* This is a variation on dtoa.c that converts arbitrary binary
floating-point formats to and from decimal notation. It uses
double-precision arithmetic internally, so there are still
various #ifdefs that adapt the calculations to the native
diff --git a/libc/upstream-openbsd/lib/libc/stdio/setvbuf.c b/libc/upstream-openbsd/lib/libc/stdio/setvbuf.c
index 9a08d13..74a1695 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/setvbuf.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/setvbuf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: setvbuf.c,v 1.14 2016/09/21 04:38:56 guenther Exp $ */
+/* $OpenBSD: setvbuf.c,v 1.15 2022/09/28 16:44:14 gnezdo Exp $ */
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
@@ -31,6 +31,7 @@
* SUCH DAMAGE.
*/
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include "local.h"
@@ -52,7 +53,7 @@
* when setting _IONBF.
*/
if (mode != _IONBF)
- if ((mode != _IOFBF && mode != _IOLBF) || (int)size < 0)
+ if ((mode != _IOFBF && mode != _IOLBF) || size > INT_MAX)
return (EOF);
/*
diff --git a/libc/upstream-openbsd/lib/libc/stdlib/div.c b/libc/upstream-openbsd/lib/libc/stdlib/div.c
index beaa428..5e6164f 100644
--- a/libc/upstream-openbsd/lib/libc/stdlib/div.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/div.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: div.c,v 1.6 2015/09/13 08:31:47 guenther Exp $ */
+/* $OpenBSD: div.c,v 1.7 2022/12/27 17:10:06 jmc Exp $ */
/*
* Copyright (c) 1990 Regents of the University of California.
* All rights reserved.
@@ -46,7 +46,7 @@
* words, we should always truncate the quotient towards
* 0, never -infinity.
*
- * Machine division and remainer may work either way when
+ * Machine division and remainder may work either way when
* one or both of n or d is negative. If only one is
* negative and r.quot has been truncated towards -inf,
* r.rem will have the same sign as denom and the opposite
diff --git a/libc/upstream-openbsd/lib/libc/stdlib/setenv.c b/libc/upstream-openbsd/lib/libc/stdlib/setenv.c
index 15c550b..fc8e5b6 100644
--- a/libc/upstream-openbsd/lib/libc/stdlib/setenv.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/setenv.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: setenv.c,v 1.19 2016/09/21 04:38:56 guenther Exp $ */
+/* $OpenBSD: setenv.c,v 1.20 2022/08/08 22:40:03 millert Exp $ */
/*
* Copyright (c) 1987 Regents of the University of California.
* All rights reserved.
@@ -48,9 +48,10 @@
for (cp = str; *cp && *cp != '='; ++cp)
;
- if (*cp != '=') {
+ if (cp == str || *cp != '=') {
+ /* '=' is the first character of string or is missing. */
errno = EINVAL;
- return (-1); /* missing `=' in string */
+ return (-1);
}
if (__findenv(str, (int)(cp - str), &offset) != NULL) {
diff --git a/libm/Android.bp b/libm/Android.bp
index cc0d666..4c34fb6 100644
--- a/libm/Android.bp
+++ b/libm/Android.bp
@@ -94,8 +94,6 @@
"upstream-freebsd/lib/msun/src/s_cbrtf.c",
"upstream-freebsd/lib/msun/src/s_ccosh.c",
"upstream-freebsd/lib/msun/src/s_ccoshf.c",
- "upstream-freebsd/lib/msun/src/s_ceil.c",
- "upstream-freebsd/lib/msun/src/s_ceilf.c",
"upstream-freebsd/lib/msun/src/s_cexp.c",
"upstream-freebsd/lib/msun/src/s_cexpf.c",
"upstream-freebsd/lib/msun/src/s_cimag.c",
@@ -130,8 +128,6 @@
"upstream-freebsd/lib/msun/src/s_fdim.c",
"upstream-freebsd/lib/msun/src/s_finite.c",
"upstream-freebsd/lib/msun/src/s_finitef.c",
- "upstream-freebsd/lib/msun/src/s_floor.c",
- "upstream-freebsd/lib/msun/src/s_floorf.c",
"upstream-freebsd/lib/msun/src/s_fma.c",
"upstream-freebsd/lib/msun/src/s_fmaf.c",
"upstream-freebsd/lib/msun/src/s_fmax.c",
@@ -282,10 +278,8 @@
arm: {
srcs: [
"arm/fenv.c",
- ],
- exclude_srcs: [
- "upstream-freebsd/lib/msun/src/s_floor.c",
- "upstream-freebsd/lib/msun/src/s_floorf.c",
+ "upstream-freebsd/lib/msun/src/s_ceil.c",
+ "upstream-freebsd/lib/msun/src/s_ceilf.c",
],
instruction_set: "arm",
pack_relocations: false,
@@ -303,10 +297,6 @@
"arm64/fenv.c",
],
exclude_srcs: [
- "upstream-freebsd/lib/msun/src/s_ceil.c",
- "upstream-freebsd/lib/msun/src/s_ceilf.c",
- "upstream-freebsd/lib/msun/src/s_floor.c",
- "upstream-freebsd/lib/msun/src/s_floorf.c",
"upstream-freebsd/lib/msun/src/s_fma.c",
"upstream-freebsd/lib/msun/src/s_fmaf.c",
"upstream-freebsd/lib/msun/src/s_fmax.c",
@@ -337,11 +327,6 @@
],
exclude_srcs: [
- // TODO: do the rest when our clang has https://reviews.llvm.org/D136508.
- // TODO: "upstream-freebsd/lib/msun/src/s_ceil.c",
- // TODO: "upstream-freebsd/lib/msun/src/s_ceilf.c",
- // TODO: "upstream-freebsd/lib/msun/src/s_floor.c",
- // TODO: "upstream-freebsd/lib/msun/src/s_floorf.c",
"upstream-freebsd/lib/msun/src/s_fma.c",
"upstream-freebsd/lib/msun/src/s_fmaf.c",
"upstream-freebsd/lib/msun/src/s_fmax.c",
@@ -356,12 +341,12 @@
"upstream-freebsd/lib/msun/src/s_lrintf.c",
"upstream-freebsd/lib/msun/src/s_lround.c",
"upstream-freebsd/lib/msun/src/s_lroundf.c",
- // TODO: "upstream-freebsd/lib/msun/src/s_rint.c",
- // TODO: "upstream-freebsd/lib/msun/src/s_rintf.c",
- // TODO: "upstream-freebsd/lib/msun/src/s_round.c",
- // TODO: "upstream-freebsd/lib/msun/src/s_roundf.c",
- // TODO: "upstream-freebsd/lib/msun/src/s_trunc.c",
- // TODO: "upstream-freebsd/lib/msun/src/s_truncf.c",
+ "upstream-freebsd/lib/msun/src/s_rint.c",
+ "upstream-freebsd/lib/msun/src/s_rintf.c",
+ "upstream-freebsd/lib/msun/src/s_round.c",
+ "upstream-freebsd/lib/msun/src/s_roundf.c",
+ "upstream-freebsd/lib/msun/src/s_trunc.c",
+ "upstream-freebsd/lib/msun/src/s_truncf.c",
],
version_script: ":libm.riscv64.map",
},
@@ -373,10 +358,6 @@
"x86/lrintf.S",
],
exclude_srcs: [
- "upstream-freebsd/lib/msun/src/s_ceil.c",
- "upstream-freebsd/lib/msun/src/s_ceilf.c",
- "upstream-freebsd/lib/msun/src/s_floor.c",
- "upstream-freebsd/lib/msun/src/s_floorf.c",
"upstream-freebsd/lib/msun/src/s_lrint.c",
"upstream-freebsd/lib/msun/src/s_lrintf.c",
"upstream-freebsd/lib/msun/src/s_rint.c",
@@ -400,10 +381,6 @@
"x86_64/lrintf.S",
],
exclude_srcs: [
- "upstream-freebsd/lib/msun/src/s_ceil.c",
- "upstream-freebsd/lib/msun/src/s_ceilf.c",
- "upstream-freebsd/lib/msun/src/s_floor.c",
- "upstream-freebsd/lib/msun/src/s_floorf.c",
"upstream-freebsd/lib/msun/src/s_llrint.c",
"upstream-freebsd/lib/msun/src/s_llrintf.c",
"upstream-freebsd/lib/msun/src/s_lrint.c",
diff --git a/libm/builtins.cpp b/libm/builtins.cpp
index 96c006d..41e145b 100644
--- a/libm/builtins.cpp
+++ b/libm/builtins.cpp
@@ -22,7 +22,7 @@
float fabsf(float x) { return __builtin_fabsf(x); }
long double fabsl(long double x) { return __builtin_fabsl(x); }
-#if defined(__aarch64__) || defined(__i386__) || defined(__x86_64__)
+#if defined(__aarch64__) || defined(__riscv) || defined(__i386__) || defined(__x86_64__)
float ceilf(float x) { return __builtin_ceilf(x); }
double ceil(double x) { return __builtin_ceil(x); }
#if defined(__ILP32__)
@@ -46,7 +46,7 @@
}
float floorf(float x) { return s_floorf::floorf(x); }
double floor(double x) { return s_floor::floor(x); }
-#elif defined(__arm__) || defined(__aarch64__) || defined(__i386__) || defined(__x86_64__)
+#else
float floorf(float x) { return __builtin_floorf(x); }
double floor(double x) { return __builtin_floor(x); }
#if defined(__ILP32__)
@@ -79,7 +79,7 @@
long long llroundf(float x) { return __builtin_llroundf(x); }
#endif
-#if defined(__aarch64__) || defined(__i386__) || defined(__x86_64__)
+#if defined(__aarch64__) || defined(__riscv) || defined(__i386__) || defined(__x86_64__)
float rintf(float x) { return __builtin_rintf(x); }
double rint(double x) { return __builtin_rint(x); }
#if defined(__ILP32__)
@@ -87,7 +87,7 @@
#endif
#endif
-#if defined(__aarch64__)
+#if defined(__aarch64__) || defined(__riscv)
float roundf(float x) { return __builtin_roundf(x); }
double round(double x) { return __builtin_round(x); }
#endif
@@ -98,7 +98,7 @@
__weak_reference(sqrt, sqrtl);
#endif
-#if defined(__aarch64__) || defined(__i386__) || defined(__x86_64__)
+#if defined(__aarch64__) || defined(__riscv) || defined(__i386__) || defined(__x86_64__)
float truncf(float x) { return __builtin_truncf(x); }
double trunc(double x) { return __builtin_trunc(x); }
#if defined(__ILP32__)
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 6246f8c..c5a822a 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -3142,6 +3142,14 @@
case DT_AARCH64_VARIANT_PCS:
// Ignored: AArch64 processor-specific dynamic array tags.
break;
+ // TODO(mitchp): Add support to libc_init_mte to use these dynamic array entries instead of
+ // the Android-specific ELF note.
+ case DT_AARCH64_MEMTAG_MODE:
+ case DT_AARCH64_MEMTAG_HEAP:
+ case DT_AARCH64_MEMTAG_STACK:
+ case DT_AARCH64_MEMTAG_GLOBALS:
+ case DT_AARCH64_MEMTAG_GLOBALSSZ:
+ break;
#endif
default:
diff --git a/tests/Android.bp b/tests/Android.bp
index 8c6057f..6d2a8d4 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -66,18 +66,20 @@
"libcutils_headers",
"gwp_asan_headers"
],
- // Ensure that the tests exercise shadow call stack support and
- // the hint space PAC/BTI instructions.
+ stl: "libc++",
+
+ // Ensure that the tests exercise shadow call stack support.
+ // We don't use `scs: true` here because that would give us a second
+ // variant of this library where we actually just want to say "this
+ // library should always be built this way".
arch: {
arm64: {
- cflags: [
- "-fsanitize=shadow-call-stack",
- // Disable this option for now: see b/151372823
- //"-mbranch-protection=standard",
- ],
+ cflags: ["-fsanitize=shadow-call-stack"],
+ },
+ riscv64: {
+ cflags: ["-fsanitize=shadow-call-stack"],
},
},
- stl: "libc++",
sanitize: {
address: false,
},
diff --git a/tests/async_safe_test.cpp b/tests/async_safe_test.cpp
index f52387e..dc4db07 100644
--- a/tests/async_safe_test.cpp
+++ b/tests/async_safe_test.cpp
@@ -16,6 +16,8 @@
#include <gtest/gtest.h>
+#include <errno.h>
+
#if defined(__BIONIC__)
#include <async_safe/log.h>
#endif // __BIONIC__
@@ -227,3 +229,19 @@
GTEST_SKIP() << "bionic-only test";
#endif // __BIONIC__
}
+
+// Verify that using %m is never cut off.
+TEST(async_safe_format_buffer, percent_m_fits_in_buffer) {
+#if defined(__BIONIC__)
+ for (int i = 0; i < 256; i++) {
+ errno = i;
+ char async_buf[256];
+ async_safe_format_buffer(async_buf, sizeof(async_buf), "%m");
+ char strerror_buf[1024];
+ strerror_r(errno, strerror_buf, sizeof(strerror_buf));
+ ASSERT_STREQ(strerror_buf, async_buf);
+ }
+#else // __BIONIC__
+ GTEST_SKIP() << "bionic-only test";
+#endif // __BIONIC__
+}
diff --git a/tests/gwp_asan_test.cpp b/tests/gwp_asan_test.cpp
index 8b12bec..c31f48c 100644
--- a/tests/gwp_asan_test.cpp
+++ b/tests/gwp_asan_test.cpp
@@ -143,6 +143,16 @@
EXPECT_DEATH({ *x = 7; }, "");
}
+// A weaker version of the above tests, only checking that GWP-ASan is enabled
+// for any pointer, not *our* pointer. This allows us to test the system_default
+// sysprops without potentially OOM-ing other random processes:
+// b/273904016#comment5
+TEST(gwp_asan_integration, DISABLED_assert_gwp_asan_enabled_weaker) {
+ std::string maps;
+ EXPECT_TRUE(android::base::ReadFileToString("/proc/self/maps", &maps));
+ EXPECT_TRUE(maps.find("GWP-ASan") != std::string::npos) << maps;
+}
+
TEST(gwp_asan_integration, DISABLED_assert_gwp_asan_disabled) {
std::string maps;
EXPECT_TRUE(android::base::ReadFileToString("/proc/self/maps", &maps));
@@ -184,32 +194,6 @@
RunSubtestNoEnv("gwp_asan_integration.DISABLED_assert_gwp_asan_enabled");
}
-TEST(gwp_asan_integration, sysprops_system) {
- // Do not override HWASan with GWP ASan.
- SKIP_WITH_HWASAN;
-
- SyspropRestorer restorer;
-
- __system_property_set("libc.debug.gwp_asan.sample_rate.system_default", "1");
- __system_property_set("libc.debug.gwp_asan.process_sampling.system_default", "1");
- __system_property_set("libc.debug.gwp_asan.max_allocs.system_default", "40000");
-
- RunSubtestNoEnv("gwp_asan_integration.DISABLED_assert_gwp_asan_enabled");
-}
-
-TEST(gwp_asan_integration, sysprops_persist_system) {
- // Do not override HWASan with GWP ASan.
- SKIP_WITH_HWASAN;
-
- SyspropRestorer restorer;
-
- __system_property_set("persist.libc.debug.gwp_asan.sample_rate.system_default", "1");
- __system_property_set("persist.libc.debug.gwp_asan.process_sampling.system_default", "1");
- __system_property_set("persist.libc.debug.gwp_asan.max_allocs.system_default", "40000");
-
- RunSubtestNoEnv("gwp_asan_integration.DISABLED_assert_gwp_asan_enabled");
-}
-
TEST(gwp_asan_integration, sysprops_non_persist_overrides_persist) {
// Do not override HWASan with GWP ASan.
SKIP_WITH_HWASAN;
@@ -218,13 +202,18 @@
__system_property_set("libc.debug.gwp_asan.sample_rate.system_default", "1");
__system_property_set("libc.debug.gwp_asan.process_sampling.system_default", "1");
- __system_property_set("libc.debug.gwp_asan.max_allocs.system_default", "40000");
+ // Note, any processes launched elsewhere on the system right now will have
+ // GWP-ASan enabled. Make sure that we only use a single slot, otherwise we
+ // could end up causing said badly-timed processes to use up to 163MiB extra
+ // penalty that 40,000 allocs would cause. See b/273904016#comment5 for more
+ // context.
+ __system_property_set("libc.debug.gwp_asan.max_allocs.system_default", "1");
__system_property_set("persist.libc.debug.gwp_asan.sample_rate.system_default", "0");
__system_property_set("persist.libc.debug.gwp_asan.process_sampling.system_default", "0");
__system_property_set("persist.libc.debug.gwp_asan.max_allocs.system_default", "0");
- RunSubtestNoEnv("gwp_asan_integration.DISABLED_assert_gwp_asan_enabled");
+ RunSubtestNoEnv("gwp_asan_integration.DISABLED_assert_gwp_asan_enabled_weaker");
}
TEST(gwp_asan_integration, sysprops_program_specific_overrides_default) {
diff --git a/tests/heap_tagging_level_test.cpp b/tests/heap_tagging_level_test.cpp
index ae678b7..917be37 100644
--- a/tests/heap_tagging_level_test.cpp
+++ b/tests/heap_tagging_level_test.cpp
@@ -26,6 +26,7 @@
#include "SignalUtils.h"
+#include <android-base/properties.h>
#include <android-base/test_utils.h>
#include <bionic/malloc_tagged_pointers.h>
@@ -223,6 +224,9 @@
TEST_P(MemtagNoteTest, SEGV) {
#if defined(__BIONIC__) && defined(__aarch64__)
SKIP_WITH_NATIVE_BRIDGE; // http://b/242170715
+ if (android::base::GetProperty("persist.arm64.memtag.default", "") != "") {
+ GTEST_SKIP() << "not supported when overriding memtag mode with property";
+ }
// Note that we do not check running_with_hwasan() - what matters here is whether the test binary
// itself is built with HWASan.
bool withHWASAN = __has_feature(hwaddress_sanitizer);
diff --git a/tests/locale_test.cpp b/tests/locale_test.cpp
index b4da6de..a220c83 100644
--- a/tests/locale_test.cpp
+++ b/tests/locale_test.cpp
@@ -79,9 +79,12 @@
}
TEST(locale, newlocale_NULL_locale_name) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnonnull"
errno = 0;
EXPECT_EQ(nullptr, newlocale(LC_ALL, nullptr, nullptr));
EXPECT_EQ(EINVAL, errno);
+#pragma clang diagnostic pop
}
TEST(locale, newlocale_bad_locale_name) {
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
index 63ad99d..4e7eb7b 100644
--- a/tests/malloc_test.cpp
+++ b/tests/malloc_test.cpp
@@ -36,7 +36,10 @@
#include <algorithm>
#include <atomic>
#include <functional>
+#include <string>
#include <thread>
+#include <unordered_map>
+#include <utility>
#include <vector>
#include <tinyxml2.h>
@@ -695,6 +698,44 @@
#endif
}
+TEST(malloc, mallopt_purge_all) {
+#if defined(__BIONIC__)
+ SKIP_WITH_HWASAN << "hwasan does not implement mallopt";
+ errno = 0;
+ ASSERT_EQ(1, mallopt(M_PURGE_ALL, 0));
+#else
+ GTEST_SKIP() << "bionic-only test";
+#endif
+}
+
+// Verify that all of the mallopt values are unique.
+TEST(malloc, mallopt_unique_params) {
+#if defined(__BIONIC__)
+ std::vector<std::pair<int, std::string>> params{
+ std::make_pair(M_DECAY_TIME, "M_DECAY_TIME"),
+ std::make_pair(M_PURGE, "M_PURGE"),
+ std::make_pair(M_PURGE_ALL, "M_PURGE_ALL"),
+ std::make_pair(M_MEMTAG_TUNING, "M_MEMTAG_TUNING"),
+ std::make_pair(M_THREAD_DISABLE_MEM_INIT, "M_THREAD_DISABLE_MEM_INIT"),
+ std::make_pair(M_CACHE_COUNT_MAX, "M_CACHE_COUNT_MAX"),
+ std::make_pair(M_CACHE_SIZE_MAX, "M_CACHE_SIZE_MAX"),
+ std::make_pair(M_TSDS_COUNT_MAX, "M_TSDS_COUNT_MAX"),
+ std::make_pair(M_BIONIC_ZERO_INIT, "M_BIONIC_ZERO_INIT"),
+ std::make_pair(M_BIONIC_SET_HEAP_TAGGING_LEVEL, "M_BIONIC_SET_HEAP_TAGGING_LEVEL"),
+ };
+
+ std::unordered_map<int, std::string> all_params;
+ for (const auto& param : params) {
+ EXPECT_TRUE(all_params.count(param.first) == 0)
+ << "mallopt params " << all_params[param.first] << " and " << param.second
+ << " have the same value " << param.first;
+ all_params.insert(param);
+ }
+#else
+ GTEST_SKIP() << "bionic-only test";
+#endif
+}
+
#if defined(__BIONIC__)
static void GetAllocatorVersion(bool* allocator_scudo) {
TemporaryFile tf;
diff --git a/tests/sched_test.cpp b/tests/sched_test.cpp
index 03e8062..fa1a07f 100644
--- a/tests/sched_test.cpp
+++ b/tests/sched_test.cpp
@@ -303,5 +303,8 @@
}
TEST(sched, sched_getaffinity_failure) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnonnull"
ASSERT_EQ(-1, sched_getaffinity(getpid(), 0, nullptr));
+#pragma clang diagnostic pop
}
diff --git a/tests/scs_test.cpp b/tests/scs_test.cpp
index 24cb347..0776a43 100644
--- a/tests/scs_test.cpp
+++ b/tests/scs_test.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#if __has_feature(shadow_call_stack)
-
#include <gtest/gtest.h>
#include "private/bionic_constants.h"
@@ -33,7 +31,9 @@
}
TEST(scs_test, stack_overflow) {
+#if defined(__aarch64__) || defined(__riscv)
ASSERT_EXIT(recurse1(SCS_SIZE), testing::KilledBySignal(SIGSEGV), "");
-}
-
+#else
+ GTEST_SKIP() << "no SCS on this architecture";
#endif
+}
diff --git a/tests/setjmp_test.cpp b/tests/setjmp_test.cpp
index 2f891ec..6ae8bfd 100644
--- a/tests/setjmp_test.cpp
+++ b/tests/setjmp_test.cpp
@@ -278,7 +278,6 @@
}
TEST(setjmp, bug_152210274) {
- SKIP_WITH_HWASAN; // b/227390656
// Ensure that we never have a mangled value in the stack pointer.
#if defined(__BIONIC__)
struct sigaction sa = {.sa_flags = SA_SIGINFO, .sa_sigaction = [](int, siginfo_t*, void*) {}};
@@ -299,15 +298,19 @@
perror("setjmp");
abort();
}
- if (*static_cast<pid_t*>(arg) == 100) longjmp(buf, 1);
+ // This will never be true, but the compiler doesn't know that, so the
+ // setjmp won't be removed by DCE. With HWASan/MTE this also acts as a
+ // kind of enforcement that the threads are done before leaving the test.
+ if (*static_cast<size_t*>(arg) != 123) longjmp(buf, 1);
}
return nullptr;
};
+ pthread_t threads[kNumThreads];
pid_t tids[kNumThreads] = {};
+ size_t var = 123;
for (size_t i = 0; i < kNumThreads; ++i) {
- pthread_t t;
- ASSERT_EQ(0, pthread_create(&t, nullptr, jumper, &tids[i]));
- tids[i] = pthread_gettid_np(t);
+ ASSERT_EQ(0, pthread_create(&threads[i], nullptr, jumper, &var));
+ tids[i] = pthread_gettid_np(threads[i]);
}
// Start the interrupter thread.
@@ -327,6 +330,9 @@
pthread_t t;
ASSERT_EQ(0, pthread_create(&t, nullptr, interrupter, tids));
pthread_join(t, nullptr);
+ for (size_t i = 0; i < kNumThreads; i++) {
+ pthread_join(threads[i], nullptr);
+ }
#else
GTEST_SKIP() << "tests uses functions not in glibc";
#endif
diff --git a/tests/stack_protector_test_helper.cpp b/tests/stack_protector_test_helper.cpp
index eddd940..69b3c5d 100644
--- a/tests/stack_protector_test_helper.cpp
+++ b/tests/stack_protector_test_helper.cpp
@@ -15,12 +15,11 @@
*/
// Deliberately overwrite the stack canary.
-__attribute__((noinline)) void modify_stack_protector_test() {
+__attribute__((noinline, optnone)) void modify_stack_protector_test() {
// We can't use memset here because it's fortified, and we want to test
// the line of defense *after* that.
- // Without volatile, the generic x86/x86-64 targets don't write to the stack.
// We can't make a constant change, since the existing byte might already have
// had that value.
- volatile char* p = reinterpret_cast<volatile char*>(&p + 1);
+ char* p = reinterpret_cast<char*>(&p + 1);
*p = ~*p;
}
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index acc7ccd..fb6bce9 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -190,6 +190,8 @@
}
TEST(STDIO_TEST, getdelim_invalid) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnonnull"
FILE* fp = tmpfile();
ASSERT_TRUE(fp != nullptr);
@@ -206,6 +208,7 @@
ASSERT_EQ(getdelim(&buffer, nullptr, ' ', fp), -1);
ASSERT_EQ(EINVAL, errno);
fclose(fp);
+#pragma clang diagnostic pop
}
TEST(STDIO_TEST, getdelim_directory) {
@@ -260,6 +263,8 @@
}
TEST(STDIO_TEST, getline_invalid) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnonnull"
FILE* fp = tmpfile();
ASSERT_TRUE(fp != nullptr);
@@ -276,6 +281,7 @@
ASSERT_EQ(getline(&buffer, nullptr, fp), -1);
ASSERT_EQ(EINVAL, errno);
fclose(fp);
+#pragma clang diagnostic pop
}
TEST(STDIO_TEST, printf_ssize_t) {
@@ -1944,6 +1950,8 @@
TEST(STDIO_TEST, open_memstream_EINVAL) {
#if defined(__BIONIC__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnonnull"
char* p;
size_t size;
@@ -1956,6 +1964,7 @@
errno = 0;
ASSERT_EQ(nullptr, open_memstream(&p, nullptr));
ASSERT_EQ(EINVAL, errno);
+#pragma clang diagnostic pop
#else
GTEST_SKIP() << "glibc is broken";
#endif
@@ -2975,9 +2984,6 @@
}
TEST(STDIO_TEST, snprintf_b) {
- // Our clang doesn't know about %b/%B yet.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wformat-invalid-specifier"
char buf[BUFSIZ];
EXPECT_EQ(5, snprintf(buf, sizeof(buf), "<%b>", 5));
EXPECT_STREQ("<101>", buf);
@@ -2989,13 +2995,9 @@
EXPECT_STREQ("<0b10101010101010101010101010101010>", buf);
EXPECT_EQ(3, snprintf(buf, sizeof(buf), "<%#b>", 0));
EXPECT_STREQ("<0>", buf);
-#pragma clang diagnostic pop
}
TEST(STDIO_TEST, snprintf_B) {
- // Our clang doesn't know about %b/%B yet.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wformat-invalid-specifier"
char buf[BUFSIZ];
EXPECT_EQ(5, snprintf(buf, sizeof(buf), "<%B>", 5));
EXPECT_STREQ("<101>", buf);
@@ -3007,13 +3009,9 @@
EXPECT_STREQ("<0B10101010101010101010101010101010>", buf);
EXPECT_EQ(3, snprintf(buf, sizeof(buf), "<%#B>", 0));
EXPECT_STREQ("<0>", buf);
-#pragma clang diagnostic pop
}
TEST(STDIO_TEST, swprintf_b) {
- // Our clang doesn't know about %b/%B yet.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wformat-invalid-specifier"
wchar_t buf[BUFSIZ];
EXPECT_EQ(5, swprintf(buf, sizeof(buf), L"<%b>", 5));
EXPECT_EQ(std::wstring(L"<101>"), buf);
@@ -3025,13 +3023,9 @@
EXPECT_EQ(std::wstring(L"<0b10101010101010101010101010101010>"), buf);
EXPECT_EQ(3, swprintf(buf, sizeof(buf), L"<%#b>", 0));
EXPECT_EQ(std::wstring(L"<0>"), buf);
-#pragma clang diagnostic pop
}
TEST(STDIO_TEST, swprintf_B) {
- // Our clang doesn't know about %b/%B yet.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wformat-invalid-specifier"
wchar_t buf[BUFSIZ];
EXPECT_EQ(5, swprintf(buf, sizeof(buf), L"<%B>", 5));
EXPECT_EQ(std::wstring(L"<101>"), buf);
@@ -3043,7 +3037,6 @@
EXPECT_EQ(std::wstring(L"<0B10101010101010101010101010101010>"), buf);
EXPECT_EQ(3, swprintf(buf, sizeof(buf), L"<%#B>", 0));
EXPECT_EQ(std::wstring(L"<0>"), buf);
-#pragma clang diagnostic pop
}
TEST(STDIO_TEST, scanf_i_decimal) {
@@ -3143,10 +3136,6 @@
}
TEST(STDIO_TEST, scanf_b) {
- // Our clang doesn't know about %b yet.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wformat"
-#pragma clang diagnostic ignored "-Wformat-invalid-specifier"
int i;
char ch;
EXPECT_EQ(2, sscanf("<1012>", "<%b%c>", &i, &ch));
@@ -3159,14 +3148,9 @@
EXPECT_EQ(2, sscanf("-0b", "%i%c", &i, &ch));
EXPECT_EQ(0, i);
EXPECT_EQ('b', ch);
-#pragma clang diagnostic pop
}
TEST(STDIO_TEST, swscanf_b) {
- // Our clang doesn't know about %b yet.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wformat"
-#pragma clang diagnostic ignored "-Wformat-invalid-specifier"
int i;
char ch;
EXPECT_EQ(2, swscanf(L"<1012>", L"<%b%c>", &i, &ch));
@@ -3179,5 +3163,4 @@
EXPECT_EQ(2, swscanf(L"-0b", L"%i%c", &i, &ch));
EXPECT_EQ(0, i);
EXPECT_EQ('b', ch);
-#pragma clang diagnostic pop
}
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 2a36460..4c21627 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -589,9 +589,10 @@
TestGetTidCachingWithFork(CloneAndSetTid, exit);
}
+__attribute__((no_sanitize("hwaddress", "memtag")))
static int CloneStartRoutine(int (*start_routine)(void*)) {
void* child_stack[1024];
- return clone(start_routine, untag_address(&child_stack[1024]), SIGCHLD, nullptr);
+ return clone(start_routine, &child_stack[1024], SIGCHLD, nullptr);
}
static int GetPidCachingCloneStartRoutine(void*) {