Merge "Move some syscalls in commmon whitelist to app"
diff --git a/docs/status.md b/docs/status.md
index 2666e58..a0e6824 100644
--- a/docs/status.md
+++ b/docs/status.md
@@ -53,8 +53,11 @@
* <spawn.h>
* `swab`
* `syncfs`
+
+New libc behavior in P:
* `%C` and `%S` support in the printf family (previously only the wprintf family supported these)
* `%mc`/`%ms`/`%m[` support in the scanf family
+ * `%s` support in strptime (strftime already supported it)
New libc functions in O:
* `sendto` FORTIFY support
diff --git a/libc/Android.bp b/libc/Android.bp
index 579c63c..7454d03 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1342,6 +1342,7 @@
"bionic/setpgrp.cpp",
"bionic/sigaction.cpp",
"bionic/signal.cpp",
+ "bionic/sigprocmask.cpp",
"bionic/socket.cpp",
"bionic/spawn.cpp",
"bionic/stat.cpp",
diff --git a/libc/bionic/__libc_current_sigrtmin.cpp b/libc/bionic/__libc_current_sigrtmin.cpp
index 04caa89..d2ea75d 100644
--- a/libc/bionic/__libc_current_sigrtmin.cpp
+++ b/libc/bionic/__libc_current_sigrtmin.cpp
@@ -28,14 +28,8 @@
#include <signal.h>
-// Realtime signals reserved for internal use:
-// 32 (__SIGRTMIN + 0) POSIX timers
-// 33 (__SIGRTMIN + 1) libbacktrace
-// 34 (__SIGRTMIN + 2) libcore
-// 35 (__SIGRTMIN + 3) debuggerd -b
+#include "private/sigrtmin.h"
-int __libc_current_sigrtmin(void) {
- // If you change this, also change __ndk_legacy___libc_current_sigrtmin
- // in <android/legacy_signal_inlines.h> to match.
- return __SIGRTMIN + 4;
+int __libc_current_sigrtmin() {
+ return __SIGRTMIN + __SIGRT_RESERVED;
}
diff --git a/libc/bionic/legacy_32_bit_support.cpp b/libc/bionic/legacy_32_bit_support.cpp
index 983fb32..ba59e8e 100644
--- a/libc/bionic/legacy_32_bit_support.cpp
+++ b/libc/bionic/legacy_32_bit_support.cpp
@@ -85,13 +85,13 @@
// to implement all four functions because the two system calls don't match any
// of the userspace functions. Unlike llseek, the pair is split lo-hi, not hi-lo.
ssize_t preadv(int fd, const struct iovec* ios, int count, off_t offset) {
- return __preadv64(fd, ios, count, offset, 0);
+ return preadv64(fd, ios, count, offset);
}
ssize_t preadv64(int fd, const struct iovec* ios, int count, off64_t offset) {
return __preadv64(fd, ios, count, offset, offset >> 32);
}
ssize_t pwritev(int fd, const struct iovec* ios, int count, off_t offset) {
- return __pwritev64(fd, ios, count, offset, 0);
+ return pwritev64(fd, ios, count, offset);
}
ssize_t pwritev64(int fd, const struct iovec* ios, int count, off64_t offset) {
return __pwritev64(fd, ios, count, offset, offset >> 32);
diff --git a/libc/bionic/poll.cpp b/libc/bionic/poll.cpp
index 1a54832..3df8b18 100644
--- a/libc/bionic/poll.cpp
+++ b/libc/bionic/poll.cpp
@@ -31,6 +31,7 @@
#include <sys/select.h>
#include "private/bionic_time_conversions.h"
+#include "private/sigrtmin.h"
#include "private/SigSetConverter.h"
extern "C" int __ppoll(pollfd*, unsigned int, timespec*, const sigset64_t*, size_t);
@@ -66,7 +67,15 @@
mutable_ts = *ts;
mutable_ts_ptr = &mutable_ts;
}
- return __ppoll(fds, fd_count, mutable_ts_ptr, ss, sizeof(*ss));
+
+ sigset64_t mutable_ss;
+ sigset64_t* mutable_ss_ptr = nullptr;
+ if (ss != nullptr) {
+ mutable_ss = filter_reserved_signals(*ss);
+ mutable_ss_ptr = &mutable_ss;
+ }
+
+ return __ppoll(fds, fd_count, mutable_ts_ptr, mutable_ss_ptr, sizeof(*mutable_ss_ptr));
}
int select(int fd_count, fd_set* read_fds, fd_set* write_fds, fd_set* error_fds, timeval* tv) {
@@ -109,6 +118,13 @@
mutable_ts_ptr = &mutable_ts;
}
+ sigset64_t mutable_ss;
+ sigset64_t* mutable_ss_ptr = nullptr;
+ if (ss != nullptr) {
+ mutable_ss = filter_reserved_signals(*ss);
+ mutable_ss_ptr = &mutable_ss;
+ }
+
// The Linux kernel only handles 6 arguments and this system call really needs 7,
// so the last argument is a void* pointing to:
struct pselect6_extra_data_t {
@@ -116,8 +132,8 @@
size_t ss_len;
};
pselect6_extra_data_t extra_data;
- extra_data.ss_addr = reinterpret_cast<uintptr_t>(ss);
- extra_data.ss_len = sizeof(*ss);
+ extra_data.ss_addr = reinterpret_cast<uintptr_t>(mutable_ss_ptr);
+ extra_data.ss_len = sizeof(*mutable_ss_ptr);
return __pselect6(fd_count, read_fds, write_fds, error_fds, mutable_ts_ptr, &extra_data);
}
diff --git a/libc/bionic/posix_timers.cpp b/libc/bionic/posix_timers.cpp
index 2edfe97..1abeb1f 100644
--- a/libc/bionic/posix_timers.cpp
+++ b/libc/bionic/posix_timers.cpp
@@ -35,6 +35,8 @@
#include <time.h>
// System calls.
+extern "C" int __rt_sigprocmask(int, const sigset64_t*, sigset64_t*, size_t);
+extern "C" int __rt_sigtimedwait(const sigset64_t*, siginfo_t*, const timespec*, size_t);
extern "C" int __timer_create(clockid_t, sigevent*, __kernel_timer_t*);
extern "C" int __timer_delete(__kernel_timer_t);
extern "C" int __timer_getoverrun(__kernel_timer_t);
@@ -77,7 +79,7 @@
while (true) {
// Wait for a signal...
siginfo_t si = {};
- if (sigtimedwait64(&sigset, &si, nullptr) == -1) continue;
+ if (__rt_sigtimedwait(&sigset, &si, nullptr, sizeof(sigset)) == -1) continue;
if (si.si_code == SI_TIMER) {
// This signal was sent because a timer fired, so call the callback.
@@ -146,11 +148,13 @@
sigset64_t sigset = {};
sigaddset64(&sigset, TIMER_SIGNAL);
sigset64_t old_sigset;
- sigprocmask64(SIG_BLOCK, &sigset, &old_sigset);
+
+ // Use __rt_sigprocmask instead of sigprocmask64 to avoid filtering out TIMER_SIGNAL.
+ __rt_sigprocmask(SIG_BLOCK, &sigset, &old_sigset, sizeof(sigset));
int rc = pthread_create(&timer->callback_thread, &thread_attributes, __timer_thread_start, timer);
- sigprocmask64(SIG_SETMASK, &old_sigset, nullptr);
+ __rt_sigprocmask(SIG_BLOCK, &old_sigset, nullptr, sizeof(old_sigset));
if (rc != 0) {
free(timer);
diff --git a/libc/bionic/sigaction.cpp b/libc/bionic/sigaction.cpp
index 19a08e6..41923cf 100644
--- a/libc/bionic/sigaction.cpp
+++ b/libc/bionic/sigaction.cpp
@@ -29,6 +29,8 @@
#include <signal.h>
#include <string.h>
+#include "private/sigrtmin.h"
+
extern "C" void __restore_rt(void);
extern "C" void __restore(void);
@@ -41,7 +43,7 @@
if (bionic_new_action != NULL) {
kernel_new_action.sa_flags = bionic_new_action->sa_flags;
kernel_new_action.sa_handler = bionic_new_action->sa_handler;
- kernel_new_action.sa_mask = bionic_new_action->sa_mask;
+ kernel_new_action.sa_mask = filter_reserved_signals(bionic_new_action->sa_mask);
#if defined(SA_RESTORER)
kernel_new_action.sa_restorer = bionic_new_action->sa_restorer;
#if defined(__aarch64__)
@@ -120,6 +122,7 @@
kernel_new.sa_restorer = (kernel_new.sa_flags & SA_SIGINFO) ? &__restore_rt : &__restore;
}
#endif
+ kernel_new.sa_mask = filter_reserved_signals(kernel_new.sa_mask);
}
return __rt_sigaction(signal,
diff --git a/libc/bionic/signal.cpp b/libc/bionic/signal.cpp
index fbfe0ce..175182b 100644
--- a/libc/bionic/signal.cpp
+++ b/libc/bionic/signal.cpp
@@ -38,9 +38,9 @@
#include "private/ErrnoRestorer.h"
#include "private/SigSetConverter.h"
+#include "private/sigrtmin.h"
extern "C" int __rt_sigpending(const sigset64_t*, size_t);
-extern "C" int __rt_sigprocmask(int, const sigset64_t*, sigset64_t*, size_t);
extern "C" int ___rt_sigqueueinfo(pid_t, int, siginfo_t*);
extern "C" int __rt_sigsuspend(const sigset64_t*, size_t);
extern "C" int __rt_sigtimedwait(const sigset64_t*, siginfo_t*, const timespec*, size_t);
@@ -208,31 +208,6 @@
return __rt_sigpending(set, sizeof(*set));
}
-int sigprocmask(int how, const sigset_t* bionic_new_set, sigset_t* bionic_old_set) {
- SigSetConverter new_set;
- sigset64_t* new_set_ptr = nullptr;
- if (bionic_new_set != nullptr) {
- sigemptyset64(&new_set.sigset64);
- new_set.sigset = *bionic_new_set;
- new_set_ptr = &new_set.sigset64;
- }
-
- SigSetConverter old_set;
- if (sigprocmask64(how, new_set_ptr, &old_set.sigset64) == -1) {
- return -1;
- }
-
- if (bionic_old_set != nullptr) {
- *bionic_old_set = old_set.sigset;
- }
-
- return 0;
-}
-
-int sigprocmask64(int how, const sigset64_t* new_set, sigset64_t* old_set) {
- return __rt_sigprocmask(how, new_set, old_set, sizeof(*new_set));
-}
-
int sigqueue(pid_t pid, int sig, const sigval value) {
siginfo_t info;
memset(&info, 0, sizeof(siginfo_t));
@@ -281,21 +256,33 @@
int sigsuspend(const sigset_t* bionic_set) {
SigSetConverter set = {};
set.sigset = *bionic_set;
- return __rt_sigsuspend(&set.sigset64, sizeof(set.sigset64));
+ return sigsuspend64(&set.sigset64);
}
int sigsuspend64(const sigset64_t* set) {
- return __rt_sigsuspend(set, sizeof(*set));
+ sigset64_t mutable_set;
+ sigset64_t* mutable_set_ptr = nullptr;
+ if (set) {
+ mutable_set = filter_reserved_signals(*set);
+ mutable_set_ptr = &mutable_set;
+ }
+ return __rt_sigsuspend(mutable_set_ptr, sizeof(*set));
}
int sigtimedwait(const sigset_t* bionic_set, siginfo_t* info, const timespec* timeout) {
SigSetConverter set = {};
set.sigset = *bionic_set;
- return __rt_sigtimedwait(&set.sigset64, info, timeout, sizeof(set.sigset64));
+ return sigtimedwait64(&set.sigset64, info, timeout);
}
int sigtimedwait64(const sigset64_t* set, siginfo_t* info, const timespec* timeout) {
- return __rt_sigtimedwait(set, info, timeout, sizeof(*set));
+ sigset64_t mutable_set;
+ sigset64_t* mutable_set_ptr = nullptr;
+ if (set) {
+ mutable_set = filter_reserved_signals(*set);
+ mutable_set_ptr = &mutable_set;
+ }
+ return __rt_sigtimedwait(mutable_set_ptr, info, timeout, sizeof(*set));
}
int sigwait(const sigset_t* bionic_set, int* sig) {
diff --git a/libc/bionic/sigprocmask.cpp b/libc/bionic/sigprocmask.cpp
new file mode 100644
index 0000000..36866f3
--- /dev/null
+++ b/libc/bionic/sigprocmask.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <signal.h>
+
+#include "private/sigrtmin.h"
+#include "private/SigSetConverter.h"
+
+extern "C" int __rt_sigprocmask(int, const sigset64_t*, sigset64_t*, size_t);
+
+//
+// These need to be kept separate from pthread_sigmask, sigblock, sigsetmask,
+// sighold, and sigset because libsigchain only intercepts sigprocmask so we
+// can't allow clang to decide to inline sigprocmask.
+//
+
+int sigprocmask(int how,
+ const sigset_t* bionic_new_set,
+ sigset_t* bionic_old_set) __attribute__((__noinline__)) {
+ SigSetConverter new_set;
+ sigset64_t* new_set_ptr = nullptr;
+ if (bionic_new_set != nullptr) {
+ sigemptyset64(&new_set.sigset64);
+ new_set.sigset = *bionic_new_set;
+ new_set_ptr = &new_set.sigset64;
+ }
+
+ SigSetConverter old_set;
+ if (sigprocmask64(how, new_set_ptr, &old_set.sigset64) == -1) {
+ return -1;
+ }
+
+ if (bionic_old_set != nullptr) {
+ *bionic_old_set = old_set.sigset;
+ }
+
+ return 0;
+}
+
+int sigprocmask64(int how,
+ const sigset64_t* new_set,
+ sigset64_t* old_set) __attribute__((__noinline__)) {
+ sigset64_t mutable_new_set;
+ sigset64_t* mutable_new_set_ptr = nullptr;
+ if (new_set) {
+ mutable_new_set = filter_reserved_signals(*new_set);
+ mutable_new_set_ptr = &mutable_new_set;
+ }
+ return __rt_sigprocmask(how, mutable_new_set_ptr, old_set, sizeof(*new_set));
+}
diff --git a/libc/dns/net/getaddrinfo.c b/libc/dns/net/getaddrinfo.c
index 418bf6d..db683bb 100644
--- a/libc/dns/net/getaddrinfo.c
+++ b/libc/dns/net/getaddrinfo.c
@@ -198,7 +198,7 @@
{ 0, 0 }
};
-#define MAXPACKET (64*1024)
+#define MAXPACKET (8*1024)
typedef union {
HEADER hdr;
diff --git a/libc/dns/net/gethnamaddr.c b/libc/dns/net/gethnamaddr.c
index 7118a29..7589380 100644
--- a/libc/dns/net/gethnamaddr.c
+++ b/libc/dns/net/gethnamaddr.c
@@ -127,7 +127,7 @@
.uid = NET_CONTEXT_INVALID_UID
};
-#define MAXPACKET (64*1024)
+#define MAXPACKET (8*1024)
typedef union {
HEADER hdr;
diff --git a/libc/private/sigrtmin.h b/libc/private/sigrtmin.h
new file mode 100644
index 0000000..ea8673d
--- /dev/null
+++ b/libc/private/sigrtmin.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+#include <signal.h>
+
+// Realtime signals reserved for internal use:
+// 32 (__SIGRTMIN + 0) POSIX timers
+// 33 (__SIGRTMIN + 1) libbacktrace
+// 34 (__SIGRTMIN + 2) libcore
+// 35 (__SIGRTMIN + 3) debuggerd -b
+//
+// If you change this, also change __ndk_legacy___libc_current_sigrtmin
+// in <android/legacy_signal_inlines.h> to match.
+
+#define __SIGRT_RESERVED 4
+static inline __always_inline sigset64_t filter_reserved_signals(sigset64_t sigset) {
+ for (int signo = __SIGRTMIN; signo < __SIGRTMIN + __SIGRT_RESERVED; ++signo) {
+ sigdelset64(&sigset, signo);
+ }
+ return sigset;
+}
diff --git a/libc/stdio/local.h b/libc/stdio/local.h
index 11b136d..ab31af1 100644
--- a/libc/stdio/local.h
+++ b/libc/stdio/local.h
@@ -38,12 +38,10 @@
#include <stdbool.h>
#include <wchar.h>
-#if defined(__cplusplus) // Until we fork all of stdio...
+#if defined(__cplusplus) // Until we fork all of stdio...
#include "private/bionic_fortify.h"
#endif
-#include "wcio.h"
-
/*
* Information local to this implementation of stdio,
* in particular, macros and private variables.
@@ -61,53 +59,66 @@
};
struct __sFILE {
- unsigned char *_p; /* current position in (some) buffer */
- int _r; /* read space left for getc() */
- int _w; /* write space left for putc() */
+ unsigned char* _p; /* current position in (some) buffer */
+ int _r; /* read space left for getc() */
+ int _w; /* write space left for putc() */
#if defined(__LP64__)
- int _flags; /* flags, below; this FILE is free if 0 */
- int _file; /* fileno, if Unix descriptor, else -1 */
+ int _flags; /* flags, below; this FILE is free if 0 */
+ int _file; /* fileno, if Unix descriptor, else -1 */
#else
- short _flags; /* flags, below; this FILE is free if 0 */
- short _file; /* fileno, if Unix descriptor, else -1 */
+ short _flags; /* flags, below; this FILE is free if 0 */
+ short _file; /* fileno, if Unix descriptor, else -1 */
#endif
- struct __sbuf _bf; /* the buffer (at least 1 byte, if !NULL) */
- int _lbfsize; /* 0 or -_bf._size, for inline putc */
+ struct __sbuf _bf; /* the buffer (at least 1 byte, if !NULL) */
+ int _lbfsize; /* 0 or -_bf._size, for inline putc */
- // Function pointers used by `funopen`.
- // Note that `_seek` is ignored if `_seek64` (in __sfileext) is set.
- // TODO: NetBSD has `funopen2` which corrects the `int`s to `size_t`s.
- // TODO: glibc has `fopencookie` which passes the function pointers in a struct.
- void* _cookie; /* cookie passed to io functions */
- int (*_close)(void*);
- int (*_read)(void*, char*, int);
- fpos_t (*_seek)(void*, fpos_t, int);
- int (*_write)(void*, const char*, int);
+ // Function pointers used by `funopen`.
+ // Note that `_seek` is ignored if `_seek64` (in __sfileext) is set.
+ // TODO: NetBSD has `funopen2` which corrects the `int`s to `size_t`s.
+ // TODO: glibc has `fopencookie` which passes the function pointers in a struct.
+ void* _cookie; /* cookie passed to io functions */
+ int (*_close)(void*);
+ int (*_read)(void*, char*, int);
+ fpos_t (*_seek)(void*, fpos_t, int);
+ int (*_write)(void*, const char*, int);
- /* extension data, to avoid further ABI breakage */
- struct __sbuf _ext;
- /* data for long sequences of ungetc() */
- unsigned char *_up; /* saved _p when _p is doing ungetc data */
- int _ur; /* saved _r when _r is counting ungetc data */
+ /* extension data, to avoid further ABI breakage */
+ struct __sbuf _ext;
+ /* data for long sequences of ungetc() */
+ unsigned char* _up; /* saved _p when _p is doing ungetc data */
+ int _ur; /* saved _r when _r is counting ungetc data */
- /* tricks to meet minimum requirements even when malloc() fails */
- unsigned char _ubuf[3]; /* guarantee an ungetc() buffer */
- unsigned char _nbuf[1]; /* guarantee a getc() buffer */
+ /* tricks to meet minimum requirements even when malloc() fails */
+ unsigned char _ubuf[3]; /* guarantee an ungetc() buffer */
+ unsigned char _nbuf[1]; /* guarantee a getc() buffer */
- /* separate buffer for fgetln() when line crosses buffer boundary */
- struct __sbuf _lb; /* buffer for fgetln() */
+ /* separate buffer for fgetln() when line crosses buffer boundary */
+ struct __sbuf _lb; /* buffer for fgetln() */
- /* Unix stdio files get aligned to block boundaries on fseek() */
- int _blksize; /* stat.st_blksize (may be != _bf._size) */
+ /* Unix stdio files get aligned to block boundaries on fseek() */
+ int _blksize; /* stat.st_blksize (may be != _bf._size) */
- fpos_t _unused_0; // This was the `_offset` field (see below).
+ fpos_t _unused_0; // This was the `_offset` field (see below).
- // Do not add new fields here. (Or remove or change the size of any above.)
- // Although bionic currently exports `stdin`, `stdout`, and `stderr` symbols,
- // that still hasn't made it to the NDK. All NDK-built apps index directly
- // into an array of this struct (which was in <stdio.h> historically), so if
- // you need to make any changes, they need to be in the `__sfileext` struct
- // below, and accessed via `_EXT`.
+ // Do not add new fields here. (Or remove or change the size of any above.)
+ // Although bionic currently exports `stdin`, `stdout`, and `stderr` symbols,
+ // that still hasn't made it to the NDK. All NDK-built apps index directly
+ // into an array of this struct (which was in <stdio.h> historically), so if
+ // you need to make any changes, they need to be in the `__sfileext` struct
+ // below, and accessed via `_EXT`.
+};
+
+/* minimal requirement of SUSv2 */
+#define WCIO_UNGETWC_BUFSIZE 1
+
+struct wchar_io_data {
+ mbstate_t wcio_mbstate_in;
+ mbstate_t wcio_mbstate_out;
+
+ wchar_t wcio_ungetwc_buf[WCIO_UNGETWC_BUFSIZE];
+ size_t wcio_ungetwc_inbuf;
+
+ int wcio_mode; /* orientation */
};
struct __sfileext {
@@ -133,9 +144,9 @@
#define __SNBF 0x0002 // Unbuffered.
// __SRD and __SWR are mutually exclusive because they indicate what we did last.
// If you want to know whether we were opened read-write, check __SRW instead.
-#define __SRD 0x0004 // Last operation was read.
-#define __SWR 0x0008 // Last operation was write.
-#define __SRW 0x0010 // Was opened for reading & writing.
+#define __SRD 0x0004 // Last operation was read.
+#define __SWR 0x0008 // Last operation was write.
+#define __SRW 0x0010 // Was opened for reading & writing.
#define __SEOF 0x0020 // Found EOF.
#define __SERR 0x0040 // Found error.
#define __SMBF 0x0080 // `_buf` is from malloc.
@@ -156,13 +167,13 @@
#define _EXT(fp) __BIONIC_CAST(reinterpret_cast, struct __sfileext*, (fp)->_ext._base)
#define _UB(fp) _EXT(fp)->_ub
-#define _FLOCK(fp) _EXT(fp)->_lock
+#define _FLOCK(fp) _EXT(fp)->_lock
-#define _FILEEXT_SETUP(fp, fext) \
- do { \
+#define _FILEEXT_SETUP(fp, fext) \
+ do { \
(fp)->_ext._base = __BIONIC_CAST(reinterpret_cast, unsigned char*, fext); \
- memset(_EXT(fp), 0, sizeof(struct __sfileext)); \
- _EXT(fp)->_caller_handles_locking = true; \
+ memset(_EXT(fp), 0, sizeof(struct __sfileext)); \
+ _EXT(fp)->_caller_handles_locking = true; \
} while (0)
// Android <= 19 had getc/putc macros in <stdio.h> that referred
@@ -182,49 +193,49 @@
__LIBC32_LEGACY_PUBLIC__ void __smakebuf(FILE*);
/* These are referenced by the Greed for Glory franchise. */
-__LIBC32_LEGACY_PUBLIC__ int __sflush(FILE *);
-__LIBC32_LEGACY_PUBLIC__ int __sread(void *, char *, int);
-__LIBC32_LEGACY_PUBLIC__ int __swrite(void *, const char *, int);
-__LIBC32_LEGACY_PUBLIC__ fpos_t __sseek(void *, fpos_t, int);
-__LIBC32_LEGACY_PUBLIC__ int __sclose(void *);
-__LIBC32_LEGACY_PUBLIC__ int _fwalk(int (*)(FILE *));
+__LIBC32_LEGACY_PUBLIC__ int __sflush(FILE*);
+__LIBC32_LEGACY_PUBLIC__ int __sread(void*, char*, int);
+__LIBC32_LEGACY_PUBLIC__ int __swrite(void*, const char*, int);
+__LIBC32_LEGACY_PUBLIC__ fpos_t __sseek(void*, fpos_t, int);
+__LIBC32_LEGACY_PUBLIC__ int __sclose(void*);
+__LIBC32_LEGACY_PUBLIC__ int _fwalk(int (*)(FILE*));
off64_t __sseek64(void*, off64_t, int);
-int __sflush_locked(FILE *);
-int __swhatbuf(FILE *, size_t *, int *);
-wint_t __fgetwc_unlock(FILE *);
-wint_t __ungetwc(wint_t, FILE *);
-int __vfprintf(FILE *, const char *, va_list);
-int __svfscanf(FILE *, const char *, va_list);
-int __vfwprintf(FILE *, const wchar_t *, va_list);
-int __vfwscanf(FILE *, const wchar_t *, va_list);
+int __sflush_locked(FILE*);
+int __swhatbuf(FILE*, size_t*, int*);
+wint_t __fgetwc_unlock(FILE*);
+wint_t __ungetwc(wint_t, FILE*);
+int __vfprintf(FILE*, const char*, va_list);
+int __svfscanf(FILE*, const char*, va_list);
+int __vfwprintf(FILE*, const wchar_t*, va_list);
+int __vfwscanf(FILE*, const wchar_t*, va_list);
/*
* Return true if the given FILE cannot be written now.
*/
-#define cantwrite(fp) \
- ((((fp)->_flags & __SWR) == 0 || (fp)->_bf._base == NULL) && \
- __swsetup(fp))
+#define cantwrite(fp) ((((fp)->_flags & __SWR) == 0 || (fp)->_bf._base == NULL) && __swsetup(fp))
/*
* Test whether the given stdio file has an active ungetc buffer;
* release such a buffer, without restoring ordinary unread data.
*/
-#define HASUB(fp) (_UB(fp)._base != NULL)
-#define FREEUB(fp) { \
- if (_UB(fp)._base != (fp)->_ubuf) \
- free(_UB(fp)._base); \
- _UB(fp)._base = NULL; \
-}
+#define HASUB(fp) (_UB(fp)._base != NULL)
+#define FREEUB(fp) \
+ { \
+ if (_UB(fp)._base != (fp)->_ubuf) free(_UB(fp)._base); \
+ _UB(fp)._base = NULL; \
+ }
-#define FLOCKFILE(fp) if (!_EXT(fp)->_caller_handles_locking) flockfile(fp)
-#define FUNLOCKFILE(fp) if (!_EXT(fp)->_caller_handles_locking) funlockfile(fp)
+#define FLOCKFILE(fp) \
+ if (!_EXT(fp)->_caller_handles_locking) flockfile(fp)
+#define FUNLOCKFILE(fp) \
+ if (!_EXT(fp)->_caller_handles_locking) funlockfile(fp)
#define NO_PRINTF_PERCENT_N
/* OpenBSD exposes these in <stdio.h>, but we only want them exposed to the implementation. */
-#define __sferror(p) (((p)->_flags & __SERR) != 0)
-#define __sclearerr(p) ((void)((p)->_flags &= ~(__SERR|__SEOF)))
+#define __sferror(p) (((p)->_flags & __SERR) != 0)
+#define __sclearerr(p) ((void)((p)->_flags &= ~(__SERR | __SEOF)))
#define __sgetc(p) (--(p)->_r < 0 ? __srget(p) : (int)(*(p)->_p++))
/* OpenBSD declares these in fvwrite.h, but we share them with C++ parts of the implementation. */
@@ -241,7 +252,7 @@
wint_t __fputwc_unlock(wchar_t wc, FILE* fp);
/* Remove the if (!__sdidinit) __sinit() idiom from untouched upstream stdio code. */
-extern void __sinit(void); // Not actually implemented.
+extern void __sinit(void); // Not actually implemented.
#define __sdidinit 1
size_t parsefloat(FILE*, char*, char*);
@@ -249,7 +260,8 @@
// Sanity check a FILE* for nullptr, so we can emit a message while crashing
// instead of doing a blind null-dereference.
-#define CHECK_FP(fp) if (fp == nullptr) __fortify_fatal("%s: null FILE*", __FUNCTION__)
+#define CHECK_FP(fp) \
+ if (fp == nullptr) __fortify_fatal("%s: null FILE*", __FUNCTION__)
/*
* Floating point scanf/printf (input/output) definitions.
@@ -276,4 +288,21 @@
char* __hldtoa(long double, const char*, int, int*, int*, char**);
char* __ldtoa(long double*, int, int, int*, int*, char**);
+#define WCIO_GET(fp) (_EXT(fp) ? &(_EXT(fp)->_wcio) : (struct wchar_io_data*)0)
+
+#define _SET_ORIENTATION(fp, mode) \
+ do { \
+ struct wchar_io_data* _wcio = WCIO_GET(fp); \
+ if (_wcio && _wcio->wcio_mode == 0) _wcio->wcio_mode = (mode); \
+ } while (0)
+
+#define WCIO_FREE(fp) \
+ do { \
+ struct wchar_io_data* _wcio = WCIO_GET(fp); \
+ if (_wcio) { \
+ _wcio->wcio_mode = 0; \
+ _wcio->wcio_ungetwc_inbuf = 0; \
+ } \
+ } while (0)
+
__END_DECLS
diff --git a/libc/stdio/wcio.h b/libc/stdio/wcio.h
deleted file mode 100644
index 047eb77..0000000
--- a/libc/stdio/wcio.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/* $OpenBSD: wcio.h,v 1.2 2013/04/17 17:40:35 tedu Exp $ */
-/* $NetBSD: wcio.h,v 1.3 2003/01/18 11:30:00 thorpej Exp $ */
-
-/*-
- * Copyright (c)2001 Citrus Project,
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $Citrus$
- */
-
-#pragma once
-
-#include <sys/cdefs.h>
-
-__BEGIN_DECLS
-
-/* minimal requirement of SUSv2 */
-#define WCIO_UNGETWC_BUFSIZE 1
-
-struct wchar_io_data {
- mbstate_t wcio_mbstate_in;
- mbstate_t wcio_mbstate_out;
-
- wchar_t wcio_ungetwc_buf[WCIO_UNGETWC_BUFSIZE];
- size_t wcio_ungetwc_inbuf;
-
- int wcio_mode; /* orientation */
-};
-
-#define WCIO_GET(fp) \
- (_EXT(fp) ? &(_EXT(fp)->_wcio) : (struct wchar_io_data *)0)
-
-#define _SET_ORIENTATION(fp, mode) \
-do {\
- struct wchar_io_data *_wcio = WCIO_GET(fp); \
- if (_wcio && _wcio->wcio_mode == 0) \
- _wcio->wcio_mode = (mode);\
-} while (0)
-
-/*
- * WCIO_FREE should be called by fclose
- */
-#define WCIO_FREE(fp) \
-do {\
- struct wchar_io_data *_wcio = WCIO_GET(fp); \
- if (_wcio) { \
- _wcio->wcio_mode = 0;\
- _wcio->wcio_ungetwc_inbuf = 0;\
- } \
-} while (0)
-
-#define WCIO_FREEUB(fp) \
-do {\
- struct wchar_io_data *_wcio = WCIO_GET(fp); \
- if (_wcio) { \
- _wcio->wcio_ungetwc_inbuf = 0;\
- } \
-} while (0)
-
-__END_DECLS
diff --git a/libc/tzcode/strptime.c b/libc/tzcode/strptime.c
index 2100630..0e9a7d3 100644
--- a/libc/tzcode/strptime.c
+++ b/libc/tzcode/strptime.c
@@ -38,7 +38,9 @@
//#include <sys/localedef.h>
#include <ctype.h>
+#include <errno.h>
#include <locale.h>
+#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "tzfile.h"
@@ -128,7 +130,7 @@
fmt++;
continue;
}
-
+
if ((c = *fmt++) != '%')
goto literal;
@@ -154,7 +156,7 @@
_LEGAL_ALT(0);
alt_format |= _ALT_O;
goto again;
-
+
/*
* "Complex" conversion rules, implemented through recursion.
*/
@@ -169,7 +171,7 @@
if (!(bp = _strptime(bp, "%m/%d/%y", tm, cr)))
return (NULL);
break;
-
+
case 'R': /* The time as "%H:%M". */
_LEGAL_ALT(0);
if (!(bp = _strptime(bp, "%H:%M", tm, cr)))
@@ -337,6 +339,25 @@
return (NULL);
break;
+ case 's':
+ {
+ // Android addition, 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);
+ time_t t = n;
+ if (bp == old_bp || errno == ERANGE || ((long) t) != n) {
+ errno = saved_errno;
+ return NULL;
+ }
+ errno = saved_errno;
+
+ if (localtime_r(&t, tm) == NULL) return NULL;
+ }
+ break;
+
+
case 'U': /* The week of year, beginning on sunday. */
case 'W': /* The week of year, beginning on monday. */
_LEGAL_ALT(_ALT_O);
diff --git a/linker/linker.cpp b/linker/linker.cpp
index ff2a7e6..dd700fe 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1105,10 +1105,14 @@
const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) {
#if !defined(__LP64__)
// Work around incorrect DT_NEEDED entries for old apps: http://b/21364029
- if (get_application_target_sdk_version() < __ANDROID_API_M__) {
+ int app_target_api_level = get_application_target_sdk_version();
+ if (app_target_api_level < __ANDROID_API_M__) {
const char* bname = basename(dt_needed);
if (bname != dt_needed) {
- DL_WARN("library \"%s\" has invalid DT_NEEDED entry \"%s\"", sopath, dt_needed);
+ DL_WARN_documented_change(__ANDROID_API_M__,
+ "invalid-dt_needed-entries-enforced-for-api-level-23",
+ "library \"%s\" has invalid DT_NEEDED entry \"%s\"",
+ sopath, dt_needed, app_target_api_level);
add_dlwarning(sopath, "invalid DT_NEEDED entry", dt_needed);
}
@@ -1246,10 +1250,11 @@
const soinfo* needed_or_dlopened_by = task->get_needed_by();
const char* sopath = needed_or_dlopened_by == nullptr ? "(unknown)" :
needed_or_dlopened_by->get_realpath();
- DL_WARN("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the namespace \"%s\""
- " - the access is temporarily granted as a workaround for http://b/26394120, note that the access"
- " will be removed in future releases of Android.",
- name, realpath.c_str(), sopath, ns->get_name());
+ DL_WARN_documented_change(__ANDROID_API_N__,
+ "private-api-enforced-for-api-level-24",
+ "library \"%s\" (\"%s\") needed or dlopened by \"%s\" "
+ "is not accessible by namespace \"%s\"",
+ name, realpath.c_str(), sopath, ns->get_name());
add_dlwarning(sopath, "unauthorized access to", name);
}
} else {
@@ -3363,7 +3368,9 @@
set_dt_flags_1(d->d_un.d_val);
if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {
- DL_WARN("\"%s\" has unsupported flags DT_FLAGS_1=%p", get_realpath(), reinterpret_cast<void*>(d->d_un.d_val));
+ DL_WARN("Warning: \"%s\" has unsupported flags DT_FLAGS_1=%p "
+ "(ignoring unsupported flags)",
+ get_realpath(), reinterpret_cast<void*>(d->d_un.d_val));
}
break;
#if defined(__mips__)
@@ -3442,7 +3449,7 @@
} else {
tag_name = "unknown";
}
- DL_WARN("\"%s\" unused DT entry: %s (type %p arg %p)",
+ DL_WARN("Warning: \"%s\" unused DT entry: %s (type %p arg %p) (ignoring)",
get_realpath(),
tag_name,
reinterpret_cast<void*>(d->d_tag),
@@ -3495,16 +3502,20 @@
// Before M release linker was using basename in place of soname.
// In the case when dt_soname is absent some apps stop working
// because they can't find dt_needed library by soname.
- // This workaround should keep them working. (applies only
- // for apps targeting sdk version < M). Make an exception for
- // the main executable and linker; they do not need to have dt_soname
+ // This workaround should keep them working. (Applies only
+ // for apps targeting sdk version < M.) Make an exception for
+ // the main executable and linker; they do not need to have dt_soname.
+ // TODO: >= O the linker doesn't need this workaround.
if (soname_ == nullptr &&
this != solist_get_somain() &&
(flags_ & FLAG_LINKER) == 0 &&
get_application_target_sdk_version() < __ANDROID_API_M__) {
soname_ = basename(realpath_.c_str());
- DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
- get_realpath(), soname_);
+ DL_WARN_documented_change(__ANDROID_API_M__,
+ "missing-soname-enforced-for-api-level-23",
+ "\"%s\" has no DT_SONAME (will use %s instead)",
+ get_realpath(), soname_);
+
// Don't call add_dlwarning because a missing DT_SONAME isn't important enough to show in the UI
}
return true;
@@ -3535,7 +3546,8 @@
#if !defined(__LP64__)
if (has_text_relocations) {
// Fail if app is targeting M or above.
- if (get_application_target_sdk_version() >= __ANDROID_API_M__) {
+ int app_target_api_level = get_application_target_sdk_version();
+ if (app_target_api_level >= __ANDROID_API_M__) {
DL_ERR_AND_LOG("\"%s\" has text relocations (https://android.googlesource.com/platform/"
"bionic/+/master/android-changes-for-ndk-developers.md#Text-Relocations-"
"Enforced-for-API-level-23)", get_realpath());
@@ -3543,13 +3555,13 @@
}
// Make segments writable to allow text relocations to work properly. We will later call
// phdr_table_protect_segments() after all of them are applied.
- DL_WARN("\"%s\" has text relocations (https://android.googlesource.com/platform/"
- "bionic/+/master/android-changes-for-ndk-developers.md#Text-Relocations-Enforced-"
- "for-API-level-23)", get_realpath());
+ DL_WARN_documented_change(__ANDROID_API_M__,
+ "Text-Relocations-Enforced-for-API-level-23",
+ "\"%s\" has text relocations",
+ get_realpath());
add_dlwarning(get_realpath(), "text relocations");
if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
- DL_ERR("can't unprotect loadable segments for \"%s\": %s",
- get_realpath(), strerror(errno));
+ DL_ERR("can't unprotect loadable segments for \"%s\": %s", get_realpath(), strerror(errno));
return false;
}
}
@@ -3739,7 +3751,7 @@
&config,
&error_msg)) {
if (!error_msg.empty()) {
- DL_WARN("error reading config file \"%s\" for \"%s\" (will use default configuration): %s",
+ DL_WARN("Warning: couldn't read \"%s\" for \"%s\" (using default configuration instead): %s",
config_file,
executable_path,
error_msg.c_str());
diff --git a/linker/linker_config.cpp b/linker/linker_config.cpp
index 83c2f36..c00b734 100644
--- a/linker/linker_config.cpp
+++ b/linker/linker_config.cpp
@@ -194,14 +194,14 @@
std::string section_name;
- while(true) {
+ while (true) {
std::string name;
std::string value;
std::string error;
int result = cp.next_token(&name, &value, &error);
if (result == ConfigParser::kError) {
- DL_WARN("error parsing %s:%zd: %s (ignoring this line)",
+ DL_WARN("%s:%zd: warning: couldn't parse %s (ignoring this line)",
ld_config_file_path,
cp.lineno(),
error.c_str());
@@ -214,7 +214,7 @@
if (result == ConfigParser::kPropertyAssign) {
if (!android::base::StartsWith(name, "dir.")) {
- DL_WARN("error parsing %s:%zd: unexpected property name \"%s\", "
+ DL_WARN("%s:%zd: warning: unexpected property name \"%s\", "
"expected format dir.<section_name> (ignoring this line)",
ld_config_file_path,
cp.lineno(),
@@ -228,7 +228,7 @@
}
if (value.empty()) {
- DL_WARN("error parsing %s:%zd: property value is empty (ignoring this line)",
+ DL_WARN("%s:%zd: warning: property value is empty (ignoring this line)",
ld_config_file_path,
cp.lineno());
continue;
@@ -275,7 +275,7 @@
if (result == ConfigParser::kPropertyAssign) {
if (properties->find(name) != properties->end()) {
- DL_WARN("%s:%zd: warning: property \"%s\" redefinition",
+ DL_WARN("%s:%zd: warning: redefining property \"%s\" (overriding previous value)",
ld_config_file_path,
cp.lineno(),
name.c_str());
@@ -284,7 +284,7 @@
(*properties)[name] = PropertyValue(std::move(value), cp.lineno());
} else if (result == ConfigParser::kPropertyAppend) {
if (properties->find(name) == properties->end()) {
- DL_WARN("%s:%zd: warning: appending to property \"%s\" which isn't defined",
+ DL_WARN("%s:%zd: warning: appending to undefined property \"%s\" (treating as assignment)",
ld_config_file_path,
cp.lineno(),
name.c_str());
@@ -299,7 +299,7 @@
value = ":" + value;
(*properties)[name].append_value(std::move(value));
} else {
- DL_WARN("%s:%zd: warning: += isn't allowed to property \"%s\". Ignoring.",
+ DL_WARN("%s:%zd: warning: += isn't allowed for property \"%s\" (ignoring)",
ld_config_file_path,
cp.lineno(),
name.c_str());
@@ -308,7 +308,7 @@
}
if (result == ConfigParser::kError) {
- DL_WARN("error parsing %s:%zd: %s (ignoring this line)",
+ DL_WARN("%s:%zd: warning: couldn't parse %s (ignoring this line)",
ld_config_file_path,
cp.lineno(),
error.c_str());
diff --git a/linker/linker_globals.cpp b/linker/linker_globals.cpp
index 155ebf4..bcc2a1e 100644
--- a/linker/linker_globals.cpp
+++ b/linker/linker_globals.cpp
@@ -26,10 +26,12 @@
* SUCH DAMAGE.
*/
-
+#include "linker.h"
#include "linker_globals.h"
#include "linker_namespaces.h"
+#include "android-base/stringprintf.h"
+
int g_argc = 0;
char** g_argv = nullptr;
char** g_envp = nullptr;
@@ -48,3 +50,18 @@
return sizeof(__linker_dl_err_buf);
}
+void DL_WARN_documented_change(int api_level, const char* doc_link, const char* fmt, ...) {
+ std::string result{"Warning: "};
+
+ va_list ap;
+ va_start(ap, fmt);
+ android::base::StringAppendV(&result, fmt, ap);
+ va_end(ap);
+
+ android::base::StringAppendF(&result,
+ " and will not work when the app moves to API level %d or later "
+ "(https://android.googlesource.com/platform/bionic/+/master/%s) "
+ "(allowing for now because this app's target API level is still %d)",
+ api_level, doc_link, get_application_target_sdk_version());
+ DL_WARN("%s", result.c_str());
+}
diff --git a/linker/linker_globals.h b/linker/linker_globals.h
index b470918..32aa09d 100644
--- a/linker/linker_globals.h
+++ b/linker/linker_globals.h
@@ -49,6 +49,8 @@
async_safe_format_fd(2, "\n"); \
} while (false)
+void DL_WARN_documented_change(int api_level, const char* doc_link, const char* fmt, ...);
+
#define DL_ERR_AND_LOG(fmt, x...) \
do { \
DL_ERR(fmt, x); \
diff --git a/linker/linker_namespaces.cpp b/linker/linker_namespaces.cpp
index 9fdf0b5..fd72cdc 100644
--- a/linker/linker_namespaces.cpp
+++ b/linker/linker_namespaces.cpp
@@ -64,7 +64,8 @@
// This is workaround for apps hacking into soinfo list.
// and inserting their own entries into it. (http://b/37191433)
if (!si->has_min_version(3)) {
- DL_WARN("invalid soinfo version for \"%s\"", si->get_soname());
+ DL_WARN("Warning: invalid soinfo version for \"%s\" (assuming inaccessible)",
+ si->get_soname());
return false;
}
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index a9873c4..a5eab44 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -268,8 +268,10 @@
name_.c_str(), header_.e_shentsize, sizeof(ElfW(Shdr)));
return false;
}
- DL_WARN("\"%s\" has unsupported e_shentsize: 0x%x (expected 0x%zx)",
- name_.c_str(), header_.e_shentsize, sizeof(ElfW(Shdr)));
+ DL_WARN_documented_change(__ANDROID_API_O__,
+ "invalid-elf-header_section-headers-enforced-for-api-level-26",
+ "\"%s\" has unsupported e_shentsize 0x%x (expected 0x%zx)",
+ name_.c_str(), header_.e_shentsize, sizeof(ElfW(Shdr)));
add_dlwarning(name_.c_str(), "has invalid ELF header");
}
@@ -280,7 +282,9 @@
return false;
}
- DL_WARN("\"%s\" has invalid e_shstrndx", name_.c_str());
+ DL_WARN_documented_change(__ANDROID_API_O__,
+ "invalid-elf-header_section-headers-enforced-for-api-level-26",
+ "\"%s\" has invalid e_shstrndx", name_.c_str());
add_dlwarning(name_.c_str(), "has invalid ELF header");
}
@@ -395,11 +399,13 @@
pt_dynamic_offset);
return false;
}
- DL_WARN("\"%s\" .dynamic section has invalid offset: 0x%zx, "
- "expected to match PT_DYNAMIC offset: 0x%zx",
- name_.c_str(),
- static_cast<size_t>(dynamic_shdr->sh_offset),
- pt_dynamic_offset);
+ DL_WARN_documented_change(__ANDROID_API_O__,
+ "invalid-elf-header_section-headers-enforced-for-api-level-26",
+ "\"%s\" .dynamic section has invalid offset: 0x%zx "
+ "(expected to match PT_DYNAMIC offset 0x%zx)",
+ name_.c_str(),
+ static_cast<size_t>(dynamic_shdr->sh_offset),
+ pt_dynamic_offset);
add_dlwarning(name_.c_str(), "invalid .dynamic section");
}
@@ -412,11 +418,13 @@
pt_dynamic_filesz);
return false;
}
- DL_WARN("\"%s\" .dynamic section has invalid size: 0x%zx, "
- "expected to match PT_DYNAMIC filesz: 0x%zx",
- name_.c_str(),
- static_cast<size_t>(dynamic_shdr->sh_size),
- pt_dynamic_filesz);
+ DL_WARN_documented_change(__ANDROID_API_O__,
+ "invalid-elf-header_section-headers-enforced-for-api-level-26",
+ "\"%s\" .dynamic section has invalid size: 0x%zx "
+ "(expected to match PT_DYNAMIC filesz 0x%zx)",
+ name_.c_str(),
+ static_cast<size_t>(dynamic_shdr->sh_size),
+ pt_dynamic_filesz);
add_dlwarning(name_.c_str(), "invalid .dynamic section");
}
@@ -651,10 +659,13 @@
if ((prot & (PROT_EXEC | PROT_WRITE)) == (PROT_EXEC | PROT_WRITE)) {
// W + E PT_LOAD segments are not allowed in O.
if (get_application_target_sdk_version() >= __ANDROID_API_O__) {
- DL_ERR_AND_LOG("\"%s\": W + E load segments are not allowed", name_.c_str());
+ DL_ERR_AND_LOG("\"%s\": W+E load segments are not allowed", name_.c_str());
return false;
}
- DL_WARN("\"%s\": W + E load segments are not allowed", name_.c_str());
+ DL_WARN_documented_change(__ANDROID_API_O__,
+ "writable-and-executable-segments-enforced-for-api-level-26",
+ "\"%s\" has load segments that are both writable and executable",
+ name_.c_str());
add_dlwarning(name_.c_str(), "W+E load segments");
}
diff --git a/linker/linker_soinfo.cpp b/linker/linker_soinfo.cpp
index 54bfcf0..731e8f5 100644
--- a/linker/linker_soinfo.cpp
+++ b/linker/linker_soinfo.cpp
@@ -152,7 +152,7 @@
ELF_ST_BIND(s->st_info) == STB_WEAK) {
return s->st_shndx != SHN_UNDEF;
} else if (ELF_ST_BIND(s->st_info) != STB_LOCAL) {
- DL_WARN("unexpected ST_BIND value: %d for \"%s\" in \"%s\"",
+ DL_WARN("Warning: unexpected ST_BIND value: %d for \"%s\" in \"%s\" (ignoring)",
ELF_ST_BIND(s->st_info), si->get_string(s->st_name), si->get_realpath());
}
diff --git a/linker/linker_utils.cpp b/linker/linker_utils.cpp
index 5bf88e7..661e7cb 100644
--- a/linker/linker_utils.cpp
+++ b/linker/linker_utils.cpp
@@ -209,31 +209,28 @@
const char* original_path = path.c_str();
if (realpath(original_path, resolved_path) != nullptr) {
struct stat s;
- if (stat(resolved_path, &s) == 0) {
- if (S_ISDIR(s.st_mode)) {
- resolved_paths->push_back(resolved_path);
- } else {
- DL_WARN("Warning: \"%s\" is not a directory (excluding from path)", resolved_path);
- continue;
- }
- } else {
- DL_WARN("Warning: cannot stat file \"%s\": %s", resolved_path, strerror(errno));
+ if (stat(resolved_path, &s) == -1) {
+ DL_WARN("Warning: cannot stat file \"%s\": %s (ignoring)", resolved_path, strerror(errno));
continue;
}
+ if (!S_ISDIR(s.st_mode)) {
+ DL_WARN("Warning: \"%s\" is not a directory (ignoring)", resolved_path);
+ continue;
+ }
+ resolved_paths->push_back(resolved_path);
} else {
+ std::string normalized_path;
+ if (!normalize_path(original_path, &normalized_path)) {
+ DL_WARN("Warning: unable to normalize \"%s\" (ignoring)", original_path);
+ continue;
+ }
+
std::string zip_path;
std::string entry_path;
-
- std::string normalized_path;
-
- if (!normalize_path(original_path, &normalized_path)) {
- DL_WARN("Warning: unable to normalize \"%s\"", original_path);
- continue;
- }
-
if (parse_zip_path(normalized_path.c_str(), &zip_path, &entry_path)) {
if (realpath(zip_path.c_str(), resolved_path) == nullptr) {
- DL_WARN("Warning: unable to resolve \"%s\": %s", zip_path.c_str(), strerror(errno));
+ DL_WARN("Warning: unable to resolve \"%s\": %s (ignoring)",
+ zip_path.c_str(), strerror(errno));
continue;
}
@@ -242,4 +239,3 @@
}
}
}
-
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index c40a35b..46f5097 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -1503,7 +1503,7 @@
"/libtest_invalid-rw_load_segment.so";
void* handle = dlopen(libpath.c_str(), RTLD_NOW);
ASSERT_TRUE(handle == nullptr);
- std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\": W + E load segments are not allowed";
+ std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\": W+E load segments are not allowed";
ASSERT_STREQ(expected_dlerror.c_str(), dlerror());
}
diff --git a/tests/grp_pwd_test.cpp b/tests/grp_pwd_test.cpp
index a905fae..12d4b7f 100644
--- a/tests/grp_pwd_test.cpp
+++ b/tests/grp_pwd_test.cpp
@@ -115,10 +115,14 @@
#else // !defined(__BIONIC__)
-static void check_get_passwd(const char* /* username */, uid_t /* uid */, uid_type_t /* uid_type */) {
+static void print_no_getpwnam_test_info() {
GTEST_LOG_(INFO) << "This test is about uid/username translation for Android, which does nothing on libc other than bionic.\n";
}
+static void check_get_passwd(const char* /* username */, uid_t /* uid */, uid_type_t /* uid_type */) {
+ print_no_getpwnam_test_info();
+}
+
#endif
TEST(pwd, getpwnam_system_id_root) {
@@ -238,6 +242,7 @@
}
TEST(pwd, getpwent_iterate) {
+#if defined(__BIONIC__)
passwd* pwd;
std::set<uid_t> uids;
@@ -263,6 +268,9 @@
endpwent();
expect_ids(uids);
+#else
+ print_no_getpwnam_test_info();
+#endif
}
static void check_group(const group* grp, const char* group_name, gid_t gid) {
@@ -477,6 +485,7 @@
}
TEST(grp, getgrent_iterate) {
+#if defined(__BIONIC__)
group* grp;
std::set<gid_t> gids;
@@ -493,4 +502,7 @@
endgrent();
expect_ids(gids);
+#else
+ print_no_getgrnam_test_info();
+#endif
}
diff --git a/tests/signal_test.cpp b/tests/signal_test.cpp
index d374c50..b37d06f 100644
--- a/tests/signal_test.cpp
+++ b/tests/signal_test.cpp
@@ -337,6 +337,214 @@
TestSigAction(sigaction64, sigaddset64, SIGRTMIN);
}
+static void ClearSignalMask() {
+ uint64_t sigset = 0;
+ if (syscall(__NR_rt_sigprocmask, SIG_SETMASK, &sigset, nullptr, sizeof(sigset)) != 0) {
+ abort();
+ }
+}
+
+static uint64_t GetSignalMask() {
+ uint64_t sigset;
+ if (syscall(__NR_rt_sigprocmask, SIG_SETMASK, nullptr, &sigset, sizeof(sigset)) != 0) {
+ abort();
+ }
+ return sigset;
+}
+
+enum class SignalMaskFunctionType {
+ RtAware,
+ RtNonaware,
+};
+
+#if defined(__LP64__) || !defined(__BIONIC__)
+constexpr SignalMaskFunctionType sigset_type = SignalMaskFunctionType::RtAware;
+#else
+constexpr SignalMaskFunctionType sigset_type = SignalMaskFunctionType::RtNonaware;
+#endif
+
+static void TestSignalMaskFiltered(uint64_t sigset, SignalMaskFunctionType type) {
+ for (int signo = 1; signo <= 64; ++signo) {
+ bool signal_blocked = sigset & (1ULL << (signo - 1));
+ if (signo == SIGKILL || signo == SIGSTOP) {
+ // SIGKILL and SIGSTOP shouldn't be blocked.
+ EXPECT_EQ(false, signal_blocked) << "signal " << signo;
+ } else if (signo < __SIGRTMIN) {
+ // Everything else should be blocked.
+ EXPECT_EQ(true, signal_blocked) << "signal " << signo;
+ } else if (signo >= __SIGRTMIN && signo < SIGRTMIN) {
+ // Reserved signals must not be blocked.
+ EXPECT_EQ(false, signal_blocked) << "signal " << signo;
+ } else if (type == SignalMaskFunctionType::RtAware) {
+ // Realtime signals should be blocked, unless we blocked using a non-rt aware function.
+ EXPECT_EQ(true, signal_blocked) << "signal " << signo;
+ }
+ }
+}
+
+static void TestSignalMaskFunction(std::function<void()> fn, SignalMaskFunctionType fn_type) {
+ ClearSignalMask();
+ fn();
+ TestSignalMaskFiltered(GetSignalMask(), fn_type);
+}
+
+TEST(signal, sigaction_filter) {
+ ClearSignalMask();
+ static uint64_t sigset;
+ struct sigaction sa = {};
+ sa.sa_handler = [](int) { sigset = GetSignalMask(); };
+ sigfillset(&sa.sa_mask);
+ sigaction(SIGUSR1, &sa, nullptr);
+ raise(SIGUSR1);
+ ASSERT_NE(0ULL, sigset);
+ TestSignalMaskFiltered(sigset, sigset_type);
+}
+
+TEST(signal, sigaction64_filter) {
+ ClearSignalMask();
+ static uint64_t sigset;
+ struct sigaction64 sa = {};
+ sa.sa_handler = [](int) { sigset = GetSignalMask(); };
+ sigfillset64(&sa.sa_mask);
+ sigaction64(SIGUSR1, &sa, nullptr);
+ raise(SIGUSR1);
+ ASSERT_NE(0ULL, sigset);
+ TestSignalMaskFiltered(sigset, SignalMaskFunctionType::RtAware);
+}
+
+TEST(signal, sigprocmask_setmask_filter) {
+ TestSignalMaskFunction(
+ []() {
+ sigset_t sigset_libc;
+ sigfillset(&sigset_libc);
+ ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &sigset_libc, nullptr));
+ },
+ sigset_type);
+}
+
+TEST(signal, sigprocmask64_setmask_filter) {
+ TestSignalMaskFunction(
+ []() {
+ sigset64_t sigset_libc;
+ sigfillset64(&sigset_libc);
+ ASSERT_EQ(0, sigprocmask64(SIG_SETMASK, &sigset_libc, nullptr));
+ },
+ SignalMaskFunctionType::RtAware);
+}
+
+TEST(signal, pthread_sigmask_setmask_filter) {
+ TestSignalMaskFunction(
+ []() {
+ sigset_t sigset_libc;
+ sigfillset(&sigset_libc);
+ ASSERT_EQ(0, pthread_sigmask(SIG_SETMASK, &sigset_libc, nullptr));
+ },
+ sigset_type);
+}
+
+TEST(signal, pthread_sigmask64_setmask_filter) {
+ TestSignalMaskFunction(
+ []() {
+ sigset64_t sigset_libc;
+ sigfillset64(&sigset_libc);
+ ASSERT_EQ(0, pthread_sigmask64(SIG_SETMASK, &sigset_libc, nullptr));
+ },
+ SignalMaskFunctionType::RtAware);
+}
+
+TEST(signal, sigprocmask_block_filter) {
+ TestSignalMaskFunction(
+ []() {
+ sigset_t sigset_libc;
+ sigfillset(&sigset_libc);
+ ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &sigset_libc, nullptr));
+ },
+ sigset_type);
+}
+
+TEST(signal, sigprocmask64_block_filter) {
+ TestSignalMaskFunction(
+ []() {
+ sigset64_t sigset_libc;
+ sigfillset64(&sigset_libc);
+ ASSERT_EQ(0, sigprocmask64(SIG_BLOCK, &sigset_libc, nullptr));
+ },
+ SignalMaskFunctionType::RtAware);
+}
+
+TEST(signal, pthread_sigmask_block_filter) {
+ TestSignalMaskFunction(
+ []() {
+ sigset_t sigset_libc;
+ sigfillset(&sigset_libc);
+ ASSERT_EQ(0, pthread_sigmask(SIG_BLOCK, &sigset_libc, nullptr));
+ },
+ sigset_type);
+}
+
+TEST(signal, pthread_sigmask64_block_filter) {
+ TestSignalMaskFunction(
+ []() {
+ sigset64_t sigset_libc;
+ sigfillset64(&sigset_libc);
+ ASSERT_EQ(0, pthread_sigmask64(SIG_BLOCK, &sigset_libc, nullptr));
+ },
+ SignalMaskFunctionType::RtAware);
+}
+
+// glibc filters out signals via sigfillset, not the actual underlying functions.
+TEST(signal, sigset_filter) {
+#if defined(__BIONIC__)
+ TestSignalMaskFunction(
+ []() {
+ for (int i = 1; i <= 64; ++i) {
+ sigset(i, SIG_HOLD);
+ }
+ },
+ SignalMaskFunctionType::RtAware);
+#endif
+}
+
+TEST(signal, sighold_filter) {
+#if defined(__BIONIC__)
+ TestSignalMaskFunction(
+ []() {
+ for (int i = 1; i <= 64; ++i) {
+ sighold(i);
+ }
+ },
+ SignalMaskFunctionType::RtAware);
+#endif
+}
+
+#if defined(__BIONIC__)
+// Not exposed via headers, but the symbols are available if you declare them yourself.
+extern "C" int sigblock(int);
+extern "C" int sigsetmask(int);
+#endif
+
+TEST(signal, sigblock_filter) {
+#if defined(__BIONIC__)
+ TestSignalMaskFunction(
+ []() {
+ int mask = ~0U;
+ ASSERT_EQ(0, sigblock(mask));
+ },
+ SignalMaskFunctionType::RtNonaware);
+#endif
+}
+
+TEST(signal, sigsetmask_filter) {
+#if defined(__BIONIC__)
+ TestSignalMaskFunction(
+ []() {
+ int mask = ~0U;
+ ASSERT_EQ(0, sigsetmask(mask));
+ },
+ SignalMaskFunctionType::RtNonaware);
+#endif
+}
+
TEST(signal, sys_signame) {
#if defined(__BIONIC__)
ASSERT_TRUE(sys_signame[0] == NULL);
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index 2b9935a..ff427a6 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -871,3 +871,54 @@
ASSERT_EQ(buf, ctime_r(&t, buf));
ASSERT_STREQ("Thu Jan 1 00:00:00 1970\n", buf);
}
+
+// https://issuetracker.google.com/37128336
+TEST(time, strftime_strptime_s) {
+ char buf[32];
+ const struct tm tm0 = { .tm_year = 1982-1900, .tm_mon = 0, .tm_mday = 1 };
+
+ setenv("TZ", "America/Los_Angeles", 1);
+ strftime(buf, sizeof(buf), "<%s>", &tm0);
+ EXPECT_STREQ("<378720000>", buf);
+
+ setenv("TZ", "UTC", 1);
+ strftime(buf, sizeof(buf), "<%s>", &tm0);
+ EXPECT_STREQ("<378691200>", buf);
+
+ struct tm tm;
+
+ setenv("TZ", "America/Los_Angeles", 1);
+ tzset();
+ memset(&tm, 0xff, sizeof(tm));
+ char* p = strptime("378720000x", "%s", &tm);
+ ASSERT_EQ('x', *p);
+ EXPECT_EQ(0, tm.tm_sec);
+ EXPECT_EQ(0, tm.tm_min);
+ EXPECT_EQ(0, tm.tm_hour);
+ EXPECT_EQ(1, tm.tm_mday);
+ EXPECT_EQ(0, tm.tm_mon);
+ EXPECT_EQ(82, tm.tm_year);
+ EXPECT_EQ(5, tm.tm_wday);
+ EXPECT_EQ(0, tm.tm_yday);
+ EXPECT_EQ(0, tm.tm_isdst);
+
+ setenv("TZ", "UTC", 1);
+ tzset();
+ memset(&tm, 0xff, sizeof(tm));
+ p = strptime("378691200x", "%s", &tm);
+ ASSERT_EQ('x', *p);
+ EXPECT_EQ(0, tm.tm_sec);
+ EXPECT_EQ(0, tm.tm_min);
+ EXPECT_EQ(0, tm.tm_hour);
+ EXPECT_EQ(1, tm.tm_mday);
+ EXPECT_EQ(0, tm.tm_mon);
+ EXPECT_EQ(82, tm.tm_year);
+ EXPECT_EQ(5, tm.tm_wday);
+ EXPECT_EQ(0, tm.tm_yday);
+ EXPECT_EQ(0, tm.tm_isdst);
+}
+
+TEST(time, strptime_s_nothing) {
+ struct tm tm;
+ ASSERT_EQ(nullptr, strptime("x", "%s", &tm));
+}