// Define the common source files for all the libc instances
// =========================================================
libc_common_src_files = [
+ "async_safe/async_safe_log.cpp",
"bionic/ether_aton.c",
"bionic/ether_ntoa.c",
"bionic/fts.c",
asflags: libc_common_flags,
conlyflags: ["-std=gnu99"],
cppflags: [],
- include_dirs: ["external/jemalloc/include"],
+ include_dirs: [
+ "bionic/libc/async_safe/include",
+ "external/jemalloc/include",
+ ],
stl: "none",
system_shared_libs: [],
"upstream-openbsd/lib/libc/string/strcat.c",
],
},
+ cortex_a73: {
+ exclude_srcs: [
+ "upstream-openbsd/lib/libc/string/memmove.c",
+ "upstream-openbsd/lib/libc/string/stpcpy.c",
+ "upstream-openbsd/lib/libc/string/strcat.c",
+ ],
+ },
denver: {
exclude_srcs: [
"upstream-openbsd/lib/libc/string/memmove.c",
"bionic/__strcpy_chk.cpp",
],
},
+ cortex_a73: {
+ srcs: [
+ "arch-arm/cortex-a7/bionic/memset.S",
+
+ "arch-arm/denver/bionic/memcpy.S",
+ "arch-arm/denver/bionic/memmove.S",
+ "arch-arm/denver/bionic/__strcat_chk.S",
+ "arch-arm/denver/bionic/__strcpy_chk.S",
+
+ "arch-arm/krait/bionic/strcmp.S",
+
+ "arch-arm/cortex-a15/bionic/stpcpy.S",
+ "arch-arm/cortex-a15/bionic/strcat.S",
+ "arch-arm/cortex-a15/bionic/strcpy.S",
+ "arch-arm/cortex-a15/bionic/strlen.S",
+ ],
+ exclude_srcs: [
+ "arch-arm/generic/bionic/memcpy.S",
+ "arch-arm/generic/bionic/memset.S",
+ "arch-arm/generic/bionic/strcmp.S",
+ "arch-arm/generic/bionic/strcpy.S",
+ "arch-arm/generic/bionic/strlen.c",
+ "bionic/__strcat_chk.cpp",
+ "bionic/__strcpy_chk.cpp",
+ ],
+ },
denver: {
srcs: [
"arch-arm/denver/bionic/memcpy.S",
"arch-arm64/generic/bionic/memmove.S",
],
},
+ cortex_a73: {
+ srcs: [
+ "arch-arm64/cortex-a53/bionic/memmove.S",
+ ],
+ exclude_srcs: [
+ "arch-arm64/generic/bionic/memmove.S",
+ ],
+ },
},
mips: {
"bionic/__libc_current_sigrtmax.cpp",
"bionic/__libc_current_sigrtmin.cpp",
"bionic/libc_init_common.cpp",
- "bionic/libc_logging.cpp",
"bionic/libgen.cpp",
"bionic/link.cpp",
"bionic/locale.cpp",
"bionic/libc_init_static.cpp",
],
cflags: ["-DLIBC_STATIC"],
- whole_static_libs: ["libc_init_static", "libjemalloc"],
+ whole_static_libs: ["libc_init_static"],
},
shared: {
srcs: [
"bionic/NetdClient.cpp",
"arch-common/bionic/crtend_so.S",
],
- whole_static_libs: ["libjemalloc"],
},
required: ["tzdata"],
// you wanted!
shared_libs: ["libdl"],
- whole_static_libs: ["libc_common"],
+ whole_static_libs: ["libc_common", "libjemalloc"],
nocrt: true,
}
// ========================================================
-// libc_logging.a
-// ========================================================
-cc_library_static {
- defaults: ["libc_defaults"],
-
- srcs: [
- "bionic/libc_logging.cpp",
- ],
-
- name: "libc_logging",
-}
-
-// ========================================================
// libstdc++.so + libstdc++.a
// ========================================================
cc_library {
],
name: "libstdc++",
system_shared_libs: ["libc"],
- shared: {
- static_libs: ["libc_logging"],
- },
+ static_libs: ["libasync_safe"],
//TODO (dimitry): This is to work around b/24465209. Remove after root cause is fixed
arch: {
}
ndk_headers {
- name: "libc_android",
+ name: "libc_kernel_android_uapi_linux",
from: "kernel/android/uapi/linux",
to: "linux",
srcs: ["kernel/android/uapi/linux/**/*.h"],
}
ndk_headers {
+ name: "libc_kernel_android_scsi",
+ from: "kernel/android/scsi",
+ to: "scsi",
+ srcs: ["kernel/android/scsi/**/*.h"],
+ license: "NOTICE",
+}
+
+ndk_headers {
name: "libc_asm_arm",
from: "kernel/uapi/asm-arm",
to: "arm-linux-androideabi",
- Copyright (c) 2014, Linaro Limited
- All rights reserved.
+ Copyright (c) 2014, ARM Limited
+ All rights Reserved.
+ Copyright (c) 2014, Linaro Ltd.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* 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.
- * Neither the name of the Linaro nor the
- names of its contributors may be used to endorse or promote products
- derived from this software without specific prior written permission.
+ * Neither the name of the company nor the names of its contributors
+ may be used to endorse or promote products derived from this
+ software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-------------------------------------------------------------------
- strchr - find a character in a string
-
- Copyright (c) 2014, ARM Limited
- All rights Reserved.
- Copyright (c) 2014, Linaro Ltd.
+ Copyright (c) 2014, Linaro Limited
+ 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 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.
- * Neither the name of the company nor the names of its contributors
- may be used to endorse or promote products derived from this
- software without specific prior written permission.
+ * Neither the name of the Linaro nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-------------------------------------------------------------------
-memchr - find a character in a memory zone
-
-Copyright (c) 2014, ARM Limited
-All rights Reserved.
-Copyright (c) 2014, Linaro Ltd.
-
-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.
- * Neither the name of the company nor the names of its contributors
- may be used to endorse or promote products derived from this
- software without specific prior written permission.
-
-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
-HOLDER 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.
-
--------------------------------------------------------------------
-
int ___fchmodat:fchmodat(int, const char*, mode_t) all
int fchownat(int, const char*, uid_t, gid_t, int) all
int fstatat64|fstatat:fstatat64(int, const char*, struct stat*, int) arm,mips,x86
-int fstatat64|fstatat:newfstatat(int, const char*, struct stat*, int) arm64,x86_64
+int fstatat64|fstatat:newfstatat(int, const char*, struct stat*, int) arm64,mips64,x86_64
int linkat(int, const char*, int, const char*, int) all
int mkdirat(int, const char*, mode_t) all
int mknodat(int, const char*, mode_t, dev_t) all
int __statfs:statfs(const char*, struct statfs*) arm64,mips64,x86_64
int fstat64|fstat:fstat64(int, struct stat*) arm,mips,x86
-int fstat64|fstat:fstat(int, struct stat*) arm64,x86_64
+int fstat64|fstat:fstat(int, struct stat*) arm64,mips64,x86_64
# file system
int chdir(const char*) all
int cacheflush:__ARM_NR_cacheflush(long start, long end, long flags) arm
# MIPS-specific
-int _flush_cache:cacheflush(char* addr, const int nbytes, const int op) mips
+int _flush_cache:cacheflush(char* addr, const int nbytes, const int op) mips,mips64
int __set_tls:set_thread_area(void*) mips,mips64
# x86-specific
#include <sys/types.h>
#include <stdio.h>
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
/*
* This source file should only be included by libc.so, its purpose is
*/
static char const warning[] = "WARNING: generic atexit() called from legacy shared library\n";
- __libc_format_log(ANDROID_LOG_WARN, "libc", warning);
+ async_safe_format_log(ANDROID_LOG_WARN, "libc", warning);
fprintf(stderr, warning);
return (__cxa_atexit((void (*)(void *))func, NULL, NULL));
/*
- * memchr - find a character in a memory zone
*
- * Copyright (c) 2014, ARM Limited
- * All rights Reserved.
- * Copyright (c) 2014, Linaro Ltd.
- *
- * 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.
- * * Neither the name of the company nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * 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
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
+ Copyright (c) 2014, ARM Limited
+ All rights Reserved.
+ Copyright (c) 2014, Linaro Ltd.
+
+ 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.
+ * Neither the name of the company nor the names of its contributors
+ may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+ 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
+ HOLDER 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.
+*/
/* Assumptions:
*
#define tmp1w w5
#define tmp2 x6
#define tmp2w w6
-#define zva_len x5
+#define zva_len x7
#define zva_lenw w7
#define L(l) .L ## l
/*
- strchr - find a character in a string
-
+ *
Copyright (c) 2014, ARM Limited
All rights Reserved.
Copyright (c) 2014, Linaro Ltd.
#include <unistd.h>
#include <sys/cachectl.h>
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
// Linux historically defines a cacheflush(3) routine for MIPS
// with this signature:
// It looks like this is really a MIPS-style cacheflush call.
static bool warned = false;
if (!warned) {
- __libc_format_log(ANDROID_LOG_WARN, "libc", "cacheflush called with (start,len) instead of (start,end)");
+ async_safe_format_log(ANDROID_LOG_WARN, "libc",
+ "cacheflush called with (start,len) instead of (start,end)");
warned = true;
}
end += start;
#include <asm/ldt.h>
-extern "C" int __set_thread_area(struct user_desc*);
+extern "C" int __set_thread_area(user_desc*);
-__LIBC_HIDDEN__ void __init_user_desc(struct user_desc* result, bool allocate, void* base_addr) {
+__LIBC_HIDDEN__ void __init_user_desc(user_desc* result, bool allocate, void* base_addr) {
if (allocate) {
// Let the kernel choose.
result->entry_number = -1;
}
extern "C" __LIBC_HIDDEN__ int __set_tls(void* ptr) {
- struct user_desc tls_descriptor;
+ user_desc tls_descriptor = {};
__init_user_desc(&tls_descriptor, true, ptr);
int rc = __set_thread_area(&tls_descriptor);
--- /dev/null
+// ========================================================
+// libasync_safe.a
+// ========================================================
+cc_library_static {
+ defaults: ["libc_defaults"],
+ srcs: [
+ "async_safe_log.cpp",
+ ],
+
+ name: "libasync_safe",
+
+ include_dirs: ["bionic/libc"],
+
+ export_include_dirs: ["include"],
+}
* SUCH DAMAGE.
*/
-// Relative paths so we can #include this .cpp file for testing.
-#include "../private/CachedProperty.h"
-#include "../private/libc_logging.h"
-#include "../private/ScopedPthreadMutexLocker.h"
-
-#include <android/set_abort_message.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <time.h>
#include <unistd.h>
+#include <android/set_abort_message.h>
+#include <async_safe/log.h>
+
+#include "private/CachedProperty.h"
+#include "private/ScopedPthreadMutexLocker.h"
+
// Must be kept in sync with frameworks/base/core/java/android/util/EventLog.java.
enum AndroidEventLogType {
- EVENT_TYPE_INT = 0,
- EVENT_TYPE_LONG = 1,
- EVENT_TYPE_STRING = 2,
- EVENT_TYPE_LIST = 3,
- EVENT_TYPE_FLOAT = 4,
+ EVENT_TYPE_INT = 0,
+ EVENT_TYPE_LONG = 1,
+ EVENT_TYPE_STRING = 2,
+ EVENT_TYPE_LIST = 3,
+ EVENT_TYPE_FLOAT = 4,
};
struct BufferOutputStream {
pos_[0] = '\0';
}
- ~BufferOutputStream() {
- }
+ ~BufferOutputStream() {}
void Send(const char* data, int len) {
if (len < 0) {
struct FdOutputStream {
public:
- explicit FdOutputStream(int fd) : total(0), fd_(fd) {
- }
+ explicit FdOutputStream(int fd) : total(0), fd_(fd) {}
void Send(const char* data, int len) {
if (len < 0) {
*
* NOTE: Does *not* handle a sign prefix.
*/
-static unsigned parse_decimal(const char *format, int *ppos) {
- const char* p = format + *ppos;
- unsigned result = 0;
-
- for (;;) {
- int ch = *p;
- unsigned d = static_cast<unsigned>(ch - '0');
+static unsigned parse_decimal(const char* format, int* ppos) {
+ const char* p = format + *ppos;
+ unsigned result = 0;
- if (d >= 10U) {
- break;
- }
+ for (;;) {
+ int ch = *p;
+ unsigned d = static_cast<unsigned>(ch - '0');
- result = result*10 + d;
- p++;
+ if (d >= 10U) {
+ break;
}
- *ppos = p - format;
- return result;
+
+ result = result * 10 + d;
+ p++;
+ }
+ *ppos = p - format;
+ return result;
}
// Writes number 'value' in base 'base' into buffer 'buf' of size 'buf_size' bytes.
/* Perform formatted output to an output target 'o' */
template <typename Out>
static void out_vformat(Out& o, const char* format, va_list args) {
- int nn = 0;
+ int nn = 0;
+
+ for (;;) {
+ int mm;
+ int padZero = 0;
+ int padLeft = 0;
+ char sign = '\0';
+ int width = -1;
+ int prec = -1;
+ size_t bytelen = sizeof(int);
+ int slen;
+ char buffer[32]; /* temporary buffer used to format numbers */
+
+ char c;
+
+ /* first, find all characters that are not 0 or '%' */
+ /* then send them to the output directly */
+ mm = nn;
+ do {
+ c = format[mm];
+ if (c == '\0' || c == '%') break;
+ mm++;
+ } while (1);
+
+ if (mm > nn) {
+ o.Send(format + nn, mm - nn);
+ nn = mm;
+ }
+
+ /* is this it ? then exit */
+ if (c == '\0') break;
+ /* nope, we are at a '%' modifier */
+ nn++; // skip it
+
+ /* parse flags */
for (;;) {
- int mm;
- int padZero = 0;
- int padLeft = 0;
- char sign = '\0';
- int width = -1;
- int prec = -1;
- size_t bytelen = sizeof(int);
- int slen;
- char buffer[32]; /* temporary buffer used to format numbers */
-
- char c;
-
- /* first, find all characters that are not 0 or '%' */
- /* then send them to the output directly */
- mm = nn;
- do {
- c = format[mm];
- if (c == '\0' || c == '%')
- break;
- mm++;
- } while (1);
-
- if (mm > nn) {
- o.Send(format+nn, mm-nn);
- nn = mm;
- }
+ c = format[nn++];
+ if (c == '\0') { /* single trailing '%' ? */
+ c = '%';
+ o.Send(&c, 1);
+ return;
+ } else if (c == '0') {
+ padZero = 1;
+ continue;
+ } else if (c == '-') {
+ padLeft = 1;
+ continue;
+ } else if (c == ' ' || c == '+') {
+ sign = c;
+ continue;
+ }
+ break;
+ }
- /* is this it ? then exit */
- if (c == '\0')
- break;
-
- /* nope, we are at a '%' modifier */
- nn++; // skip it
-
- /* parse flags */
- for (;;) {
- c = format[nn++];
- if (c == '\0') { /* single trailing '%' ? */
- c = '%';
- o.Send(&c, 1);
- return;
- }
- else if (c == '0') {
- padZero = 1;
- continue;
- }
- else if (c == '-') {
- padLeft = 1;
- continue;
- }
- else if (c == ' ' || c == '+') {
- sign = c;
- continue;
- }
- break;
- }
+ /* parse field width */
+ if ((c >= '0' && c <= '9')) {
+ nn--;
+ width = static_cast<int>(parse_decimal(format, &nn));
+ c = format[nn++];
+ }
- /* parse field width */
- if ((c >= '0' && c <= '9')) {
- nn --;
- width = static_cast<int>(parse_decimal(format, &nn));
- c = format[nn++];
- }
+ /* parse precision */
+ if (c == '.') {
+ prec = static_cast<int>(parse_decimal(format, &nn));
+ c = format[nn++];
+ }
- /* parse precision */
- if (c == '.') {
- prec = static_cast<int>(parse_decimal(format, &nn));
- c = format[nn++];
+ /* length modifier */
+ switch (c) {
+ case 'h':
+ bytelen = sizeof(short);
+ if (format[nn] == 'h') {
+ bytelen = sizeof(char);
+ nn += 1;
+ }
+ c = format[nn++];
+ break;
+ case 'l':
+ bytelen = sizeof(long);
+ if (format[nn] == 'l') {
+ bytelen = sizeof(long long);
+ nn += 1;
}
+ c = format[nn++];
+ break;
+ case 'z':
+ bytelen = sizeof(size_t);
+ c = format[nn++];
+ break;
+ case 't':
+ bytelen = sizeof(ptrdiff_t);
+ c = format[nn++];
+ break;
+ default:;
+ }
- /* length modifier */
- switch (c) {
- case 'h':
- bytelen = sizeof(short);
- if (format[nn] == 'h') {
- bytelen = sizeof(char);
- nn += 1;
- }
- c = format[nn++];
- break;
- case 'l':
- bytelen = sizeof(long);
- if (format[nn] == 'l') {
- bytelen = sizeof(long long);
- nn += 1;
- }
- c = format[nn++];
- break;
- case 'z':
- bytelen = sizeof(size_t);
- c = format[nn++];
- break;
- case 't':
- bytelen = sizeof(ptrdiff_t);
- c = format[nn++];
- break;
+ /* conversion specifier */
+ const char* str = buffer;
+ if (c == 's') {
+ /* string */
+ str = va_arg(args, const char*);
+ if (str == NULL) {
+ str = "(null)";
+ }
+ } else if (c == 'c') {
+ /* character */
+ /* NOTE: char is promoted to int when passed through the stack */
+ buffer[0] = static_cast<char>(va_arg(args, int));
+ buffer[1] = '\0';
+ } else if (c == 'p') {
+ uint64_t value = reinterpret_cast<uintptr_t>(va_arg(args, void*));
+ buffer[0] = '0';
+ buffer[1] = 'x';
+ format_integer(buffer + 2, sizeof(buffer) - 2, value, 'x');
+ } else if (c == 'd' || c == 'i' || c == 'o' || c == 'u' || c == 'x' || c == 'X') {
+ /* integers - first read value from stack */
+ uint64_t value;
+ int is_signed = (c == 'd' || c == 'i' || c == 'o');
+
+ /* NOTE: int8_t and int16_t are promoted to int when passed
+ * through the stack
+ */
+ switch (bytelen) {
+ case 1:
+ value = static_cast<uint8_t>(va_arg(args, int));
+ break;
+ case 2:
+ value = static_cast<uint16_t>(va_arg(args, int));
+ break;
+ case 4:
+ value = va_arg(args, uint32_t);
+ break;
+ case 8:
+ value = va_arg(args, uint64_t);
+ break;
default:
- ;
- }
+ return; /* should not happen */
+ }
- /* conversion specifier */
- const char* str = buffer;
- if (c == 's') {
- /* string */
- str = va_arg(args, const char*);
- if (str == NULL) {
- str = "(null)";
- }
- } else if (c == 'c') {
- /* character */
- /* NOTE: char is promoted to int when passed through the stack */
- buffer[0] = static_cast<char>(va_arg(args, int));
- buffer[1] = '\0';
- } else if (c == 'p') {
- uint64_t value = reinterpret_cast<uintptr_t>(va_arg(args, void*));
- buffer[0] = '0';
- buffer[1] = 'x';
- format_integer(buffer + 2, sizeof(buffer) - 2, value, 'x');
- } else if (c == 'd' || c == 'i' || c == 'o' || c == 'u' || c == 'x' || c == 'X') {
- /* integers - first read value from stack */
- uint64_t value;
- int is_signed = (c == 'd' || c == 'i' || c == 'o');
-
- /* NOTE: int8_t and int16_t are promoted to int when passed
- * through the stack
- */
- switch (bytelen) {
- case 1: value = static_cast<uint8_t>(va_arg(args, int)); break;
- case 2: value = static_cast<uint16_t>(va_arg(args, int)); break;
- case 4: value = va_arg(args, uint32_t); break;
- case 8: value = va_arg(args, uint64_t); break;
- default: return; /* should not happen */
- }
-
- /* sign extension, if needed */
- if (is_signed) {
- int shift = 64 - 8*bytelen;
- value = static_cast<uint64_t>((static_cast<int64_t>(value << shift)) >> shift);
- }
-
- /* format the number properly into our buffer */
- format_integer(buffer, sizeof(buffer), value, c);
- } else if (c == '%') {
- buffer[0] = '%';
- buffer[1] = '\0';
- } else {
- __assert(__FILE__, __LINE__, "conversion specifier unsupported");
- }
+ /* sign extension, if needed */
+ if (is_signed) {
+ int shift = 64 - 8 * bytelen;
+ value = static_cast<uint64_t>((static_cast<int64_t>(value << shift)) >> shift);
+ }
- /* if we are here, 'str' points to the content that must be
- * outputted. handle padding and alignment now */
+ /* format the number properly into our buffer */
+ format_integer(buffer, sizeof(buffer), value, c);
+ } else if (c == '%') {
+ buffer[0] = '%';
+ buffer[1] = '\0';
+ } else {
+ __assert(__FILE__, __LINE__, "conversion specifier unsupported");
+ }
- slen = strlen(str);
+ /* if we are here, 'str' points to the content that must be
+ * outputted. handle padding and alignment now */
- if (sign != '\0' || prec != -1) {
- __assert(__FILE__, __LINE__, "sign/precision unsupported");
- }
+ slen = strlen(str);
- if (slen < width && !padLeft) {
- char padChar = padZero ? '0' : ' ';
- SendRepeat(o, padChar, width - slen);
- }
+ if (sign != '\0' || prec != -1) {
+ __assert(__FILE__, __LINE__, "sign/precision unsupported");
+ }
- o.Send(str, slen);
+ if (slen < width && !padLeft) {
+ char padChar = padZero ? '0' : ' ';
+ SendRepeat(o, padChar, width - slen);
+ }
- if (slen < width && padLeft) {
- char padChar = padZero ? '0' : ' ';
- SendRepeat(o, padChar, width - slen);
- }
+ o.Send(str, slen);
+
+ if (slen < width && padLeft) {
+ char padChar = padZero ? '0' : ' ';
+ SendRepeat(o, padChar, width - slen);
}
+ }
}
-int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) {
+int async_safe_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) {
BufferOutputStream os(buffer, buffer_size);
va_list args;
va_start(args, format);
return os.total;
}
-int __libc_format_buffer_va_list(char* buffer, size_t buffer_size, const char* format,
- va_list args) {
+int async_safe_format_buffer_va_list(char* buffer, size_t buffer_size, const char* format,
+ va_list args) {
BufferOutputStream os(buffer, buffer_size);
out_vformat(os, format, args);
return os.total;
}
-int __libc_format_fd(int fd, const char* format, ...) {
+int async_safe_format_fd(int fd, const char* format, ...) {
FdOutputStream os(fd);
va_list args;
va_start(args, format);
return os.total;
}
-static int __libc_write_stderr(const char* tag, const char* msg) {
+static int write_stderr(const char* tag, const char* msg) {
iovec vec[4];
vec[0].iov_base = const_cast<char*>(tag);
vec[0].iov_len = strlen(tag);
return result;
}
-static int __libc_open_log_socket() {
+static int open_log_socket() {
// ToDo: Ideally we want this to fail if the gid of the current
// process is AID_LOGD, but will have to wait until we have
// registered this in private/android_filesystem_config.h. We have
}
union {
- struct sockaddr addr;
+ struct sockaddr addr;
struct sockaddr_un addrUn;
} u;
memset(&u, 0, sizeof(u));
return log_fd;
}
-static clockid_t __android_log_clockid() {
+static clockid_t log_clockid() {
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
ScopedPthreadMutexLocker locker(&mutex);
return (tolower(ch) == 'm') ? CLOCK_MONOTONIC : CLOCK_REALTIME;
}
-struct log_time { // Wire format
+struct log_time { // Wire format
uint32_t tv_sec;
uint32_t tv_nsec;
};
-int __libc_write_log(int priority, const char* tag, const char* msg) {
- int main_log_fd = __libc_open_log_socket();
+int async_safe_write_log(int priority, const char* tag, const char* msg) {
+ int main_log_fd = open_log_socket();
if (main_log_fd == -1) {
// Try stderr instead.
- return __libc_write_stderr(tag, msg);
+ return write_stderr(tag, msg);
}
iovec vec[6];
vec[1].iov_base = &tid;
vec[1].iov_len = sizeof(tid);
timespec ts;
- clock_gettime(__android_log_clockid(), &ts);
+ clock_gettime(log_clockid(), &ts);
log_time realtime_ts;
realtime_ts.tv_sec = ts.tv_sec;
realtime_ts.tv_nsec = ts.tv_nsec;
return result;
}
-int __libc_format_log_va_list(int priority, const char* tag, const char* format, va_list args) {
+int async_safe_format_log_va_list(int priority, const char* tag, const char* format, va_list args) {
char buffer[1024];
BufferOutputStream os(buffer, sizeof(buffer));
out_vformat(os, format, args);
- return __libc_write_log(priority, tag, buffer);
+ return async_safe_write_log(priority, tag, buffer);
}
-int __libc_format_log(int priority, const char* tag, const char* format, ...) {
+int async_safe_format_log(int priority, const char* tag, const char* format, ...) {
va_list args;
va_start(args, format);
- int result = __libc_format_log_va_list(priority, tag, format, args);
+ int result = async_safe_format_log_va_list(priority, tag, format, args);
va_end(args);
return result;
}
-static void __libc_fatal_va_list(const char* prefix, const char* format, va_list args) {
+void async_safe_fatal_va_list(const char* prefix, const char* format, va_list args) {
char msg[1024];
BufferOutputStream os(msg, sizeof(msg));
// Log to stderr for the benefit of "adb shell" users and gtests.
struct iovec iov[2] = {
- { msg, os.total },
- { const_cast<char*>("\n"), 1 },
+ {msg, os.total}, {const_cast<char*>("\n"), 1},
};
TEMP_FAILURE_RETRY(writev(2, iov, 2));
// Log to the log for the benefit of regular app developers (whose stdout and stderr are closed).
- __libc_write_log(ANDROID_LOG_FATAL, "libc", msg);
+ async_safe_write_log(ANDROID_LOG_FATAL, "libc", msg);
android_set_abort_message(msg);
}
-void __libc_fatal(const char* fmt, ...) {
- va_list args;
- va_start(args, fmt);
- __libc_fatal_va_list(nullptr, fmt, args);
- va_end(args);
- abort();
-}
-
-void __fortify_fatal(const char* fmt, ...) {
+void async_safe_fatal(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
- __libc_fatal_va_list("FORTIFY", fmt, args);
+ async_safe_fatal_va_list(nullptr, fmt, args);
va_end(args);
abort();
}
* SUCH DAMAGE.
*/
-#ifndef _LIBC_LOGGING_H
-#define _LIBC_LOGGING_H
+#ifndef _ASYNC_SAFE_LOG_LOG_H
+#define _ASYNC_SAFE_LOG_LOG_H
#include <sys/cdefs.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
+// These functions do not allocate memory to send data to the log.
+
__BEGIN_DECLS
enum {
};
// Formats a message to the log (priority 'fatal'), then aborts.
-__noreturn void __libc_fatal(const char* _Nonnull, ...) __printflike(1, 2);
+__noreturn void async_safe_fatal(const char* _Nonnull fmt, ...) __printflike(1, 2);
-// Formats a message to the log (priority 'fatal'), prefixed by "FORTIFY: ", then aborts.
-__noreturn void __fortify_fatal(const char* _Nonnull, ...) __printflike(1, 2);
+// This function does return, so callers that want to abort, must do so themselves.
+#if defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+void async_safe_fatal_va_list(
+ const char* _Nullable prefix, const char* _Nonnull fmt, va_list);
+#else // defined(__mips__) || defined(__i386__)
+void async_safe_fatal_va_list(
+ const char* _Nullable prefix, const char* _Nonnull fmt, va_list _Nonnull);
+#endif
//
// Formatting routines for the C library's internal debugging.
// These are async signal safe, so they can be called from signal handlers.
//
-int __libc_format_buffer(char* _Nonnull buf, size_t size, const char* _Nonnull fmt, ...) __printflike(3, 4);
+int async_safe_format_buffer(char* _Nonnull buf, size_t size, const char* _Nonnull fmt, ...) __printflike(3, 4);
#if defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
-int __libc_format_buffer_va_list(char* _Nonnull buffer, size_t buffer_size,
- const char* _Nonnull format, va_list args);
+int async_safe_format_buffer_va_list(
+ char* _Nonnull buffer, size_t buffer_size, const char* _Nonnull format, va_list args);
#else // defined(__mips__) || defined(__i386__)
-int __libc_format_buffer_va_list(char* _Nonnull buffer, size_t buffer_size,
- const char* _Nonnull format, va_list _Nonnull args);
+int async_safe_format_buffer_va_list(
+ char* _Nonnull buffer, size_t buffer_size, const char* _Nonnull format, va_list _Nonnull args);
#endif
-int __libc_format_fd(int fd, const char* _Nonnull format , ...) __printflike(2, 3);
-int __libc_format_log(int pri, const char* _Nonnull tag, const char* _Nonnull fmt, ...) __printflike(3, 4);
+int async_safe_format_fd(int fd, const char* _Nonnull format , ...) __printflike(2, 3);
+int async_safe_format_log(int pri, const char* _Nonnull tag, const char* _Nonnull fmt, ...) __printflike(3, 4);
#if defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
-int __libc_format_log_va_list(int pri, const char* _Nonnull tag, const char* _Nonnull fmt, va_list ap);
+int async_safe_format_log_va_list(
+ int pri, const char* _Nonnull tag, const char* _Nonnull fmt, va_list ap);
#else // defined(__mips__) || defined(__i386__)
-int __libc_format_log_va_list(int pri, const char* _Nonnull tag, const char* _Nonnull fmt, va_list _Nonnull ap);
+int async_safe_format_log_va_list(
+ int pri, const char* _Nonnull tag, const char* _Nonnull fmt, va_list _Nonnull ap);
#endif
-int __libc_write_log(int pri, const char* _Nonnull tag, const char* _Nonnull msg);
+int async_safe_write_log(int pri, const char* _Nonnull tag, const char* _Nonnull msg);
#define CHECK(predicate) \
do { \
if (!(predicate)) { \
- __libc_fatal("%s:%d: %s CHECK '" #predicate "' failed", \
+ async_safe_fatal("%s:%d: %s CHECK '" #predicate "' failed", \
__FILE__, __LINE__, __FUNCTION__); \
} \
} while(0)
#error NetdClient.cpp should NOT be included in static libc builds.
#endif
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
+
#include "private/NetdClientDispatch.h"
#include <dlfcn.h>
extern "C" __LIBC_HIDDEN__ void netdClientInit() {
if (pthread_once(&netdClientInitOnce, netdClientInitImpl)) {
- __libc_format_log(ANDROID_LOG_ERROR, "netdClient", "Failed to initialize netd_client");
+ async_safe_format_log(ANDROID_LOG_ERROR, "netdClient", "Failed to initialize netd_client");
}
}
* limitations under the License.
*/
-#include <private/libc_logging.h>
+#include <async_safe/log.h>
extern "C" void __cxa_pure_virtual() {
- __libc_fatal("Pure virtual function called. Are you calling virtual methods from a destructor?");
+ async_safe_fatal("Pure virtual function called. Are you calling virtual methods from a destructor?");
}
#include <signal.h>
int __libc_current_sigrtmax(void) {
+ // If you change this, also change __ndk_legacy___libc_current_sigrtmax
+ // in <android/legacy_signal_inlines.h> to match.
return __SIGRTMAX;
}
// __SIGRTMIN + 3 is reserved for triggering native stack dumps.
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;
}
#include <stdlib.h>
+#include <async_safe/log.h>
+
#include "private/bionic_ssp.h"
-#include "private/libc_logging.h"
void __stack_chk_fail() {
- __libc_fatal("stack corruption detected (-fstack-protector)");
+ async_safe_fatal("stack corruption detected (-fstack-protector)");
}
#include <signal.h>
#include <stdlib.h>
+#include <sys/syscall.h>
#include <unistd.h>
void abort() {
+ // Protect ourselves against stale cached PID/TID values by fetching them via syscall.
+ // http://b/37769298
+ pid_t pid = syscall(__NR_getpid);
+ pid_t tid = syscall(__NR_gettid);
+
// Don't block SIGABRT to give any signal handler a chance; we ignore
// any errors -- X311J doesn't allow abort to return anyway.
sigset_t mask;
sigdelset(&mask, SIGABRT);
sigprocmask(SIG_SETMASK, &mask, NULL);
- tgkill(getpid(), gettid(), SIGABRT);
+ // Use tgkill directly instead of raise, to avoid inserting spurious stack frames.
+ tgkill(pid, tid, SIGABRT);
// If SIGABRT ignored, or caught and the handler returns,
// remove the SIGABRT signal handler and raise SIGABRT again.
sigaction(SIGABRT, &sa, &sa);
sigprocmask(SIG_SETMASK, &mask, NULL);
- tgkill(getpid(), gettid(), SIGABRT);
+ tgkill(pid, tid, SIGABRT);
// If we get this far, just exit.
_exit(127);
#include <assert.h>
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
void __assert(const char* file, int line, const char* failed_expression) {
- __libc_fatal("%s:%d: assertion \"%s\" failed", file, line, failed_expression);
+ async_safe_fatal("%s:%d: assertion \"%s\" failed", file, line, failed_expression);
}
void __assert2(const char* file, int line, const char* function, const char* failed_expression) {
- __libc_fatal("%s:%d: %s: assertion \"%s\" failed", file, line, function, failed_expression);
+ async_safe_fatal("%s:%d: %s: assertion \"%s\" failed", file, line, function, failed_expression);
}
extern "C" __LIBC_HIDDEN__ void longjmperror() {
- __libc_fatal("longjmp botch");
+ async_safe_fatal("longjmp botch");
}
#include <syscall.h>
#include <unistd.h>
+#include <async_safe/log.h>
+
#include "private/KernelArgumentBlock.h"
-#include "private/libc_logging.h"
bool __libc_arc4random_has_unlimited_entropy() {
static bool have_urandom = access("/dev/urandom", R_OK) == 0;
static size_t at_random_bytes_consumed = 0;
if (at_random_bytes_consumed + n > 16) {
- __libc_fatal("ran out of AT_RANDOM bytes, have %zu, requested %zu",
- 16 - at_random_bytes_consumed, n);
+ async_safe_fatal("ran out of AT_RANDOM bytes, have %zu, requested %zu",
+ 16 - at_random_bytes_consumed, n);
}
memcpy(buf, reinterpret_cast<char*>(args.getauxval(AT_RANDOM)) + at_random_bytes_consumed, n);
#include "private/bionic_lock.h"
#include "private/bionic_systrace.h"
#include "private/CachedProperty.h"
-#include "private/libc_logging.h"
#include <cutils/trace.h> // For ATRACE_TAG_BIONIC.
int execl(const char* name, const char* arg, ...) {
va_list ap;
va_start(ap, arg);
- return __execl(name, arg, kIsExecL, ap);
+ int result = __execl(name, arg, kIsExecL, ap);
+ va_end(ap);
+ return result;
}
int execle(const char* name, const char* arg, ...) {
va_list ap;
va_start(ap, arg);
- return __execl(name, arg, kIsExecLE, ap);
+ int result = __execl(name, arg, kIsExecLE, ap);
+ va_end(ap);
+ return result;
}
int execlp(const char* name, const char* arg, ...) {
va_list ap;
va_start(ap, arg);
- return __execl(name, arg, kIsExecLP, ap);
+ int result = __execl(name, arg, kIsExecLP, ap);
+ va_end(ap);
+ return result;
}
int execv(const char* name, char* const* argv) {
#include "private/bionic_macros.h"
#include "private/grp_pwd.h"
#include "private/ErrnoRestorer.h"
-#include "private/libc_logging.h"
// Generated android_ids array
#include "generated_android_ids.h"
#include <pthread.h>
#include <stdlib.h>
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
// Allowed icu4c version numbers are in the range [44, 999].
// Gingerbread's icu4c 4.4 is the minimum supported ICU version.
free(namelist);
if (max_version == -1 || max_version < ICUDATA_VERSION_MIN) {
- __libc_write_log(ANDROID_LOG_ERROR, "bionic-icu", "couldn't find an ICU .dat file");
+ async_safe_write_log(ANDROID_LOG_ERROR, "bionic-icu", "couldn't find an ICU .dat file");
return false;
}
g_libicuuc_handle = dlopen("libicuuc.so", RTLD_LOCAL);
if (g_libicuuc_handle == nullptr) {
- __libc_format_log(ANDROID_LOG_ERROR, "bionic-icu", "couldn't open libicuuc.so: %s", dlerror());
+ async_safe_format_log(ANDROID_LOG_ERROR, "bionic-icu", "couldn't open libicuuc.so: %s",
+ dlerror());
return false;
}
void* symbol = dlsym(g_libicuuc_handle, versioned_symbol_name);
if (symbol == nullptr) {
- __libc_format_log(ANDROID_LOG_ERROR, "bionic-icu", "couldn't find %s", versioned_symbol_name);
+ async_safe_format_log(ANDROID_LOG_ERROR, "bionic-icu", "couldn't find %s",
+ versioned_symbol_name);
}
return symbol;
}
__BEGIN_DECLS
struct mallinfo je_mallinfo();
+int je_mallopt(int, int);
int je_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*);
void je_malloc_disable();
void je_malloc_enable();
* limitations under the License.
*/
+#include <malloc.h>
#include <sys/param.h>
#include <unistd.h>
}
return je_memalign(boundary, size);
}
+
+int je_mallopt(int param, int value) {
+ // The only parameter we currently understand is M_DECAY_TIME.
+ if (param == M_DECAY_TIME) {
+ // Only support setting the value to 1 or 0.
+ ssize_t decay_time;
+ if (value) {
+ decay_time = 1;
+ } else {
+ decay_time = 0;
+ }
+ // First get the total number of arenas.
+ unsigned narenas;
+ size_t sz = sizeof(unsigned);
+ if (je_mallctl("arenas.narenas", &narenas, &sz, nullptr, 0) != 0) {
+ return 0;
+ }
+
+ // Set the decay time for any arenas that will be created in the future.
+ if (je_mallctl("arenas.decay_time", nullptr, nullptr, &decay_time, sizeof(decay_time)) != 0) {
+ return 0;
+ }
+
+ // Change the decay on the already existing arenas.
+ char buffer[100];
+ for (unsigned i = 0; i < narenas; i++) {
+ snprintf(buffer, sizeof(buffer), "arena.%d.decay_time", i);
+ if (je_mallctl(buffer, nullptr, nullptr, &decay_time, sizeof(decay_time)) != 0) {
+ break;
+ }
+ }
+ return 1;
+ }
+ return 0;
+}
#include <sys/time.h>
#include <unistd.h>
+#include <async_safe/log.h>
+
#include "private/KernelArgumentBlock.h"
#include "private/WriteProtected.h"
#include "private/bionic_auxv.h"
#include "private/bionic_globals.h"
#include "private/bionic_tls.h"
-#include "private/libc_logging.h"
#include "private/thread_private.h"
#include "pthread_internal.h"
__LIBC_HIDDEN__ void* __libc_sysinfo = reinterpret_cast<void*>(__libc_int0x80);
__LIBC_HIDDEN__ void __libc_init_sysinfo(KernelArgumentBlock& args) {
- __libc_sysinfo = reinterpret_cast<void*>(args.getauxval(AT_SYSINFO));
+ // Running under valgrind, AT_SYSINFO won't be set.
+ void* at_sysinfo = reinterpret_cast<void*>(args.getauxval(AT_SYSINFO));
+ if (at_sysinfo != nullptr) __libc_sysinfo = at_sysinfo;
}
// TODO: lose this function and just access __libc_sysinfo directly.
#if !defined(__LP64__)
static void __check_max_thread_id() {
if (gettid() > 65535) {
- __libc_fatal("Limited by the size of pthread_mutex_t, 32 bit bionic libc only accepts "
- "pid <= 65535, but current pid is %d", gettid());
+ async_safe_fatal("Limited by the size of pthread_mutex_t, 32 bit bionic libc only accepts "
+ "pid <= 65535, but current pid is %d", gettid());
}
}
#endif
#if !defined(__LP64__)
int old_value = personality(0xffffffff);
if (old_value == -1) {
- __libc_fatal("error getting old personality value: %s", strerror(errno));
+ async_safe_fatal("error getting old personality value: %s", strerror(errno));
}
if (personality((static_cast<unsigned int>(old_value) & ~PER_MASK) | PER_LINUX32) == -1) {
- __libc_fatal("error setting PER_LINUX32 personality: %s", strerror(errno));
+ async_safe_fatal("error setting PER_LINUX32 personality: %s", strerror(errno));
}
#endif
}
Malloc(iterate),
Malloc(malloc_disable),
Malloc(malloc_enable),
+ Malloc(mallopt),
};
// In a VM process, this is set to 1 after fork()ing out of zygote.
return Malloc(mallinfo)();
}
+extern "C" int mallopt(int param, int value) {
+ auto _mallopt = __libc_globals->malloc_dispatch.mallopt;
+ if (__predict_false(_mallopt != nullptr)) {
+ return _mallopt(param, value);
+ }
+ return Malloc(mallopt)(param, value);
+}
+
extern "C" void* malloc(size_t bytes) {
auto _malloc = __libc_globals->malloc_dispatch.malloc;
if (__predict_false(_malloc != nullptr)) {
#include <stdio.h>
#include <stdlib.h>
-#include <private/libc_logging.h>
+#include <async_safe/log.h>
#include <sys/system_properties.h>
extern "C" int __cxa_atexit(void (*func)(void *), void *arg, void *dso);
// Log functions
// =============================================================================
#define error_log(format, ...) \
- __libc_format_log(ANDROID_LOG_ERROR, "libc", (format), ##__VA_ARGS__ )
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc", (format), ##__VA_ARGS__ )
#define info_log(format, ...) \
- __libc_format_log(ANDROID_LOG_INFO, "libc", (format), ##__VA_ARGS__ )
+ async_safe_format_log(ANDROID_LOG_INFO, "libc", (format), ##__VA_ARGS__ )
// =============================================================================
// =============================================================================
prefix, "mallinfo")) {
return false;
}
+ if (!InitMallocFunction<MallocMallopt>(malloc_impl_handler, &table->mallopt,
+ prefix, "mallopt")) {
+ return false;
+ }
if (!InitMallocFunction<MallocMalloc>(malloc_impl_handler, &table->malloc,
prefix, "malloc")) {
return false;
#include <wchar.h>
#include "private/bionic_macros.h"
-#include "private/libc_logging.h"
extern "C" {
// LP64 doesn't need to support any legacy cruft.
#if !defined(__LP64__)
+// By the time any NDK-built code is running, there are plenty of threads.
+int __isthreaded = 1;
+
// These were accidentally declared in <unistd.h> because we stupidly used to inline
// getpagesize() and __getpageshift(). Needed for backwards compatibility with old NDK apps.
unsigned int __page_size = PAGE_SIZE;
#include <errno.h>
#include <stdlib.h>
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
const std::nothrow_t std::nothrow = {};
void* operator new(std::size_t size) {
void* p = malloc(size);
if (p == NULL) {
- __libc_fatal("new failed to allocate %zu bytes", size);
+ async_safe_fatal("new failed to allocate %zu bytes", size);
}
return p;
}
void* operator new[](std::size_t size) {
void* p = malloc(size);
if (p == NULL) {
- __libc_fatal("new[] failed to allocate %zu bytes", size);
+ async_safe_fatal("new[] failed to allocate %zu bytes", size);
}
return p;
}
#include <stdlib.h>
#include <unistd.h>
-#include "private/libc_logging.h"
+#include "private/bionic_fortify.h"
extern "C" int __openat(int, const char*, int, int);
#include <sys/resource.h>
#include <unistd.h>
+#include <async_safe/log.h>
+
#include "private/bionic_string_utils.h"
#include "private/ErrnoRestorer.h"
-#include "private/libc_logging.h"
#include "pthread_internal.h"
int pthread_attr_init(pthread_attr_t* attr) {
static uintptr_t __get_main_stack_startstack() {
FILE* fp = fopen("/proc/self/stat", "re");
if (fp == nullptr) {
- __libc_fatal("couldn't open /proc/self/stat: %s", strerror(errno));
+ async_safe_fatal("couldn't open /proc/self/stat: %s", strerror(errno));
}
char line[BUFSIZ];
if (fgets(line, sizeof(line), fp) == nullptr) {
- __libc_fatal("couldn't read /proc/self/stat: %s", strerror(errno));
+ async_safe_fatal("couldn't read /proc/self/stat: %s", strerror(errno));
}
fclose(fp);
"%*u %*u %*u %*u %*u %*u %*u "
"%*d %*d %*d %*d %*d %*d "
"%*u %*u %*d %*u %*u %*u %" SCNuPTR, &startstack) != 1) {
- __libc_fatal("couldn't parse /proc/self/stat");
+ async_safe_fatal("couldn't parse /proc/self/stat");
}
return startstack;
// Hunt for the region that contains that address.
FILE* fp = fopen("/proc/self/maps", "re");
if (fp == nullptr) {
- __libc_fatal("couldn't open /proc/self/maps");
+ async_safe_fatal("couldn't open /proc/self/maps");
}
char line[BUFSIZ];
while (fgets(line, sizeof(line), fp) != NULL) {
}
}
}
- __libc_fatal("Stack not found in /proc/self/maps");
+ async_safe_fatal("Stack not found in /proc/self/maps");
}
int pthread_attr_getstack(const pthread_attr_t* attr, void** stack_base, size_t* stack_size) {
#include "pthread_internal.h"
+#include <async_safe/log.h>
+
#include "private/bionic_macros.h"
#include "private/bionic_prctl.h"
#include "private/bionic_ssp.h"
#include "private/bionic_tls.h"
-#include "private/libc_logging.h"
#include "private/ErrnoRestorer.h"
// x86 uses segment descriptors rather than a direct pointer to TLS.
void __init_user_desc(struct user_desc*, bool, void*);
#endif
-extern "C" int __isthreaded;
-
// This code is used both by each new pthread and the code that initializes the main thread.
void __init_tls(pthread_internal_t* thread) {
// Slot 0 must point to itself. The x86 Linux kernel reads the TLS from %fs:0.
size_t allocation_size = BIONIC_TLS_SIZE + 2 * PAGE_SIZE;
void* allocation = mmap(nullptr, allocation_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (allocation == MAP_FAILED) {
- __libc_fatal("failed to allocate TLS");
+ async_safe_fatal("failed to allocate TLS");
}
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, allocation, allocation_size, "bionic TLS guard page");
thread->bionic_tls = reinterpret_cast<bionic_tls*>(static_cast<char*>(allocation) + PAGE_SIZE);
if (mprotect(thread->bionic_tls, BIONIC_TLS_SIZE, PROT_READ | PROT_WRITE) != 0) {
- __libc_fatal("failed to mprotect TLS");
+ async_safe_fatal("failed to mprotect TLS");
}
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, thread->bionic_tls, BIONIC_TLS_SIZE, "bionic TLS");
}
// For backwards compatibility reasons, we only report failures on 64-bit devices.
error = errno;
#endif
- __libc_format_log(ANDROID_LOG_WARN, "libc",
- "pthread_create sched_setscheduler call failed: %s", strerror(errno));
+ async_safe_format_log(ANDROID_LOG_WARN, "libc",
+ "pthread_create sched_setscheduler call failed: %s", strerror(errno));
}
}
int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
void* space = mmap(NULL, mmap_size, prot, flags, -1, 0);
if (space == MAP_FAILED) {
- __libc_format_log(ANDROID_LOG_WARN,
+ async_safe_format_log(ANDROID_LOG_WARN,
"libc",
"pthread_create failed: couldn't allocate %zu-bytes mapped space: %s",
mmap_size, strerror(errno));
// Stack is at the lower end of mapped space, stack guard region is at the lower end of stack.
// Set the stack guard region to PROT_NONE, so we can detect thread stack overflow.
if (mprotect(space, stack_guard_size, PROT_NONE) == -1) {
- __libc_format_log(ANDROID_LOG_WARN, "libc",
- "pthread_create failed: couldn't mprotect PROT_NONE %zu-byte stack guard region: %s",
- stack_guard_size, strerror(errno));
+ async_safe_format_log(ANDROID_LOG_WARN, "libc",
+ "pthread_create failed: couldn't mprotect PROT_NONE %zu-byte stack guard region: %s",
+ stack_guard_size, strerror(errno));
munmap(space, mmap_size);
return NULL;
}
void* (*start_routine)(void*), void* arg) {
ErrnoRestorer errno_restorer;
- // Inform the rest of the C library that at least one thread was created.
- __isthreaded = 1;
-
pthread_attr_t thread_attr;
if (attr == NULL) {
pthread_attr_init(&thread_attr);
if (thread->mmap_size != 0) {
munmap(thread->attr.stack_base, thread->mmap_size);
}
- __libc_format_log(ANDROID_LOG_WARN, "libc", "pthread_create failed: clone failed: %s", strerror(errno));
+ async_safe_format_log(ANDROID_LOG_WARN, "libc", "pthread_create failed: clone failed: %s",
+ strerror(errno));
return clone_errno;
}
#include <string.h>
#include <sys/mman.h>
+#include <async_safe/log.h>
+
#include "private/bionic_futex.h"
#include "private/bionic_sdk_version.h"
#include "private/bionic_tls.h"
-#include "private/libc_logging.h"
static pthread_internal_t* g_thread_list = nullptr;
static pthread_rwlock_t g_thread_list_lock = PTHREAD_RWLOCK_INITIALIZER;
// addresses might sometimes contain threads or things that look enough like
// threads for us to do some real damage by continuing.
// TODO: try getting rid of this when Treble lets us keep vendor blobs on an old API level.
- __libc_format_log(ANDROID_LOG_WARN, "libc", "invalid pthread_t (0) passed to libc");
+ async_safe_format_log(ANDROID_LOG_WARN, "libc", "invalid pthread_t (0) passed to libc");
} else {
- __libc_fatal("invalid pthread_t %p passed to libc", thread);
+ async_safe_fatal("invalid pthread_t %p passed to libc", thread);
}
}
return nullptr;
*/
#include <errno.h>
-#include <pthread.h>
#include <signal.h>
+#include <unistd.h>
+#include <sys/syscall.h>
int raise(int sig) {
- int rc = pthread_kill(pthread_self(), sig);
- if (rc != 0) {
- errno = rc;
- return -1;
- }
- return 0;
+ // Protect ourselves against stale cached PID/TID values by fetching them via syscall.
+ // http://b/37769298
+ pid_t pid = syscall(__NR_getpid);
+ pid_t tid = syscall(__NR_gettid);
+ return tgkill(pid, tid, sig);
}
#include <sys/auxv.h>
#include <sys/cdefs.h>
+#include <async_safe/log.h>
+
#include "private/bionic_arc4random.h"
#include "private/bionic_globals.h"
-#include "private/libc_logging.h"
#include "private/KernelArgumentBlock.h"
void __libc_init_setjmp_cookie(libc_globals* globals, KernelArgumentBlock& args) {
extern "C" __LIBC_HIDDEN__ long __bionic_setjmp_cookie_get(long sigflag) {
if (sigflag & ~1) {
- __libc_fatal("unexpected sigflag value: %ld", sigflag);
+ async_safe_fatal("unexpected sigflag value: %ld", sigflag);
}
return __libc_globals->setjmp_cookie | sigflag;
// Aborts if cookie doesn't match, returns the signal flag otherwise.
extern "C" __LIBC_HIDDEN__ long __bionic_setjmp_cookie_check(long cookie) {
if (__libc_globals->setjmp_cookie != (cookie & ~1)) {
- __libc_fatal("setjmp cookie mismatch");
+ async_safe_fatal("setjmp cookie mismatch");
}
return cookie & 1;
}
extern "C" __LIBC_HIDDEN__ long __bionic_setjmp_checksum_mismatch() {
- __libc_fatal("setjmp checksum mismatch");
+ async_safe_fatal("setjmp checksum mismatch");
}
#include <signal.h>
#include <stdio.h>
+#include <async_safe/log.h>
+
#include "private/ErrnoRestorer.h"
-#include "private/libc_logging.h"
struct Pair {
int code;
if (error_name != NULL) {
length = strlcpy(buf, error_name, buf_len);
} else {
- length = __libc_format_buffer(buf, buf_len, "Unknown error %d", error_number);
+ length = async_safe_format_buffer(buf, buf_len, "Unknown error %d", error_number);
}
if (length >= buf_len) {
errno_restorer.override(ERANGE);
#include <string.h>
#include <syslog.h>
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
static const char* syslog_log_tag = NULL;
static int syslog_priority_mask = 0xff;
*dst = '\0';
}
- // We can't let __libc_format_log do the formatting because it doesn't support
+ // We can't let async_safe_format_log do the formatting because it doesn't support
// all the printf functionality.
char log_line[1024];
vsnprintf(log_line, sizeof(log_line), log_fmt, args);
free(const_cast<char*>(log_fmt));
}
- __libc_format_log(android_log_priority, log_tag, "%s", log_line);
+ async_safe_format_log(android_log_priority, log_tag, "%s", log_line);
}
#include <sys/_system_properties.h>
#include <sys/system_properties.h>
+#include <async_safe/log.h>
+
#include "private/ErrnoRestorer.h"
#include "private/bionic_futex.h"
#include "private/bionic_lock.h"
#include "private/bionic_macros.h"
#include "private/bionic_sdk_version.h"
-#include "private/libc_logging.h"
static constexpr int PROP_FILENAME_MAX = 1024;
if (context) {
if (fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1, 0) != 0) {
- __libc_format_log(ANDROID_LOG_ERROR, "libc",
- "fsetxattr failed to set context (%s) for \"%s\"", context, filename);
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+ "fsetxattr failed to set context (%s) for \"%s\"", context, filename);
/*
* fsetxattr() will fail during system properties tests due to selinux policy.
* We do not want to create a custom policy for the tester, so we will continue in
// ms so callers who do read-after-write can reliably see
// what they've written. Most of the time.
// TODO: fix the system properties design.
- __libc_format_log(ANDROID_LOG_WARN, "libc",
- "Property service has timed out while trying to set \"%s\" to \"%s\"",
- msg->name, msg->value);
+ async_safe_format_log(ANDROID_LOG_WARN, "libc",
+ "Property service has timed out while trying to set \"%s\" to \"%s\"",
+ msg->name, msg->value);
result = 0;
}
}
}
char filename[PROP_FILENAME_MAX];
- int len = __libc_format_buffer(filename, sizeof(filename), "%s/%s", property_filename, context_);
+ int len = async_safe_format_buffer(filename, sizeof(filename), "%s/%s", property_filename,
+ context_);
if (len < 0 || len > PROP_FILENAME_MAX) {
lock_.unlock();
return false;
bool context_node::check_access() {
char filename[PROP_FILENAME_MAX];
- int len = __libc_format_buffer(filename, sizeof(filename), "%s/%s", property_filename, context_);
+ int len = async_safe_format_buffer(filename, sizeof(filename), "%s/%s", property_filename,
+ context_);
if (len < 0 || len > PROP_FILENAME_MAX) {
return false;
}
static bool map_system_property_area(bool access_rw, bool* fsetxattr_failed) {
char filename[PROP_FILENAME_MAX];
int len =
- __libc_format_buffer(filename, sizeof(filename), "%s/properties_serial", property_filename);
+ async_safe_format_buffer(filename, sizeof(filename), "%s/properties_serial",
+ property_filename);
if (len < 0 || len > PROP_FILENAME_MAX) {
__system_property_area__ = nullptr;
return false;
prop_area* pa = get_prop_area_for_name(name);
if (!pa) {
- __libc_format_log(ANDROID_LOG_ERROR, "libc", "Access denied finding property \"%s\"", name);
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Access denied finding property \"%s\"", name);
return nullptr;
}
if (name != nullptr) {
size_t namelen = strlcpy(name, pi->name, PROP_NAME_MAX);
if (namelen >= PROP_NAME_MAX) {
- __libc_format_log(ANDROID_LOG_ERROR, "libc",
- "The property name length for \"%s\" is >= %d;"
- " please use __system_property_read_callback"
- " to read this property. (the name is truncated to \"%s\")",
- pi->name, PROP_NAME_MAX - 1, name);
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+ "The property name length for \"%s\" is >= %d;"
+ " please use __system_property_read_callback"
+ " to read this property. (the name is truncated to \"%s\")",
+ pi->name, PROP_NAME_MAX - 1, name);
}
}
return len;
char value[PROP_VALUE_MAX];
if (__system_property_get(kServiceVersionPropertyName, value) == 0) {
g_propservice_protocol_version = kProtocolVersion1;
- __libc_format_log(ANDROID_LOG_WARN, "libc",
- "Using old property service protocol (\"%s\" is not set)",
- kServiceVersionPropertyName);
+ async_safe_format_log(ANDROID_LOG_WARN, "libc",
+ "Using old property service protocol (\"%s\" is not set)",
+ kServiceVersionPropertyName);
} else {
uint32_t version = static_cast<uint32_t>(atoll(value));
if (version >= kProtocolVersion2) {
g_propservice_protocol_version = kProtocolVersion2;
} else {
- __libc_format_log(ANDROID_LOG_WARN, "libc",
- "Using old property service protocol (\"%s\"=\"%s\")",
- kServiceVersionPropertyName, value);
+ async_safe_format_log(ANDROID_LOG_WARN, "libc",
+ "Using old property service protocol (\"%s\"=\"%s\")",
+ kServiceVersionPropertyName, value);
g_propservice_protocol_version = kProtocolVersion1;
}
}
PropertyServiceConnection connection;
if (!connection.IsValid()) {
errno = connection.GetLastError();
- __libc_format_log(ANDROID_LOG_WARN,
- "libc",
- "Unable to set property \"%s\" to \"%s\": connection failed; errno=%d (%s)",
- key,
- value,
- errno,
- strerror(errno));
+ async_safe_format_log(ANDROID_LOG_WARN,
+ "libc",
+ "Unable to set property \"%s\" to \"%s\": connection failed; errno=%d (%s)",
+ key,
+ value,
+ errno,
+ strerror(errno));
return -1;
}
SocketWriter writer(&connection);
if (!writer.WriteUint32(PROP_MSG_SETPROP2).WriteString(key).WriteString(value).Send()) {
errno = connection.GetLastError();
- __libc_format_log(ANDROID_LOG_WARN,
- "libc",
- "Unable to set property \"%s\" to \"%s\": write failed; errno=%d (%s)",
- key,
- value,
- errno,
- strerror(errno));
+ async_safe_format_log(ANDROID_LOG_WARN,
+ "libc",
+ "Unable to set property \"%s\" to \"%s\": write failed; errno=%d (%s)",
+ key,
+ value,
+ errno,
+ strerror(errno));
return -1;
}
int result = -1;
if (!connection.RecvInt32(&result)) {
errno = connection.GetLastError();
- __libc_format_log(ANDROID_LOG_WARN,
- "libc",
- "Unable to set property \"%s\" to \"%s\": recv failed; errno=%d (%s)",
- key,
- value,
- errno,
- strerror(errno));
+ async_safe_format_log(ANDROID_LOG_WARN,
+ "libc",
+ "Unable to set property \"%s\" to \"%s\": recv failed; errno=%d (%s)",
+ key,
+ value,
+ errno,
+ strerror(errno));
return -1;
}
if (result != PROP_SUCCESS) {
- __libc_format_log(ANDROID_LOG_WARN,
- "libc",
- "Unable to set property \"%s\" to \"%s\": error code: 0x%x",
- key,
- value,
- result);
+ async_safe_format_log(ANDROID_LOG_WARN,
+ "libc",
+ "Unable to set property \"%s\" to \"%s\": error code: 0x%x",
+ key,
+ value,
+ result);
return -1;
}
prop_area* pa = get_prop_area_for_name(name);
if (!pa) {
- __libc_format_log(ANDROID_LOG_ERROR, "libc", "Access denied adding property \"%s\"", name);
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Access denied adding property \"%s\"", name);
return -1;
}
#include "resolv_netid.h"
#include "res_private.h"
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
/* This code implements a small and *simple* DNS resolver cache.
*
#define XLOG(...) ({ \
if (DEBUG) { \
- __libc_format_log(ANDROID_LOG_DEBUG,"libc",__VA_ARGS__); \
+ async_safe_format_log(ANDROID_LOG_DEBUG,"libc",__VA_ARGS__); \
} else { \
((void)0); \
} \
#include <resolv_cache.h>
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
#ifndef DE_CONST
#define DE_CONST(c,v) v = ((c) ? \
}
if (DBG) {
- __libc_format_log(ANDROID_LOG_DEBUG, "libc",
+ async_safe_format_log(ANDROID_LOG_DEBUG, "libc",
"used send_vc %d\n", n);
}
} else {
/* Use datagrams. */
if (DBG) {
- __libc_format_log(ANDROID_LOG_DEBUG, "libc", "using send_dg\n");
+ async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "using send_dg\n");
}
n = send_dg(statp, buf, buflen, ans, anssiz, &terrno,
}
if (DBG) {
- __libc_format_log(ANDROID_LOG_DEBUG, "libc", "used send_dg %d\n",n);
+ async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "used send_dg %d\n",n);
}
if (n < 0)
if (n == 0)
goto next_ns;
if (DBG) {
- __libc_format_log(ANDROID_LOG_DEBUG, "libc", "time=%ld\n",
+ async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "time=%ld\n",
time(NULL));
}
if (v_circuit)
timeout = 1;
}
if (DBG) {
- __libc_format_log(ANDROID_LOG_DEBUG, "libc", "using timeout of %d sec\n", timeout);
+ async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "using timeout of %d sec\n", timeout);
}
return timeout;
void *tmp;
if (DBG) {
- __libc_format_log(ANDROID_LOG_DEBUG, "libc", "using send_vc\n");
+ async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "using send_vc\n");
}
nsap = get_nsaddr(statp, (size_t)ns);
timeout = evConsTime((long)sec, 0L);
finish = evAddTime(now, timeout);
if (DBG) {
- __libc_format_log(ANDROID_LOG_DEBUG, "libc", " %d send_vc\n", sock);
+ async_safe_format_log(ANDROID_LOG_DEBUG, "libc", " %d send_vc\n", sock);
}
res = retrying_select(sock, &rset, &wset, &finish);
done:
fcntl(sock, F_SETFL, origflags);
if (DBG) {
- __libc_format_log(ANDROID_LOG_DEBUG, "libc",
+ async_safe_format_log(ANDROID_LOG_DEBUG, "libc",
" %d connect_with_timeout returning %d\n", sock, res);
}
return res;
retry:
if (DBG) {
- __libc_format_log(ANDROID_LOG_DEBUG, "libc", " %d retrying_select\n", sock);
+ async_safe_format_log(ANDROID_LOG_DEBUG, "libc", " %d retrying_select\n", sock);
}
now = evNowTime();
n = pselect(sock + 1, readset, writeset, NULL, &timeout, NULL);
if (n == 0) {
if (DBG) {
- __libc_format_log(ANDROID_LOG_DEBUG, " libc",
+ async_safe_format_log(ANDROID_LOG_DEBUG, " libc",
" %d retrying_select timeout\n", sock);
}
errno = ETIMEDOUT;
if (errno == EINTR)
goto retry;
if (DBG) {
- __libc_format_log(ANDROID_LOG_DEBUG, "libc",
+ async_safe_format_log(ANDROID_LOG_DEBUG, "libc",
" %d retrying_select got error %d\n",sock, n);
}
return n;
if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len) < 0 || error) {
errno = error;
if (DBG) {
- __libc_format_log(ANDROID_LOG_DEBUG, "libc",
+ async_safe_format_log(ANDROID_LOG_DEBUG, "libc",
" %d retrying_select dot error2 %d\n", sock, errno);
}
}
}
if (DBG) {
- __libc_format_log(ANDROID_LOG_DEBUG, "libc",
+ async_safe_format_log(ANDROID_LOG_DEBUG, "libc",
" %d retrying_select returning %d\n",sock, n);
}
#define DEBUG 0
#if DEBUG
-# include "private/libc_logging.h"
+# include <async_safe/log.h>
# include <unistd.h> /* for gettid() */
-# define D(...) __libc_format_log(ANDROID_LOG_DEBUG,"libc", __VA_ARGS__)
+# define D(...) async_safe_format_log(ANDROID_LOG_DEBUG,"libc", __VA_ARGS__)
#else
# define D(...) do{}while(0)
#endif
#include <arpa/nameser.h>
#include <string.h>
-#include "resolv_stats.h"
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
+
#include "isc/eventlib.h"
+#include "resolv_stats.h"
#define DBG 0
_res_stats_set_sample(struct __res_sample* sample, time_t now, int rcode, int rtt)
{
if (DBG) {
- __libc_format_log(ANDROID_LOG_INFO, "libc", "rcode = %d, sec = %d", rcode, rtt);
+ async_safe_format_log(ANDROID_LOG_INFO, "libc", "rcode = %d, sec = %d", rcode, rtt);
}
sample->at = now;
sample->rcode = rcode;
if (successes >= 0 && errors >= 0 && timeouts >= 0) {
int total = successes + errors + timeouts;
if (DBG) {
- __libc_format_log(ANDROID_LOG_DEBUG, "libc", "NS stats: S %d + E %d + T %d + I %d "
+ async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "NS stats: S %d + E %d + T %d + I %d "
"= %d, rtt = %d, min_samples = %d\n", successes, errors, timeouts, internal_errors,
total, rtt_avg, params->min_samples);
}
if (total >= params->min_samples && (errors > 0 || timeouts > 0)) {
int success_rate = successes * 100 / total;
if (DBG) {
- __libc_format_log(ANDROID_LOG_DEBUG, "libc", "success rate %d%%\n", success_rate);
+ async_safe_format_log(ANDROID_LOG_DEBUG, "libc", "success rate %d%%\n",
+ success_rate);
}
if (success_rate < params->success_threshold) {
// evNowTime() is used here instead of time() to stay consistent with the rest of
// date has been reached, however the code for returning the ring buffer to its
// previous non-circular state would induce additional complexity.
if (DBG) {
- __libc_format_log(ANDROID_LOG_INFO, "libc",
+ async_safe_format_log(ANDROID_LOG_INFO, "libc",
"samples stale, retrying server\n");
}
_res_stats_clear_samples(stats);
} else {
if (DBG) {
- __libc_format_log(ANDROID_LOG_INFO, "libc",
+ async_safe_format_log(ANDROID_LOG_INFO, "libc",
"too many resolution errors, ignoring server\n");
}
return 0;
#if __ANDROID_API__ < __ANDROID_API_L__
+/* These weren't introduced until L. */
+int __libc_current_sigrtmax() __attribute__((__weak__)) __VERSIONER_NO_GUARD;
+int __libc_current_sigrtmin() __attribute__((__weak__)) __VERSIONER_NO_GUARD;
+
+static __inline int __ndk_legacy___libc_current_sigrtmax() {
+ if (__libc_current_sigrtmax) return __libc_current_sigrtmax();
+ return __SIGRTMAX; /* Should match __libc_current_sigrtmax. */
+}
+
+static __inline int __ndk_legacy___libc_current_sigrtmin() {
+ if (__libc_current_sigrtmin) return __libc_current_sigrtmin();
+ return __SIGRTMIN + 4; /* Should match __libc_current_sigrtmin. */
+}
+
+#undef SIGRTMAX
+#define SIGRTMAX __ndk_legacy___libc_current_sigrtmax()
+#undef SIGRTMIN
+#define SIGRTMIN __ndk_legacy___libc_current_sigrtmin()
+
static __inline int sigismember(const sigset_t *set, int signum) {
/* Signal numbers start at 1, but bit positions start at 0. */
int bit = signum - 1;
#define PT_GNU_RELRO 0x6474e552
+#undef ELF_ST_TYPE
+#define ELF_ST_TYPE(x) ((x) & 0xf)
+#define ELF_ST_INFO(b,t) (((b) << 4) + ((t) & 0xf))
+#define ELF32_ST_INFO(b,t) ELF_ST_INFO(b,t)
+#define ELF64_ST_INFO(b,t) ELF_ST_INFO(b,t)
+
#define STB_LOOS 10
#define STB_HIOS 12
#define STB_LOPROC 13
__BEGIN_DECLS
-#if defined(__clang__)
-/* clang should support alloc_size in the nearish future. */
-#if __has_attribute(alloc_size)
-#error "We should enable alloc_size for clang."
-#else
+// Remove the workaround once b/37423073 is fixed.
+#if defined(__clang__) && !__has_attribute(alloc_size)
#define __BIONIC_ALLOC_SIZE(...)
-#endif
#else
#define __BIONIC_ALLOC_SIZE(...) __attribute__((__alloc_size__(__VA_ARGS__)))
#endif
*/
int malloc_info(int, FILE*) __INTRODUCED_IN(23);
+/* mallopt options */
+#define M_DECAY_TIME -100
+
+int mallopt(int, int) __INTRODUCED_IN_FUTURE;
+
__END_DECLS
#endif /* LIBC_INCLUDE_MALLOC_H_ */
#include <linux/sem.h>
+__BEGIN_DECLS
+
#define semid_ds semid64_ds
-__BEGIN_DECLS
+union semun {
+ int val;
+ struct semid_ds* buf;
+ unsigned short* array;
+ struct seminfo* __buf;
+ void* __pad;
+};
int semctl(int, int, int, ...) __INTRODUCED_IN(26);
int semget(key_t, int, int) __INTRODUCED_IN(26);
"semid_ds": "__kernel_legacy_semid_ds",
"shmid_ds": "__kernel_legacy_shmid_ds",
"ipc_perm": "__kernel_legacy_ipc_perm",
+ # The kernel semun isn't usable (https://github.com/android-ndk/ndk/issues/400).
+ "semun": "__kernel_legacy_semun",
# The kernel's _NSIG/NSIG are one less than the userspace value, so we need to move them aside.
"_NSIG": "_KERNEL__NSIG",
"NSIG": "_KERNEL_NSIG",
short sem_flg;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
};
-union semun {
+union __kernel_legacy_semun {
int val;
struct __kernel_legacy_semid_ds __user * buf;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
LIBC_O {
global:
- __sendto_chk; # future
- __system_property_read_callback; # future
- __system_property_wait; # future
+ __sendto_chk; # introduced=26
+ __system_property_read_callback; # introduced=26
+ __system_property_wait; # introduced=26
bsd_signal; # arm x86 mips versioned=26
- catclose; # future
- catgets; # future
- catopen; # future
- ctermid; # future
- endgrent; # future
- endpwent; # future
- futimes; # future
- futimesat; # future
- getdomainname; # future
- getgrent; # future
- getpwent; # future
- getsubopt; # future
- hasmntopt; # future
- lutimes; # future
- mblen; # future
- msgctl; # future
- msgget; # future
- msgrcv; # future
- msgsnd; # future
- nl_langinfo; # future
- nl_langinfo_l; # future
- pthread_getname_np; # future
- quotactl; # future
- semctl; # future
- semget; # future
- semop; # future
- semtimedop; # future
- setdomainname; # future
- setgrent; # future
- setpwent; # future
- shmat; # future
- shmctl; # future
- shmdt; # future
- shmget; # future
- sighold; # future
- sigignore; # future
- sigpause; # future
- sigrelse; # future
- sigset; # future
- strtod_l; # future
- strtof_l; # future
- strtol_l; # future
- strtoul_l; # future
- sync_file_range; # future
- towctrans; # future
- towctrans_l; # future
- wctrans; # future
- wctrans_l; # future
+ catclose; # introduced=26
+ catgets; # introduced=26
+ catopen; # introduced=26
+ ctermid; # introduced=26
+ endgrent; # introduced=26
+ endpwent; # introduced=26
+ futimes; # introduced=26
+ futimesat; # introduced=26
+ getdomainname; # introduced=26
+ getgrent; # introduced=26
+ getpwent; # introduced=26
+ getsubopt; # introduced=26
+ hasmntopt; # introduced=26
+ lutimes; # introduced=26
+ mblen; # introduced=26
+ msgctl; # introduced=26
+ msgget; # introduced=26
+ msgrcv; # introduced=26
+ msgsnd; # introduced=26
+ nl_langinfo; # introduced=26
+ nl_langinfo_l; # introduced=26
+ pthread_getname_np; # introduced=26
+ quotactl; # introduced=26
+ semctl; # introduced=26
+ semget; # introduced=26
+ semop; # introduced=26
+ semtimedop; # introduced=26
+ setdomainname; # introduced=26
+ setgrent; # introduced=26
+ setpwent; # introduced=26
+ shmat; # introduced=26
+ shmctl; # introduced=26
+ shmdt; # introduced=26
+ shmget; # introduced=26
+ sighold; # introduced=26
+ sigignore; # introduced=26
+ sigpause; # introduced=26
+ sigrelse; # introduced=26
+ sigset; # introduced=26
+ strtod_l; # introduced=26
+ strtof_l; # introduced=26
+ strtol_l; # introduced=26
+ strtoul_l; # introduced=26
+ sync_file_range; # introduced=26
+ towctrans; # introduced=26
+ towctrans_l; # introduced=26
+ wctrans; # introduced=26
+ wctrans_l; # introduced=26
} LIBC_N;
LIBC_PRIVATE {
malloc_disable;
malloc_enable;
malloc_iterate;
+ mallopt;
} LIBC_O;
LIBC_O {
global:
- __sendto_chk; # future
- __system_property_read_callback; # future
- __system_property_wait; # future
- catclose; # future
- catgets; # future
- catopen; # future
- ctermid; # future
- endgrent; # future
- endpwent; # future
- futimes; # future
- futimesat; # future
- getdomainname; # future
- getgrent; # future
- getpwent; # future
- getsubopt; # future
- hasmntopt; # future
- lutimes; # future
- mblen; # future
- msgctl; # future
- msgget; # future
- msgrcv; # future
- msgsnd; # future
- nl_langinfo; # future
- nl_langinfo_l; # future
- pthread_getname_np; # future
- quotactl; # future
- semctl; # future
- semget; # future
- semop; # future
- semtimedop; # future
- setdomainname; # future
- setgrent; # future
- setpwent; # future
- shmat; # future
- shmctl; # future
- shmdt; # future
- shmget; # future
- sighold; # future
- sigignore; # future
- sigpause; # future
- sigrelse; # future
- sigset; # future
- strtod_l; # future
- strtof_l; # future
- strtol_l; # future
- strtoul_l; # future
- sync_file_range; # future
- towctrans; # future
- towctrans_l; # future
- wctrans; # future
- wctrans_l; # future
+ __sendto_chk; # introduced=26
+ __system_property_read_callback; # introduced=26
+ __system_property_wait; # introduced=26
+ catclose; # introduced=26
+ catgets; # introduced=26
+ catopen; # introduced=26
+ ctermid; # introduced=26
+ endgrent; # introduced=26
+ endpwent; # introduced=26
+ futimes; # introduced=26
+ futimesat; # introduced=26
+ getdomainname; # introduced=26
+ getgrent; # introduced=26
+ getpwent; # introduced=26
+ getsubopt; # introduced=26
+ hasmntopt; # introduced=26
+ lutimes; # introduced=26
+ mblen; # introduced=26
+ msgctl; # introduced=26
+ msgget; # introduced=26
+ msgrcv; # introduced=26
+ msgsnd; # introduced=26
+ nl_langinfo; # introduced=26
+ nl_langinfo_l; # introduced=26
+ pthread_getname_np; # introduced=26
+ quotactl; # introduced=26
+ semctl; # introduced=26
+ semget; # introduced=26
+ semop; # introduced=26
+ semtimedop; # introduced=26
+ setdomainname; # introduced=26
+ setgrent; # introduced=26
+ setpwent; # introduced=26
+ shmat; # introduced=26
+ shmctl; # introduced=26
+ shmdt; # introduced=26
+ shmget; # introduced=26
+ sighold; # introduced=26
+ sigignore; # introduced=26
+ sigpause; # introduced=26
+ sigrelse; # introduced=26
+ sigset; # introduced=26
+ strtod_l; # introduced=26
+ strtof_l; # introduced=26
+ strtol_l; # introduced=26
+ strtoul_l; # introduced=26
+ sync_file_range; # introduced=26
+ towctrans; # introduced=26
+ towctrans_l; # introduced=26
+ wctrans; # introduced=26
+ wctrans_l; # introduced=26
} LIBC_N;
LIBC_PRIVATE {
malloc_disable;
malloc_enable;
malloc_iterate;
+ mallopt;
} LIBC_O;
LIBC_O {
global:
- __sendto_chk; # future
- __system_property_read_callback; # future
- __system_property_wait; # future
+ __sendto_chk; # introduced=26
+ __system_property_read_callback; # introduced=26
+ __system_property_wait; # introduced=26
bsd_signal; # arm x86 mips versioned=26
- catclose; # future
- catgets; # future
- catopen; # future
- ctermid; # future
- endgrent; # future
- endpwent; # future
- futimes; # future
- futimesat; # future
- getdomainname; # future
- getgrent; # future
- getpwent; # future
- getsubopt; # future
- hasmntopt; # future
- lutimes; # future
- mblen; # future
- msgctl; # future
- msgget; # future
- msgrcv; # future
- msgsnd; # future
- nl_langinfo; # future
- nl_langinfo_l; # future
- pthread_getname_np; # future
- quotactl; # future
- semctl; # future
- semget; # future
- semop; # future
- semtimedop; # future
- setdomainname; # future
- setgrent; # future
- setpwent; # future
- shmat; # future
- shmctl; # future
- shmdt; # future
- shmget; # future
- sighold; # future
- sigignore; # future
- sigpause; # future
- sigrelse; # future
- sigset; # future
- strtod_l; # future
- strtof_l; # future
- strtol_l; # future
- strtoul_l; # future
- sync_file_range; # future
- towctrans; # future
- towctrans_l; # future
- wctrans; # future
- wctrans_l; # future
+ catclose; # introduced=26
+ catgets; # introduced=26
+ catopen; # introduced=26
+ ctermid; # introduced=26
+ endgrent; # introduced=26
+ endpwent; # introduced=26
+ futimes; # introduced=26
+ futimesat; # introduced=26
+ getdomainname; # introduced=26
+ getgrent; # introduced=26
+ getpwent; # introduced=26
+ getsubopt; # introduced=26
+ hasmntopt; # introduced=26
+ lutimes; # introduced=26
+ mblen; # introduced=26
+ msgctl; # introduced=26
+ msgget; # introduced=26
+ msgrcv; # introduced=26
+ msgsnd; # introduced=26
+ nl_langinfo; # introduced=26
+ nl_langinfo_l; # introduced=26
+ pthread_getname_np; # introduced=26
+ quotactl; # introduced=26
+ semctl; # introduced=26
+ semget; # introduced=26
+ semop; # introduced=26
+ semtimedop; # introduced=26
+ setdomainname; # introduced=26
+ setgrent; # introduced=26
+ setpwent; # introduced=26
+ shmat; # introduced=26
+ shmctl; # introduced=26
+ shmdt; # introduced=26
+ shmget; # introduced=26
+ sighold; # introduced=26
+ sigignore; # introduced=26
+ sigpause; # introduced=26
+ sigrelse; # introduced=26
+ sigset; # introduced=26
+ strtod_l; # introduced=26
+ strtof_l; # introduced=26
+ strtol_l; # introduced=26
+ strtoul_l; # introduced=26
+ sync_file_range; # introduced=26
+ towctrans; # introduced=26
+ towctrans_l; # introduced=26
+ wctrans; # introduced=26
+ wctrans_l; # introduced=26
} LIBC_N;
LIBC_PRIVATE {
malloc_disable;
malloc_enable;
malloc_iterate;
+ mallopt;
} LIBC_O;
LIBC_O {
global:
- __sendto_chk; # future
- __system_property_read_callback; # future
- __system_property_wait; # future
- catclose; # future
- catgets; # future
- catopen; # future
- ctermid; # future
- endgrent; # future
- endpwent; # future
- futimes; # future
- futimesat; # future
- getdomainname; # future
- getgrent; # future
- getpwent; # future
- getsubopt; # future
- hasmntopt; # future
- lutimes; # future
- mblen; # future
- msgctl; # future
- msgget; # future
- msgrcv; # future
- msgsnd; # future
- nl_langinfo; # future
- nl_langinfo_l; # future
- pthread_getname_np; # future
- quotactl; # future
- semctl; # future
- semget; # future
- semop; # future
- semtimedop; # future
- setdomainname; # future
- setgrent; # future
- setpwent; # future
- shmat; # future
- shmctl; # future
- shmdt; # future
- shmget; # future
- sighold; # future
- sigignore; # future
- sigpause; # future
- sigrelse; # future
- sigset; # future
- strtod_l; # future
- strtof_l; # future
- strtol_l; # future
- strtoul_l; # future
- sync_file_range; # future
- towctrans; # future
- towctrans_l; # future
- wctrans; # future
- wctrans_l; # future
+ __sendto_chk; # introduced=26
+ __system_property_read_callback; # introduced=26
+ __system_property_wait; # introduced=26
+ catclose; # introduced=26
+ catgets; # introduced=26
+ catopen; # introduced=26
+ ctermid; # introduced=26
+ endgrent; # introduced=26
+ endpwent; # introduced=26
+ futimes; # introduced=26
+ futimesat; # introduced=26
+ getdomainname; # introduced=26
+ getgrent; # introduced=26
+ getpwent; # introduced=26
+ getsubopt; # introduced=26
+ hasmntopt; # introduced=26
+ lutimes; # introduced=26
+ mblen; # introduced=26
+ msgctl; # introduced=26
+ msgget; # introduced=26
+ msgrcv; # introduced=26
+ msgsnd; # introduced=26
+ nl_langinfo; # introduced=26
+ nl_langinfo_l; # introduced=26
+ pthread_getname_np; # introduced=26
+ quotactl; # introduced=26
+ semctl; # introduced=26
+ semget; # introduced=26
+ semop; # introduced=26
+ semtimedop; # introduced=26
+ setdomainname; # introduced=26
+ setgrent; # introduced=26
+ setpwent; # introduced=26
+ shmat; # introduced=26
+ shmctl; # introduced=26
+ shmdt; # introduced=26
+ shmget; # introduced=26
+ sighold; # introduced=26
+ sigignore; # introduced=26
+ sigpause; # introduced=26
+ sigrelse; # introduced=26
+ sigset; # introduced=26
+ strtod_l; # introduced=26
+ strtof_l; # introduced=26
+ strtol_l; # introduced=26
+ strtoul_l; # introduced=26
+ sync_file_range; # introduced=26
+ towctrans; # introduced=26
+ towctrans_l; # introduced=26
+ wctrans; # introduced=26
+ wctrans_l; # introduced=26
} LIBC_N;
LIBC_PRIVATE {
malloc_disable;
malloc_enable;
malloc_iterate;
+ mallopt;
} LIBC_O;
LIBC_O {
global:
- __sendto_chk; # future
- __system_property_read_callback; # future
- __system_property_wait; # future
+ __sendto_chk; # introduced=26
+ __system_property_read_callback; # introduced=26
+ __system_property_wait; # introduced=26
bsd_signal; # arm x86 mips versioned=26
- catclose; # future
- catgets; # future
- catopen; # future
- ctermid; # future
- endgrent; # future
- endpwent; # future
- futimes; # future
- futimesat; # future
- getdomainname; # future
- getgrent; # future
- getpwent; # future
- getsubopt; # future
- hasmntopt; # future
- lutimes; # future
- mblen; # future
- msgctl; # future
- msgget; # future
- msgrcv; # future
- msgsnd; # future
- nl_langinfo; # future
- nl_langinfo_l; # future
- pthread_getname_np; # future
- quotactl; # future
- semctl; # future
- semget; # future
- semop; # future
- semtimedop; # future
- setdomainname; # future
- setgrent; # future
- setpwent; # future
- shmat; # future
- shmctl; # future
- shmdt; # future
- shmget; # future
- sighold; # future
- sigignore; # future
- sigpause; # future
- sigrelse; # future
- sigset; # future
- strtod_l; # future
- strtof_l; # future
- strtol_l; # future
- strtoul_l; # future
- sync_file_range; # future
- towctrans; # future
- towctrans_l; # future
- wctrans; # future
- wctrans_l; # future
+ catclose; # introduced=26
+ catgets; # introduced=26
+ catopen; # introduced=26
+ ctermid; # introduced=26
+ endgrent; # introduced=26
+ endpwent; # introduced=26
+ futimes; # introduced=26
+ futimesat; # introduced=26
+ getdomainname; # introduced=26
+ getgrent; # introduced=26
+ getpwent; # introduced=26
+ getsubopt; # introduced=26
+ hasmntopt; # introduced=26
+ lutimes; # introduced=26
+ mblen; # introduced=26
+ msgctl; # introduced=26
+ msgget; # introduced=26
+ msgrcv; # introduced=26
+ msgsnd; # introduced=26
+ nl_langinfo; # introduced=26
+ nl_langinfo_l; # introduced=26
+ pthread_getname_np; # introduced=26
+ quotactl; # introduced=26
+ semctl; # introduced=26
+ semget; # introduced=26
+ semop; # introduced=26
+ semtimedop; # introduced=26
+ setdomainname; # introduced=26
+ setgrent; # introduced=26
+ setpwent; # introduced=26
+ shmat; # introduced=26
+ shmctl; # introduced=26
+ shmdt; # introduced=26
+ shmget; # introduced=26
+ sighold; # introduced=26
+ sigignore; # introduced=26
+ sigpause; # introduced=26
+ sigrelse; # introduced=26
+ sigset; # introduced=26
+ strtod_l; # introduced=26
+ strtof_l; # introduced=26
+ strtol_l; # introduced=26
+ strtoul_l; # introduced=26
+ sync_file_range; # introduced=26
+ towctrans; # introduced=26
+ towctrans_l; # introduced=26
+ wctrans; # introduced=26
+ wctrans_l; # introduced=26
} LIBC_N;
LIBC_PRIVATE {
malloc_disable;
malloc_enable;
malloc_iterate;
+ mallopt;
} LIBC_O;
LIBC_O {
global:
- __sendto_chk; # future
- __system_property_read_callback; # future
- __system_property_wait; # future
- catclose; # future
- catgets; # future
- catopen; # future
- ctermid; # future
- endgrent; # future
- endpwent; # future
- futimes; # future
- futimesat; # future
- getdomainname; # future
- getgrent; # future
- getpwent; # future
- getsubopt; # future
- hasmntopt; # future
- lutimes; # future
- mblen; # future
- msgctl; # future
- msgget; # future
- msgrcv; # future
- msgsnd; # future
- nl_langinfo; # future
- nl_langinfo_l; # future
- pthread_getname_np; # future
- quotactl; # future
- semctl; # future
- semget; # future
- semop; # future
- semtimedop; # future
- setdomainname; # future
- setgrent; # future
- setpwent; # future
- shmat; # future
- shmctl; # future
- shmdt; # future
- shmget; # future
- sighold; # future
- sigignore; # future
- sigpause; # future
- sigrelse; # future
- sigset; # future
- strtod_l; # future
- strtof_l; # future
- strtol_l; # future
- strtoul_l; # future
- sync_file_range; # future
- towctrans; # future
- towctrans_l; # future
- wctrans; # future
- wctrans_l; # future
+ __sendto_chk; # introduced=26
+ __system_property_read_callback; # introduced=26
+ __system_property_wait; # introduced=26
+ catclose; # introduced=26
+ catgets; # introduced=26
+ catopen; # introduced=26
+ ctermid; # introduced=26
+ endgrent; # introduced=26
+ endpwent; # introduced=26
+ futimes; # introduced=26
+ futimesat; # introduced=26
+ getdomainname; # introduced=26
+ getgrent; # introduced=26
+ getpwent; # introduced=26
+ getsubopt; # introduced=26
+ hasmntopt; # introduced=26
+ lutimes; # introduced=26
+ mblen; # introduced=26
+ msgctl; # introduced=26
+ msgget; # introduced=26
+ msgrcv; # introduced=26
+ msgsnd; # introduced=26
+ nl_langinfo; # introduced=26
+ nl_langinfo_l; # introduced=26
+ pthread_getname_np; # introduced=26
+ quotactl; # introduced=26
+ semctl; # introduced=26
+ semget; # introduced=26
+ semop; # introduced=26
+ semtimedop; # introduced=26
+ setdomainname; # introduced=26
+ setgrent; # introduced=26
+ setpwent; # introduced=26
+ shmat; # introduced=26
+ shmctl; # introduced=26
+ shmdt; # introduced=26
+ shmget; # introduced=26
+ sighold; # introduced=26
+ sigignore; # introduced=26
+ sigpause; # introduced=26
+ sigrelse; # introduced=26
+ sigset; # introduced=26
+ strtod_l; # introduced=26
+ strtof_l; # introduced=26
+ strtol_l; # introduced=26
+ strtoul_l; # introduced=26
+ sync_file_range; # introduced=26
+ towctrans; # introduced=26
+ towctrans_l; # introduced=26
+ wctrans; # introduced=26
+ wctrans_l; # introduced=26
} LIBC_N;
LIBC_PRIVATE {
malloc_disable;
malloc_enable;
malloc_iterate;
+ mallopt;
} LIBC_O;
stl: "libc++_static",
- static_libs: ["libc_logging"],
+ whole_static_libs: ["libasync_safe"],
include_dirs: ["bionic/libc"],
+
export_include_dirs: ["."],
sanitize: {
"-Werror",
"-Wno-error=format-zero-length",
],
-
}
// ==============================================================
},
static_libs: [
+ "libasync_safe",
"libbase",
"libc_malloc_debug_backtrace",
- "libc_logging",
],
multilib: {
"-fno-stack-protector",
"-Wno-error=format-zero-length",
],
-
}
// ==============================================================
whole_static_libs: ["libc_malloc_debug"],
local_include_dirs: ["tests"],
- include_dirs: ["bionic/libc"],
+ include_dirs: ["bionic/libc", "bionic/libc/async_safe/include"],
shared_libs: ["libbase"],
"-Werror",
"-Wno-error=format-zero-length",
],
-
}
char* demangled_symbol = __cxa_demangle(symbol, nullptr, nullptr, nullptr);
const char* best_name = (demangled_symbol != nullptr) ? demangled_symbol : symbol;
- __libc_format_buffer(buf, sizeof(buf),
- " #%02zd pc %" PAD_PTR " %s (%s+%" PRIuPTR ")\n", frame_num,
+ async_safe_format_buffer(
+ buf, sizeof(buf), " #%02zd pc %" PAD_PTR " %s (%s+%" PRIuPTR ")\n", frame_num,
rel_pc, soname, best_name, frames[frame_num] - offset);
free(demangled_symbol);
} else {
- __libc_format_buffer(buf, sizeof(buf),
- " #%02zd pc %" PAD_PTR " %s\n", frame_num, rel_pc, soname);
+ async_safe_format_buffer(
+ buf, sizeof(buf), " #%02zd pc %" PAD_PTR " %s\n", frame_num, rel_pc, soname);
}
str += buf;
}
#ifndef MALLOC_DEBUG_LOG_H
#define MALLOC_DEBUG_LOG_H
-#include <private/libc_logging.h>
+#include <async_safe/log.h>
// =============================================================================
// log functions
// =============================================================================
#define debug_log(format, ...) \
- __libc_format_log(ANDROID_LOG_DEBUG, "malloc_debug", (format), ##__VA_ARGS__ )
+ async_safe_format_log(ANDROID_LOG_DEBUG, "malloc_debug", (format), ##__VA_ARGS__ )
#define error_log(format, ...) \
- __libc_format_log(ANDROID_LOG_ERROR, "malloc_debug", (format), ##__VA_ARGS__ )
+ async_safe_format_log(ANDROID_LOG_ERROR, "malloc_debug", (format), ##__VA_ARGS__ )
#define error_log_string(str) \
- __libc_write_log(ANDROID_LOG_ERROR, "malloc_debug", (str))
+ async_safe_write_log(ANDROID_LOG_ERROR, "malloc_debug", (str))
#define info_log(format, ...) \
- __libc_format_log(ANDROID_LOG_INFO, "malloc_debug", (format), ##__VA_ARGS__ )
+ async_safe_format_log(ANDROID_LOG_INFO, "malloc_debug", (format), ##__VA_ARGS__ )
#endif // MALLOC_DEBUG_LOG_H
debug_malloc_disable;
debug_malloc_enable;
debug_malloc_usable_size;
+ debug_mallopt;
debug_memalign;
debug_posix_memalign;
debug_pvalloc;
debug_malloc_disable;
debug_malloc_enable;
debug_malloc_usable_size;
+ debug_mallopt;
debug_memalign;
debug_posix_memalign;
debug_realloc;
void* debug_realloc(void* pointer, size_t bytes);
void* debug_calloc(size_t nmemb, size_t bytes);
struct mallinfo debug_mallinfo();
+int debug_mallopt(int param, int value);
int debug_posix_memalign(void** memptr, size_t alignment, size_t size);
int debug_iterate(uintptr_t base, size_t size,
void (*callback)(uintptr_t base, size_t size, void* arg), void* arg);
return g_dispatch->mallinfo();
}
+int debug_mallopt(int param, int value) {
+ return g_dispatch->mallopt(param, value);
+}
+
int debug_posix_memalign(void** memptr, size_t alignment, size_t size) {
if (DebugCallsDisabled()) {
return g_dispatch->posix_memalign(memptr, alignment, size);
return g_fake_log_print;
}
-extern "C" int __libc_format_log(int priority, const char* tag, const char* format, ...) {
+extern "C" int async_safe_format_log(int priority, const char* tag, const char* format, ...) {
g_fake_log_print += std::to_string(priority) + ' ';
g_fake_log_print += tag;
g_fake_log_print += ' ';
void debug_free_malloc_leak_info(uint8_t*);
struct mallinfo debug_mallinfo();
+int debug_mallopt(int, int);
#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
void* debug_pvalloc(size_t);
nullptr,
nullptr,
nullptr,
+ mallopt,
};
void VerifyAllocCalls() {
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
+TEST_F(MallocDebugTest, debug_mallopt) {
+ Init("guard");
+
+ void* pointer = debug_malloc(150);
+ ASSERT_TRUE(pointer != nullptr);
+
+ EXPECT_EQ(0, debug_mallopt(-1000, 1));
+
+ debug_free(pointer);
+
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
TEST_F(MallocDebugTest, debug_posix_memalign) {
Init("guard");
#include <sys/mman.h>
#include <sys/user.h>
+#include <async_safe/log.h>
+
#include "private/bionic_macros.h"
#include "private/bionic_prctl.h"
-#include "private/libc_logging.h"
template <typename T>
union WriteProtectedContents {
memset(&contents, 0, sizeof(contents));
if (mprotect(&contents, PAGE_SIZE, PROT_READ)) {
- __libc_fatal("failed to make WriteProtected nonwritable in initialize");
+ async_safe_fatal("failed to make WriteProtected nonwritable in initialize");
}
}
template <typename Mutator>
void mutate(Mutator mutator) {
if (mprotect(&contents, PAGE_SIZE, PROT_READ | PROT_WRITE) != 0) {
- __libc_fatal("failed to make WriteProtected writable in mutate: %s",
- strerror(errno));
+ async_safe_fatal("failed to make WriteProtected writable in mutate: %s",
+ strerror(errno));
}
mutator(&contents.value);
if (mprotect(&contents, PAGE_SIZE, PROT_READ) != 0) {
- __libc_fatal("failed to make WriteProtected nonwritable in mutate: %s",
- strerror(errno));
+ async_safe_fatal("failed to make WriteProtected nonwritable in mutate: %s",
+ strerror(errno));
}
}
};
* SUCH DAMAGE.
*/
-#include "private/libc_logging.h"
-
#include <poll.h> // For struct pollfd.
+#include <stdarg.h>
+#include <stdlib.h>
#include <sys/select.h> // For struct fd_set.
+#include <async_safe/log.h>
+
+static inline __noreturn void __fortify_fatal(const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ async_safe_fatal_va_list("FORTIFY", fmt, args);
+ va_end(args);
+ abort();
+}
+
//
// Common helpers.
//
typedef int (*MallocIterate)(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*);
typedef void (*MallocMallocDisable)();
typedef void (*MallocMallocEnable)();
+typedef int (*MallocMallopt)(int, int);
#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
typedef void* (*MallocPvalloc)(size_t);
MallocIterate iterate;
MallocMallocDisable malloc_disable;
MallocMallocEnable malloc_enable;
+ MallocMallopt mallopt;
} __attribute__((aligned(32)));
#endif
#include "seccomp_bpfs.h"
const sock_filter mips64_filter[] = {
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5000, 0, 82),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5168, 41, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5089, 21, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5038, 11, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5023, 5, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5008, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5000, 0, 84),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5164, 41, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5077, 21, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5034, 11, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5008, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5005, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5003, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5002, 75, 74), //read|write
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5004, 74, 73), //close
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5020, 73, 72), //lseek|mmap|mprotect|munmap|brk|rt_sigaction|rt_sigprocmask|ioctl|pread64|pwrite64|readv|writev
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5034, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5031, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5028, 70, 69), //sched_yield|mremap|msync|mincore|madvise
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5032, 69, 68), //dup
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5037, 68, 67), //nanosleep|getitimer|setitimer
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5070, 5, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5057, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5043, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5042, 64, 63), //getpid|sendfile|socket|connect
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5056, 63, 62), //sendto|recvfrom|sendmsg|recvmsg|shutdown|bind|listen|getsockname|getpeername|socketpair|setsockopt|getsockopt|clone
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5002, 77, 76), //read|write
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5004, 76, 75), //close
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5006, 75, 74), //fstat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5031, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5023, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5020, 72, 71), //lseek|mmap|mprotect|munmap|brk|rt_sigaction|rt_sigprocmask|ioctl|pread64|pwrite64|readv|writev
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5028, 71, 70), //sched_yield|mremap|msync|mincore|madvise
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5032, 70, 69), //dup
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5057, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5043, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5038, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5037, 66, 65), //nanosleep|getitimer|setitimer
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5042, 65, 64), //getpid|sendfile|socket|connect
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5056, 64, 63), //sendto|recvfrom|sendmsg|recvmsg|shutdown|bind|listen|getsockname|getpeername|socketpair|setsockopt|getsockopt|clone
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5070, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5062, 62, 61), //execve|exit|wait4|kill|uname
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5077, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5076, 60, 59), //fcntl|flock|fsync|fdatasync|truncate|ftruncate
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5080, 59, 58), //getcwd|chdir|fchdir
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5134, 9, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5110, 5, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5093, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5091, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5090, 54, 53), //fchmod
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5092, 53, 52), //fchown
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5076, 61, 60), //fcntl|flock|fsync|fdatasync|truncate|ftruncate
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5132, 9, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5093, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5091, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5089, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5080, 56, 55), //getcwd|chdir|fchdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5090, 55, 54), //fchmod
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5092, 54, 53), //fchown
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5110, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5109, 52, 51), //umask|gettimeofday|getrlimit|getrusage|sysinfo|times|ptrace|getuid|syslog|getgid|setuid|setgid|geteuid|getegid|setpgid|getppid
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5132, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5130, 50, 49), //setsid|setreuid|setregid|getgroups|setgroups|setresuid|getresuid|setresgid|getresgid|getpgid|setfsuid|setfsgid|getsid|capget|capset|rt_sigpending|rt_sigtimedwait|rt_sigqueueinfo|rt_sigsuspend|sigaltstack
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5133, 49, 48), //personality
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5153, 5, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5151, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5137, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5136, 45, 44), //statfs|fstatfs
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5150, 44, 43), //getpriority|setpriority|sched_setparam|sched_getparam|sched_setscheduler|sched_getscheduler|sched_get_priority_max|sched_get_priority_min|sched_rr_get_interval|mlock|munlock|mlockall|munlockall
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5130, 51, 50), //setsid|setreuid|setregid|getgroups|setgroups|setresuid|getresuid|setresgid|getresgid|getpgid|setfsuid|setfsgid|getsid|capget|capset|rt_sigpending|rt_sigtimedwait|rt_sigqueueinfo|rt_sigsuspend|sigaltstack
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5151, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5137, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5134, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5133, 47, 46), //personality
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5136, 46, 45), //statfs|fstatfs
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5150, 45, 44), //getpriority|setpriority|sched_setparam|sched_getparam|sched_setscheduler|sched_getscheduler|sched_get_priority_max|sched_get_priority_min|sched_rr_get_interval|mlock|munlock|mlockall|munlockall
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5153, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5152, 43, 42), //pivot_root
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5164, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5162, 41, 40), //prctl|adjtimex|setrlimit|chroot|sync|acct|settimeofday|mount|umount2
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5167, 40, 39), //reboot|sethostname|setdomainname
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5244, 19, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5208, 9, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5194, 5, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5178, 3, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5172, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5170, 34, 33), //init_module|delete_module
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5173, 33, 32), //quotactl
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5193, 32, 31), //gettid|readahead|setxattr|lsetxattr|fsetxattr|getxattr|lgetxattr|fgetxattr|listxattr|llistxattr|flistxattr|removexattr|lremovexattr|fremovexattr|tkill
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5205, 1, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5197, 30, 29), //futex|sched_setaffinity|sched_getaffinity
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5162, 42, 41), //prctl|adjtimex|setrlimit|chroot|sync|acct|settimeofday|mount|umount2
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5244, 21, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5208, 11, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5178, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5172, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5168, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5167, 36, 35), //reboot|sethostname|setdomainname
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5170, 35, 34), //init_module|delete_module
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5173, 34, 33), //quotactl
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5205, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5194, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5193, 31, 30), //gettid|readahead|setxattr|lsetxattr|fsetxattr|getxattr|lgetxattr|fgetxattr|listxattr|llistxattr|flistxattr|removexattr|lremovexattr|fremovexattr|tkill
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5198, 30, 29), //futex|sched_setaffinity|sched_getaffinity|cacheflush
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5206, 29, 28), //exit_group
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5237, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5215, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5243, 20, 19), //set_thread_area
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5297, 9, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5271, 5, 0),
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5253, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5252, 3, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5247, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5246, 15, 14), //inotify_add_watch|inotify_rm_watch
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5251, 14, 13), //openat|mkdirat|mknodat|fchownat
-BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5267, 13, 12), //unlinkat|renameat|linkat|symlinkat|readlinkat|fchmodat|faccessat|pselect6|ppoll|unshare|splice|sync_file_range|tee|vmsplice
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5267, 13, 12), //newfstatat|unlinkat|renameat|linkat|symlinkat|readlinkat|fchmodat|faccessat|pselect6|ppoll|unshare|splice|sync_file_range|tee|vmsplice
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5279, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5276, 11, 10), //getcpu|epoll_pwait|ioprio_set|ioprio_get|utimensat
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5295, 10, 9), //fallocate|timerfd_create|timerfd_gettime|timerfd_settime|signalfd4|eventfd2|epoll_create1|dup3|pipe2|inotify_init1|preadv|pwritev|rt_tgsigqueueinfo|perf_event_open|accept4|recvmmsg
#elif defined __mips__ || defined __mips64__
#define DUAL_ARCH
-#define PRIMARY_ARCH AUDIT_ARCH_MIPS64
+#define PRIMARY_ARCH AUDIT_ARCH_MIPSEL64
static const struct sock_filter* primary_filter = mips64_filter;
static const size_t primary_filter_size = mips64_filter_size;
-#define SECONDARY_ARCH AUDIT_ARCH_MIPS
+#define SECONDARY_ARCH AUDIT_ARCH_MIPSEL
static const struct sock_filter* secondary_filter = mips_filter;
static const size_t secondary_filter_size = mips_filter_size;
#include <errno.h>
#include <stdlib.h>
+#include <async_safe/log.h>
+
#include "local.h"
-#include "private/libc_logging.h"
size_t __fbufsize(FILE* fp) {
return fp->_bf._size;
if (type != FSETLOCKING_INTERNAL && type != FSETLOCKING_BYCALLER) {
// The API doesn't let us report an error, so blow up.
- __libc_fatal("Bad type (%d) passed to __fsetlocking", type);
+ async_safe_fatal("Bad type (%d) passed to __fsetlocking", type);
}
_EXT(fp)->_caller_handles_locking = (type == FSETLOCKING_BYCALLER);
-/* $OpenBSD: exit.c,v 1.12 2007/09/03 14:40:16 millert Exp $ */
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
* SUCH DAMAGE.
*/
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <stdlib.h>
#include <unistd.h>
-/*
- * This variable is zero until a process has created a thread.
- * It is used to avoid calling locking functions in libc when they
- * are not required. By default, libc is intended to be(come)
- * thread-safe, but without a (significant) penalty to non-threaded
- * processes.
- */
-int __isthreaded = 0;
-
-/* BEGIN android-added: using __cxa_finalize and __cxa_thread_finalize */
extern void __cxa_finalize(void* dso_handle);
extern void __cxa_thread_finalize();
-/* END android-added */
-/*
- * Exit, flushing stdio buffers if necessary.
- */
-void
-exit(int status)
-{
- /* BEGIN android-added: call thread_local d-tors */
+void exit(int status) {
__cxa_thread_finalize();
- /* END android-added */
-
- /*
- * Call functions registered by atexit() or _cxa_atexit()
- * (including the stdio cleanup routine) and then _exit().
- */
- __cxa_finalize(NULL);
- _exit(status);
+ __cxa_finalize(NULL);
+ _exit(status);
}
#include <pthread.h>
#include <signal.h>
+#include <async_safe/log.h>
+
#include "private/bionic_prctl.h"
-#include "private/libc_logging.h"
// Android gets these from "thread_private.h".
#include "thread_private.h"
static inline void
_getentropy_fail(void)
{
- __libc_fatal("getentropy failed");
+ async_safe_fatal("getentropy failed");
}
volatile sig_atomic_t _rs_forked;
__LIBC_HIDDEN__ extern char* __findenv(const char*, int, int*);
__LIBC_HIDDEN__ extern char* _mktemp(char*);
-/* TODO: hide this when android_support.a is fixed (http://b/16298580).*/
-/*__LIBC_HIDDEN__*/ extern int __isthreaded;
-
#endif
android_init_anonymous_namespace;
android_create_namespace;
android_link_namespaces;
+ android_get_exported_namespace;
} LIBC_N;
android_init_anonymous_namespace;
android_create_namespace;
android_link_namespaces;
+ android_get_exported_namespace;
} LIBC_N;
__attribute__((__weak__, visibility("default")))
void __loader_android_dlwarning(void* obj, void (*f)(void*, const char*));
+__attribute__((__weak__, visibility("default")))
+struct android_namespace_t* __loader_android_get_exported_namespace(const char* name);
+
// Proxy calls to bionic loader
void* dlopen(const char* filename, int flag) {
const void* caller_addr = __builtin_return_address(0);
}
#endif
+/*
+ * This needs to be defined as weak because it is also defined in libc.a.
+ * Without this, static executables will have a multiple definition error.
+ */
+__attribute__((__weak__))
int dl_iterate_phdr(int (*cb)(struct dl_phdr_info* info, size_t size, void* data), void* data) {
return __loader_dl_iterate_phdr(cb, data);
}
void android_dlwarning(void* obj, void (*f)(void*, const char*)) {
__loader_android_dlwarning(obj, f);
}
+
+struct android_namespace_t* android_get_exported_namespace(const char* name) {
+ return __loader_android_get_exported_namespace(name);
+}
android_init_anonymous_namespace;
android_create_namespace;
android_link_namespaces;
+ android_get_exported_namespace;
} LIBC_N;
android_init_anonymous_namespace;
android_create_namespace;
android_link_namespaces;
+ android_get_exported_namespace;
} LIBC_N;
android_init_anonymous_namespace;
android_create_namespace;
android_link_namespaces;
+ android_get_exported_namespace;
} LIBC_N;
android_init_anonymous_namespace;
android_create_namespace;
android_link_namespaces;
+ android_get_exported_namespace;
} LIBC_N;
android_init_anonymous_namespace;
android_create_namespace;
android_link_namespaces;
+ android_get_exported_namespace;
} LIBC_N;
// We need to access Bionic private headers in the linker.
include_dirs: ["bionic/libc"],
+
+ static_libs: ["libasync_safe"],
}
cc_binary {
return success;
}
+android_namespace_t* __android_get_exported_namespace(const char* name) {
+ return get_exported_namespace(name);
+}
+
void __cfi_fail(uint64_t CallSiteTypeId, void* Ptr, void *DiagData, void *CallerPc) {
CFIShadowWriter::CfiFail(CallSiteTypeId, Ptr, DiagData, CallerPc);
}
// 4*
// 0000000 000111111111122222222223333 333333444444444455 555555556666666666777777777788888 888889999999999
// 0123456 789012345678901234567890123 456789012345678901 234567890123456789012345678901234 567890123456789
- "dlvsym\0__loader_android_dlwarning\0__loader_cfi_fail\0__loader_android_link_namespaces\0"
+ "dlvsym\0__loader_android_dlwarning\0__loader_cfi_fail\0__loader_android_link_namespaces\0__loader_androi"
+ // 5*
+ // 0000000000111111111122222 22222
+ // 0123456789012345678901234 56789
+ "d_get_exported_namespace\0"
#if defined(__arm__)
- // 485
+ // 525
"__loader_dl_unwind_find_exidx\0"
#endif
;
ELFW(SYM_INITIALIZER)(407, &__android_dlwarning, 1),
ELFW(SYM_INITIALIZER)(434, &__cfi_fail, 1),
ELFW(SYM_INITIALIZER)(452, &__android_link_namespaces, 1),
+ ELFW(SYM_INITIALIZER)(485, &__android_get_exported_namespace, 1),
#if defined(__arm__)
- ELFW(SYM_INITIALIZER)(485, &__dl_unwind_find_exidx, 1),
+ ELFW(SYM_INITIALIZER)(525, &__dl_unwind_find_exidx, 1),
#endif
};
// Note that adding any new symbols here requires stubbing them out in libdl.
static unsigned g_libdl_buckets[1] = { 1 };
#if defined(__arm__)
-static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 0 };
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0 };
#else
-static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 0 };
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 0 };
#endif
static uint8_t __libdl_info_buf[sizeof(soinfo)] __attribute__((aligned(8)));
#include <android-base/scopeguard.h>
+#include <async_safe/log.h>
+
// Private C library headers.
#include "linker.h"
#define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
static android_namespace_t* g_anonymous_namespace = &g_default_namespace;
+static std::unordered_map<std::string, android_namespace_t*> g_exported_namespaces;
static LinkerTypeAllocator<soinfo> g_soinfo_allocator;
static LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
static bool realpath_fd(int fd, std::string* realpath) {
std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
- __libc_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
+ async_safe_format_buffer(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
PRINT("readlink(\"%s\") failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
return false;
}
if (ref_count_ == 0) { // overflow
- __libc_fatal("Too many nested calls to dlopen()");
+ async_safe_fatal("Too many nested calls to dlopen()");
}
}
}
static bool format_path(char* buf, size_t buf_size, const char* path, const char* name) {
- int n = __libc_format_buffer(buf, buf_size, "%s/%s", path, name);
+ int n = async_safe_format_buffer(buf, buf_size, "%s/%s", path, name);
if (n < 0 || n >= static_cast<int>(buf_size)) {
PRINT("Warning: ignoring very long library path: %s/%s", path, name);
return false;
}
// TODO(dimitry): workaround for http://b/26394120 (the grey-list)
- if (fd == -1 && ns != &g_default_namespace && is_greylisted(ns, name, needed_by)) {
+ if (fd == -1 && ns->is_greylist_enabled() && is_greylisted(ns, name, needed_by)) {
// try searching for it on default_namespace default_library_path
fd = open_library_on_paths(zip_archive_cache, name, file_offset,
g_default_namespace.get_default_library_paths(), realpath);
}
} else {
#if !defined(__work_around_b_24465209__)
- __libc_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
+ async_safe_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
#else
PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
for_each_dt_needed(si, [&] (const char* library_name) {
}
if (buffer_size < required_size) {
- __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
- "buffer len %zu, required len %zu", buffer_size, required_size);
+ async_safe_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "
+ "buffer len %zu, required len %zu", buffer_size, required_size);
}
char* end = buffer;
android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();
ns->set_name(name);
ns->set_isolated((type & ANDROID_NAMESPACE_TYPE_ISOLATED) != 0);
- ns->set_ld_library_paths(std::move(ld_library_paths));
- ns->set_default_library_paths(std::move(default_library_paths));
- ns->set_permitted_paths(std::move(permitted_paths));
+ ns->set_greylist_enabled((type & ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED) != 0);
if ((type & ANDROID_NAMESPACE_TYPE_SHARED) != 0) {
+ // append parent namespace paths.
+ std::copy(parent_namespace->get_ld_library_paths().begin(),
+ parent_namespace->get_ld_library_paths().end(),
+ back_inserter(ld_library_paths));
+
+ std::copy(parent_namespace->get_default_library_paths().begin(),
+ parent_namespace->get_default_library_paths().end(),
+ back_inserter(default_library_paths));
+
+ std::copy(parent_namespace->get_permitted_paths().begin(),
+ parent_namespace->get_permitted_paths().end(),
+ back_inserter(permitted_paths));
+
// If shared - clone the parent namespace
add_soinfos_to_namespace(parent_namespace->soinfo_list(), ns);
+ // and copy parent namespace links
+ for (auto& link : parent_namespace->linked_namespaces()) {
+ ns->add_linked_namespace(link.linked_namespace(), link.shared_lib_sonames());
+ }
} else {
// If not shared - copy only the shared group
add_soinfos_to_namespace(get_shared_group(parent_namespace), ns);
}
+ ns->set_ld_library_paths(std::move(ld_library_paths));
+ ns->set_default_library_paths(std::move(default_library_paths));
+ ns->set_permitted_paths(std::move(permitted_paths));
+
return ns;
}
ns->set_permitted_paths(ns_config->permitted_paths());
namespaces[ns_config->name()] = ns;
+ if (ns_config->visible()) {
+ g_exported_namespaces[ns_config->name()] = ns;
+ }
}
// 3. Establish links between namespaces
set_application_target_sdk_version(config->target_sdk_version());
}
+
+// This function finds a namespace exported in ld.config.txt by its name.
+// A namespace can be exported by setting .visible property to true.
+android_namespace_t* get_exported_namespace(const char* name) {
+ if (name == nullptr) {
+ return nullptr;
+ }
+ auto it = g_exported_namespaces.find(std::string(name));
+ if (it == g_exported_namespaces.end()) {
+ return nullptr;
+ }
+ return it->second;
+}
#include <unistd.h>
#include "private/bionic_page.h"
-#include "private/libc_logging.h"
#include "linked_list.h"
#include "linker_common_types.h"
#include "linker_logger.h"
* permitted_path from the caller's namespace.
*/
ANDROID_NAMESPACE_TYPE_SHARED = 2,
+
+ /* This flag instructs linker to enable grey-list workaround for the namespace.
+ * See http://b/26394120 for details.
+ */
+ ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED = 0x08000000,
+
ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED = ANDROID_NAMESPACE_TYPE_SHARED |
ANDROID_NAMESPACE_TYPE_ISOLATED,
};
android_namespace_t* namespace_to,
const char* shared_lib_sonames);
+android_namespace_t* get_exported_namespace(const char* name);
+
#endif
#include <sys/mman.h>
#include <unistd.h>
+#include <async_safe/log.h>
+
#include "private/bionic_prctl.h"
//
ssize_t offset = reinterpret_cast<uintptr_t>(ptr) - sizeof(page_info);
if (offset % block_size_ != 0) {
- __libc_fatal("invalid pointer: %p (block_size=%zd)", ptr, block_size_);
+ async_safe_fatal("invalid pointer: %p (block_size=%zd)", ptr, block_size_);
}
memset(ptr, 0, block_size_);
if (it == page_records_.end() || it->page_addr != addr) {
// not found...
- __libc_fatal("page record for %p was not found (block_size=%zd)", ptr, block_size_);
+ async_safe_fatal("page record for %p was not found (block_size=%zd)", ptr, block_size_);
}
return it;
void* map_ptr = mmap(nullptr, PAGE_SIZE,
PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
if (map_ptr == MAP_FAILED) {
- __libc_fatal("mmap failed");
+ async_safe_fatal("mmap failed");
}
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, map_ptr, PAGE_SIZE, "linker_alloc_small_objects");
PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
if (map_ptr == MAP_FAILED) {
- __libc_fatal("mmap failed");
+ async_safe_fatal("mmap failed");
}
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, map_ptr, allocated_size, "linker_alloc_lob");
page_info* LinkerMemoryAllocator::get_page_info(void* ptr) {
page_info* info = reinterpret_cast<page_info*>(PAGE_START(reinterpret_cast<size_t>(ptr)));
if (memcmp(info->signature, kSignature, sizeof(kSignature)) != 0) {
- __libc_fatal("invalid pointer %p (page signature mismatch)", ptr);
+ async_safe_fatal("invalid pointer %p (page signature mismatch)", ptr);
}
return info;
} else {
LinkerSmallObjectAllocator* allocator = get_small_object_allocator(info->type);
if (allocator != info->allocator_addr) {
- __libc_fatal("invalid pointer %p (page signature mismatch)", ptr);
+ async_safe_fatal("invalid pointer %p (page signature mismatch)", ptr);
}
old_size = allocator->get_block_size();
} else {
LinkerSmallObjectAllocator* allocator = get_small_object_allocator(info->type);
if (allocator != info->allocator_addr) {
- __libc_fatal("invalid pointer %p (invalid allocator address for the page)", ptr);
+ async_safe_fatal("invalid pointer %p (invalid allocator address for the page)", ptr);
}
allocator->free(ptr);
LinkerSmallObjectAllocator* LinkerMemoryAllocator::get_small_object_allocator(uint32_t type) {
if (type < kSmallObjectMinSizeLog2 || type > kSmallObjectMaxSizeLog2) {
- __libc_fatal("invalid type: %u", type);
+ async_safe_fatal("invalid type: %u", type);
}
initialize_allocators();
#include <vector>
+#include <async_safe/log.h>
+
#include "private/bionic_prctl.h"
-#include "private/libc_logging.h"
const uint32_t kSmallObjectMaxSizeLog2 = 10;
const uint32_t kSmallObjectMinSizeLog2 = 4;
if (ptr == MAP_FAILED) {
// Spec says we need to throw std::bad_alloc here but because our
// code does not support exception handling anyways - we are going to abort.
- __libc_fatal("mmap failed");
+ async_safe_fatal("mmap failed");
}
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, size, "linker_alloc_vector");
#include <android-base/scopeguard.h>
#include <android-base/strings.h>
+#include <async_safe/log.h>
+
#include <stdlib.h>
#include <string>
size_t lineno,
const std::string& msg) {
char buf[1024];
- __libc_format_buffer(buf, sizeof(buf), "%s:%zu: error: %s", file, lineno, msg.c_str());
+ async_safe_format_buffer(buf, sizeof(buf), "%s:%zu: error: %s", file, lineno, msg.c_str());
return std::string(buf);
}
params.push_back({ "LIB", kLibParamValue });
if (target_sdk_version_ != 0) {
char buf[16];
- __libc_format_buffer(buf, sizeof(buf), "%d", target_sdk_version_);
+ async_safe_format_buffer(buf, sizeof(buf), "%d", target_sdk_version_);
params.push_back({ "SDK_VER", buf });
}
}
ns_config->set_isolated(properties.get_bool(property_name_prefix + ".isolated"));
+ ns_config->set_visible(properties.get_bool(property_name_prefix + ".visible"));
// these are affected by is_asan flag
if (is_asan) {
class NamespaceConfig {
public:
explicit NamespaceConfig(const std::string& name)
- : name_(name), isolated_(false)
+ : name_(name), isolated_(false), visible_(false)
{}
const char* name() const {
return isolated_;
}
+ bool visible() const {
+ return visible_;
+ }
+
const std::vector<std::string>& search_paths() const {
return search_paths_;
}
isolated_ = isolated;
}
+ void set_visible(bool visible) {
+ visible_ = visible;
+ }
+
void set_search_paths(std::vector<std::string>&& search_paths) {
search_paths_ = search_paths;
}
private:
const std::string name_;
bool isolated_;
+ bool visible_;
std::vector<std::string> search_paths_;
std::vector<std::string> permitted_paths_;
std::vector<NamespaceLinkConfig> namespace_links_;
* To enable/disable specific debug options, change the defines above
*********************************************************************/
-#include "private/libc_logging.h"
#include <unistd.h>
+#include <async_safe/log.h>
+
__LIBC_HIDDEN__ extern int g_ld_debug_verbosity;
#if LINKER_DEBUG_TO_LOG
#define _PRINTVF(v, x...) \
do { \
- if (g_ld_debug_verbosity > (v)) __libc_format_log(5-(v), "linker", x); \
+ if (g_ld_debug_verbosity > (v)) async_safe_format_log(5-(v), "linker", x); \
} while (0)
#else /* !LINKER_DEBUG_TO_LOG */
#define _PRINTVF(v, x...) \
do { \
- if (g_ld_debug_verbosity > (v)) { __libc_format_fd(1, x); write(1, "\n", 1); } \
+ if (g_ld_debug_verbosity > (v)) { async_safe_format_fd(1, x); write(1, "\n", 1); } \
} while (0)
#endif /* !LINKER_DEBUG_TO_LOG */
#include <unordered_map>
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
#define DL_ERR(fmt, x...) \
do { \
- __libc_format_buffer(linker_get_error_buffer(), linker_get_error_buffer_size(), fmt, ##x); \
+ async_safe_format_buffer(linker_get_error_buffer(), linker_get_error_buffer_size(), fmt, ##x); \
/* If LD_DEBUG is set high enough, log every dlerror(3) message. */ \
} while (false)
#define DL_WARN(fmt, x...) \
do { \
- __libc_format_log(ANDROID_LOG_WARN, "linker", fmt, ##x); \
- __libc_format_fd(2, "WARNING: linker: "); \
- __libc_format_fd(2, fmt, ##x); \
- __libc_format_fd(2, "\n"); \
+ async_safe_format_log(ANDROID_LOG_WARN, "linker", fmt, ##x); \
+ async_safe_format_fd(2, "WARNING: linker: "); \
+ async_safe_format_fd(2, fmt, ##x); \
+ async_safe_format_fd(2, "\n"); \
} while (false)
#define DL_ERR_AND_LOG(fmt, x...) \
* SUCH DAMAGE.
*/
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
void* __find_icu_symbol(const char* symbol_name __attribute__((__unused__))) {
- __libc_fatal("__find_icu_symbol should not be called in the linker");
+ async_safe_fatal("__find_icu_symbol should not be called in the linker");
}
#include <string>
#include <vector>
+#include <async_safe/log.h>
+
#include "android-base/strings.h"
#include "private/CachedProperty.h"
-#include "private/libc_logging.h"
LinkerLogger g_linker_logger;
bool g_greylist_disabled = false;
} else if (o == "dlsym") {
flags |= kLogDlsym;
} else {
- __libc_format_log(ANDROID_LOG_WARN, "linker", "Ignoring unknown debug.ld option \"%s\"",
- o.c_str());
+ async_safe_format_log(ANDROID_LOG_WARN, "linker", "Ignoring unknown debug.ld option \"%s\"",
+ o.c_str());
}
}
bool old_value = g_greylist_disabled;
g_greylist_disabled = (strcmp(greylist_disabled.Get(), "true") == 0);
if (g_greylist_disabled != old_value) {
- __libc_format_log(ANDROID_LOG_INFO, "linker", "%s greylist",
- g_greylist_disabled ? "Disabling" : "Enabling");
+ async_safe_format_log(ANDROID_LOG_INFO, "linker", "%s greylist",
+ g_greylist_disabled ? "Disabling" : "Enabling");
}
flags_ = 0;
va_list ap;
va_start(ap, format);
- __libc_format_log_va_list(ANDROID_LOG_DEBUG, "linker", format, ap);
+ async_safe_format_log_va_list(ANDROID_LOG_DEBUG, "linker", format, ap);
va_end(ap);
}
#include "debuggerd/handler.h"
#endif
+#include <async_safe/log.h>
+
#include <vector>
extern void __libc_init_globals(KernelArgumentBlock&);
char path[PATH_MAX];
ssize_t path_len = readlink("/proc/self/exe", path, sizeof(path));
if (path_len == -1 || path_len >= static_cast<ssize_t>(sizeof(path))) {
- __libc_fatal("readlink('/proc/self/exe') failed: %s", strerror(errno));
+ async_safe_fatal("readlink('/proc/self/exe') failed: %s", strerror(errno));
}
executable_path = std::string(path, path_len);
}
// the executable could be unlinked by this point and it should
// not cause a crash (see http://b/31084669)
if (TEMP_FAILURE_RETRY(stat("/proc/self/exe", &file_stat)) != 0) {
- __libc_fatal("unable to stat \"/proc/self/exe\": %s", strerror(errno));
+ async_safe_fatal("unable to stat \"/proc/self/exe\": %s", strerror(errno));
}
const char* executable_path = get_executable_path();
soinfo* si = soinfo_alloc(&g_default_namespace, executable_path, &file_stat, 0, RTLD_GLOBAL);
if (si == nullptr) {
- __libc_fatal("Couldn't allocate soinfo: out of memory?");
+ async_safe_fatal("Couldn't allocate soinfo: out of memory?");
}
/* bootstrap the link map, the main exe always needs to be first */
// tombstone for them. The tombstone never provided any detail relevant to
// fixing the problem anyway, and the utility of drawing extra attention
// to the problem is non-existent at this late date.
- __libc_format_fd(STDERR_FILENO,
+ async_safe_format_fd(STDERR_FILENO,
"\"%s\": error: Android 5.0 and later only support "
"position-independent executables (-fPIE).\n",
g_argv[0]);
init_default_namespace(executable_path);
if (!si->prelink_image()) {
- __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
+ async_safe_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
}
// add somain to global group
nullptr,
true /* add_as_children */,
true /* search_linked_namespaces */)) {
- __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
+ async_safe_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
} else if (needed_libraries_count == 0) {
if (!si->link_image(g_empty_list, soinfo_list_t::make_list(si), nullptr)) {
- __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
+ async_safe_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
}
si->increment_ref_count();
}
add_vdso(args);
if (!get_cfi_shadow()->InitialLinkDone(solist)) {
- __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
+ async_safe_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
}
si->call_pre_init_constructors();
}
static void __linker_cannot_link(const char* argv0) {
- __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", argv0, linker_get_error_buffer());
+ async_safe_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", argv0, linker_get_error_buffer());
}
/*
// This happens when user tries to run 'adb shell /system/bin/linker'
// see also https://code.google.com/p/android/issues/detail?id=63174
if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) {
- __libc_format_fd(STDOUT_FILENO,
+ async_safe_format_fd(STDOUT_FILENO,
"This is %s, the helper program for dynamic executables.\n",
args.argv[0]);
exit(0);
#include <sys/cdefs.h>
#include <unistd.h>
-#include "private/libc_logging.h"
+#include <async_safe/log.h>
static LinkerMemoryAllocator g_linker_allocator;
static pid_t fallback_tid = 0;
// case the linker heap is corrupted. Do not use this function.
extern "C" void __linker_enable_fallback_allocator() {
if (fallback_tid != 0) {
- __libc_fatal("attempted to use currently-in-use fallback allocator");
+ async_safe_fatal("attempted to use currently-in-use fallback allocator");
}
fallback_tid = gettid();
extern "C" void __linker_disable_fallback_allocator() {
if (fallback_tid == 0) {
- __libc_fatal("attempted to disable unused fallback allocator");
+ async_safe_fatal("attempted to disable unused fallback allocator");
}
fallback_tid = 0;
return linked_namespace_;
}
+ const std::unordered_set<std::string>& shared_lib_sonames() const {
+ return shared_lib_sonames_;
+ }
+
bool is_accessible(const char* soname) const {
return shared_lib_sonames_.find(soname) != shared_lib_sonames_.end();
}
struct android_namespace_t {
public:
- android_namespace_t() : name_(nullptr), is_isolated_(false) {}
+ android_namespace_t() : name_(nullptr), is_isolated_(false), is_greylist_enabled_(false) {}
const char* get_name() const { return name_; }
void set_name(const char* name) { name_ = name; }
bool is_isolated() const { return is_isolated_; }
void set_isolated(bool isolated) { is_isolated_ = isolated; }
+ bool is_greylist_enabled() const { return is_greylist_enabled_; }
+ void set_greylist_enabled(bool enabled) { is_greylist_enabled_ = enabled; }
+
const std::vector<std::string>& get_ld_library_paths() const {
return ld_library_paths_;
}
private:
const char* name_;
bool is_isolated_;
+ bool is_greylist_enabled_;
std::vector<std::string> ld_library_paths_;
std::vector<std::string> default_library_paths_;
std::vector<std::string> permitted_paths_;
#include <stdint.h>
+#include <async_safe/log.h>
+
#include "linker_debug.h"
// Helper classes for decoding LEB128, used in packed relocation data.
do {
if (current_ >= end_) {
- __libc_fatal("sleb128_decoder ran out of bounds");
+ async_safe_fatal("sleb128_decoder ran out of bounds");
}
byte = *current_++;
value |= (static_cast<size_t>(byte & 127) << shift);
#include <sys/stat.h>
#include <unistd.h>
+#include <async_safe/log.h>
+
#include "linker_debug.h"
#include "linker_globals.h"
#include "linker_logger.h"
const char* soinfo::get_string(ElfW(Word) index) const {
if (has_min_version(1) && (index >= strtab_size_)) {
- __libc_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d",
+ async_safe_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d",
get_realpath(), strtab_size_, index);
}
../linker_config.cpp \
../linker_utils.cpp \
-# for __libc_fatal
-LOCAL_SRC_FILES += ../../libc/bionic/libc_logging.cpp
-
-LOCAL_STATIC_LIBRARIES += libbase
+LOCAL_STATIC_LIBRARIES += libasync_safe libbase
include $(BUILD_NATIVE_TEST)
"namespace.default.links = system\n"
"namespace.default.link.system.shared_libs = libc.so:libm.so:libdl.so:libstdc++.so\n"
"namespace.system.isolated = true\n"
+ "namespace.system.visible = true\n"
"namespace.system.search.paths = /system/${LIB}\n"
"namespace.system.permitted.paths = /system/${LIB}\n"
"namespace.system.asan.search.paths = /data:/system/${LIB}\n"
ASSERT_TRUE(default_ns_config != nullptr);
ASSERT_TRUE(default_ns_config->isolated());
+ ASSERT_FALSE(default_ns_config->visible());
ASSERT_EQ(kExpectedDefaultSearchPath, default_ns_config->search_paths());
ASSERT_EQ(kExpectedDefaultPermittedPath, default_ns_config->permitted_paths());
ASSERT_TRUE(ns_system != nullptr) << "system namespace was not found";
ASSERT_TRUE(ns_system->isolated());
+ ASSERT_TRUE(ns_system->visible());
ASSERT_EQ(kExpectedSystemSearchPath, ns_system->search_paths());
ASSERT_EQ(kExpectedSystemPermittedPath, ns_system->permitted_paths());
}
defaults: ["bionic_tests_defaults"],
srcs: [
"arpa_inet_test.cpp",
+ "async_safe_test.cpp",
"assert_test.cpp",
"buffer_tests.cpp",
"bug_26110743_test.cpp",
"complex_test.cpp",
"ctype_test.cpp",
"dirent_test.cpp",
+ "elf_test.cpp",
"endian_test.cpp",
"error_test.cpp",
"eventfd_test.cpp",
"inttypes_test.cpp",
"langinfo_test.cpp",
"leak_test.cpp",
- "libc_logging_test.cpp",
"libgen_basename_test.cpp",
"libgen_test.cpp",
"linux_swab_test.cpp",
"external/tinyxml2",
],
+ target: {
+ android: {
+ whole_static_libs: ["libasync_safe"],
+ },
+ },
+
static_libs: [
"libtinyxml2",
"liblog",
#include <gtest/gtest.h>
#if defined(__BIONIC__)
-#include "../libc/bionic/libc_logging.cpp"
-extern int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...);
+#include <async_safe/log.h>
#endif // __BIONIC__
-TEST(libc_logging, smoke) {
+TEST(async_safe_log, smoke) {
#if defined(__BIONIC__)
char buf[BUFSIZ];
- __libc_format_buffer(buf, sizeof(buf), "a");
+ async_safe_format_buffer(buf, sizeof(buf), "a");
EXPECT_STREQ("a", buf);
- __libc_format_buffer(buf, sizeof(buf), "%%");
+ async_safe_format_buffer(buf, sizeof(buf), "%%");
EXPECT_STREQ("%", buf);
- __libc_format_buffer(buf, sizeof(buf), "01234");
+ async_safe_format_buffer(buf, sizeof(buf), "01234");
EXPECT_STREQ("01234", buf);
- __libc_format_buffer(buf, sizeof(buf), "a%sb", "01234");
+ async_safe_format_buffer(buf, sizeof(buf), "a%sb", "01234");
EXPECT_STREQ("a01234b", buf);
char* s = NULL;
- __libc_format_buffer(buf, sizeof(buf), "a%sb", s);
+ async_safe_format_buffer(buf, sizeof(buf), "a%sb", s);
EXPECT_STREQ("a(null)b", buf);
- __libc_format_buffer(buf, sizeof(buf), "aa%scc", "bb");
+ async_safe_format_buffer(buf, sizeof(buf), "aa%scc", "bb");
EXPECT_STREQ("aabbcc", buf);
- __libc_format_buffer(buf, sizeof(buf), "a%cc", 'b');
+ async_safe_format_buffer(buf, sizeof(buf), "a%cc", 'b');
EXPECT_STREQ("abc", buf);
- __libc_format_buffer(buf, sizeof(buf), "a%db", 1234);
+ async_safe_format_buffer(buf, sizeof(buf), "a%db", 1234);
EXPECT_STREQ("a1234b", buf);
- __libc_format_buffer(buf, sizeof(buf), "a%db", -8123);
+ async_safe_format_buffer(buf, sizeof(buf), "a%db", -8123);
EXPECT_STREQ("a-8123b", buf);
- __libc_format_buffer(buf, sizeof(buf), "a%hdb", static_cast<short>(0x7fff0010));
+ async_safe_format_buffer(buf, sizeof(buf), "a%hdb", static_cast<short>(0x7fff0010));
EXPECT_STREQ("a16b", buf);
- __libc_format_buffer(buf, sizeof(buf), "a%hhdb", static_cast<char>(0x7fffff10));
+ async_safe_format_buffer(buf, sizeof(buf), "a%hhdb", static_cast<char>(0x7fffff10));
EXPECT_STREQ("a16b", buf);
- __libc_format_buffer(buf, sizeof(buf), "a%lldb", 0x1000000000LL);
+ async_safe_format_buffer(buf, sizeof(buf), "a%lldb", 0x1000000000LL);
EXPECT_STREQ("a68719476736b", buf);
- __libc_format_buffer(buf, sizeof(buf), "a%ldb", 70000L);
+ async_safe_format_buffer(buf, sizeof(buf), "a%ldb", 70000L);
EXPECT_STREQ("a70000b", buf);
- __libc_format_buffer(buf, sizeof(buf), "a%pb", reinterpret_cast<void*>(0xb0001234));
+ async_safe_format_buffer(buf, sizeof(buf), "a%pb", reinterpret_cast<void*>(0xb0001234));
EXPECT_STREQ("a0xb0001234b", buf);
- __libc_format_buffer(buf, sizeof(buf), "a%xz", 0x12ab);
+ async_safe_format_buffer(buf, sizeof(buf), "a%xz", 0x12ab);
EXPECT_STREQ("a12abz", buf);
- __libc_format_buffer(buf, sizeof(buf), "a%Xz", 0x12ab);
+ async_safe_format_buffer(buf, sizeof(buf), "a%Xz", 0x12ab);
EXPECT_STREQ("a12ABz", buf);
- __libc_format_buffer(buf, sizeof(buf), "a%08xz", 0x123456);
+ async_safe_format_buffer(buf, sizeof(buf), "a%08xz", 0x123456);
EXPECT_STREQ("a00123456z", buf);
- __libc_format_buffer(buf, sizeof(buf), "a%5dz", 1234);
+ async_safe_format_buffer(buf, sizeof(buf), "a%5dz", 1234);
EXPECT_STREQ("a 1234z", buf);
- __libc_format_buffer(buf, sizeof(buf), "a%05dz", 1234);
+ async_safe_format_buffer(buf, sizeof(buf), "a%05dz", 1234);
EXPECT_STREQ("a01234z", buf);
- __libc_format_buffer(buf, sizeof(buf), "a%8dz", 1234);
+ async_safe_format_buffer(buf, sizeof(buf), "a%8dz", 1234);
EXPECT_STREQ("a 1234z", buf);
- __libc_format_buffer(buf, sizeof(buf), "a%-8dz", 1234);
+ async_safe_format_buffer(buf, sizeof(buf), "a%-8dz", 1234);
EXPECT_STREQ("a1234 z", buf);
- __libc_format_buffer(buf, sizeof(buf), "A%-11sZ", "abcdef");
+ async_safe_format_buffer(buf, sizeof(buf), "A%-11sZ", "abcdef");
EXPECT_STREQ("Aabcdef Z", buf);
- __libc_format_buffer(buf, sizeof(buf), "A%s:%dZ", "hello", 1234);
+ async_safe_format_buffer(buf, sizeof(buf), "A%s:%dZ", "hello", 1234);
EXPECT_STREQ("Ahello:1234Z", buf);
- __libc_format_buffer(buf, sizeof(buf), "a%03d:%d:%02dz", 5, 5, 5);
+ async_safe_format_buffer(buf, sizeof(buf), "a%03d:%d:%02dz", 5, 5, 5);
EXPECT_STREQ("a005:5:05z", buf);
void* p = NULL;
- __libc_format_buffer(buf, sizeof(buf), "a%d,%pz", 5, p);
+ async_safe_format_buffer(buf, sizeof(buf), "a%d,%pz", 5, p);
EXPECT_STREQ("a5,0x0z", buf);
- __libc_format_buffer(buf, sizeof(buf), "a%lld,%d,%d,%dz", 0x1000000000LL, 6, 7, 8);
+ async_safe_format_buffer(buf, sizeof(buf), "a%lld,%d,%d,%dz", 0x1000000000LL, 6, 7, 8);
EXPECT_STREQ("a68719476736,6,7,8z", buf);
#else // __BIONIC__
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif // __BIONIC__
}
-TEST(libc_logging, d_INT_MAX) {
+TEST(async_safe_log, d_INT_MAX) {
#if defined(__BIONIC__)
char buf[BUFSIZ];
- __libc_format_buffer(buf, sizeof(buf), "%d", INT_MAX);
+ async_safe_format_buffer(buf, sizeof(buf), "%d", INT_MAX);
EXPECT_STREQ("2147483647", buf);
#else // __BIONIC__
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif // __BIONIC__
}
-TEST(libc_logging, d_INT_MIN) {
+TEST(async_safe_log, d_INT_MIN) {
#if defined(__BIONIC__)
char buf[BUFSIZ];
- __libc_format_buffer(buf, sizeof(buf), "%d", INT_MIN);
+ async_safe_format_buffer(buf, sizeof(buf), "%d", INT_MIN);
EXPECT_STREQ("-2147483648", buf);
#else // __BIONIC__
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif // __BIONIC__
}
-TEST(libc_logging, ld_LONG_MAX) {
+TEST(async_safe_log, ld_LONG_MAX) {
#if defined(__BIONIC__)
char buf[BUFSIZ];
- __libc_format_buffer(buf, sizeof(buf), "%ld", LONG_MAX);
+ async_safe_format_buffer(buf, sizeof(buf), "%ld", LONG_MAX);
#if defined(__LP64__)
EXPECT_STREQ("9223372036854775807", buf);
#else
#endif // __BIONIC__
}
-TEST(libc_logging, ld_LONG_MIN) {
+TEST(async_safe_log, ld_LONG_MIN) {
#if defined(__BIONIC__)
char buf[BUFSIZ];
- __libc_format_buffer(buf, sizeof(buf), "%ld", LONG_MIN);
+ async_safe_format_buffer(buf, sizeof(buf), "%ld", LONG_MIN);
#if defined(__LP64__)
EXPECT_STREQ("-9223372036854775808", buf);
#else
#endif // __BIONIC__
}
-TEST(libc_logging, lld_LLONG_MAX) {
+TEST(async_safe_log, lld_LLONG_MAX) {
#if defined(__BIONIC__)
char buf[BUFSIZ];
- __libc_format_buffer(buf, sizeof(buf), "%lld", LLONG_MAX);
+ async_safe_format_buffer(buf, sizeof(buf), "%lld", LLONG_MAX);
EXPECT_STREQ("9223372036854775807", buf);
#else // __BIONIC__
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif // __BIONIC__
}
-TEST(libc_logging, lld_LLONG_MIN) {
+TEST(async_safe_log, lld_LLONG_MIN) {
#if defined(__BIONIC__)
char buf[BUFSIZ];
- __libc_format_buffer(buf, sizeof(buf), "%lld", LLONG_MIN);
+ async_safe_format_buffer(buf, sizeof(buf), "%lld", LLONG_MIN);
EXPECT_STREQ("-9223372036854775808", buf);
#else // __BIONIC__
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif // __BIONIC__
}
-TEST(libc_logging, buffer_overrun) {
+TEST(async_safe_log, buffer_overrun) {
#if defined(__BIONIC__)
char buf[BUFSIZ];
- ASSERT_EQ(11, __libc_format_buffer(buf, sizeof(buf), "hello %s", "world"));
+ ASSERT_EQ(11, async_safe_format_buffer(buf, sizeof(buf), "hello %s", "world"));
EXPECT_STREQ("hello world", buf);
- ASSERT_EQ(11, __libc_format_buffer(buf, 8, "hello %s", "world"));
+ ASSERT_EQ(11, async_safe_format_buffer(buf, 8, "hello %s", "world"));
EXPECT_STREQ("hello w", buf);
#else // __BIONIC__
GTEST_LOG_(INFO) << "This test does nothing.\n";
* permitted_path from the caller's namespace.
*/
ANDROID_NAMESPACE_TYPE_SHARED = 2,
+
+ /* This flag instructs linker to enable grey-list workaround for the namespace.
+ * See http://b/26394120 for details.
+ */
+ ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED = 0x08000000,
+
ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED = ANDROID_NAMESPACE_TYPE_SHARED |
ANDROID_NAMESPACE_TYPE_ISOLATED,
};
#include <unistd.h>
#include <android/dlext.h>
+#include <android-base/strings.h>
#include <linux/memfd.h>
#include <sys/mman.h>
EXPECT_EQ(1729U, *taxicab_number);
}
- void SpawnChildrenAndMeasurePss(const char* lib, bool share_relro, size_t* pss_out);
+ void SpawnChildrenAndMeasurePss(const char* lib, const char* relro_file, bool share_relro,
+ size_t* pss_out);
android_dlextinfo extinfo_;
};
ASSERT_NOERROR(pipe(pipefd));
size_t without_sharing, with_sharing;
- ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(kLibName, false, &without_sharing));
- ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(kLibName, true, &with_sharing));
+ ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(kLibName, tf.filename, false, &without_sharing));
+ ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(kLibName, tf.filename, true, &with_sharing));
+ ASSERT_LT(with_sharing, without_sharing);
- // We expect the sharing to save at least 10% of the total PSS. In practice
- // it saves 40%+ for this test.
- size_t expected_size = without_sharing - (without_sharing/10);
- EXPECT_LT(with_sharing, expected_size);
+ // We expect the sharing to save at least 50% of the library's total PSS.
+ // In practice it saves 80%+ for this library in the test.
+ size_t pss_saved = without_sharing - with_sharing;
+ size_t expected_min_saved = without_sharing / 2;
+
+ EXPECT_LT(expected_min_saved, pss_saved);
// Use destructor of tf to close and unlink the file.
tf.fd = extinfo_.relro_fd;
}
-void getPss(pid_t pid, size_t* pss_out) {
+void GetPss(bool shared_relro, const char* lib, const char* relro_file, pid_t pid,
+ size_t* total_pss) {
pm_kernel_t* kernel;
ASSERT_EQ(0, pm_kernel_create(&kernel));
size_t num_maps;
ASSERT_EQ(0, pm_process_maps(process, &maps, &num_maps));
- size_t total_pss = 0;
- for (size_t i = 0; i < num_maps; i++) {
- pm_memusage_t usage;
- ASSERT_EQ(0, pm_map_usage(maps[i], &usage));
- total_pss += usage.pss;
+ // Calculate total PSS of the library.
+ *total_pss = 0;
+ bool saw_relro_file = false;
+ for (size_t i = 0; i < num_maps; ++i) {
+ if (android::base::EndsWith(maps[i]->name, lib) || strcmp(maps[i]->name, relro_file) == 0) {
+ if (strcmp(maps[i]->name, relro_file) == 0) saw_relro_file = true;
+
+ pm_memusage_t usage;
+ ASSERT_EQ(0, pm_map_usage(maps[i], &usage));
+ *total_pss += usage.pss;
+ }
}
- *pss_out = total_pss;
free(maps);
pm_process_destroy(process);
pm_kernel_destroy(kernel);
+
+ if (shared_relro) ASSERT_TRUE(saw_relro_file);
}
-void DlExtRelroSharingTest::SpawnChildrenAndMeasurePss(const char* lib, bool share_relro,
- size_t* pss_out) {
+void DlExtRelroSharingTest::SpawnChildrenAndMeasurePss(const char* lib, const char* relro_file,
+ bool share_relro, size_t* pss_out) {
const int CHILDREN = 20;
// Create children
childpipe[i] = parent_done_pipe[1];
}
- // Sum the PSS of all the children
+ // Sum the PSS of tested library of all the children
size_t total_pss = 0;
for (int i=0; i<CHILDREN; ++i) {
size_t child_pss;
- ASSERT_NO_FATAL_FAILURE(getPss(child_pids[i], &child_pss));
+ ASSERT_NO_FATAL_FAILURE(GetPss(share_relro, lib, relro_file, child_pids[i], &child_pss));
total_pss += child_pss;
}
*pss_out = total_pss;
"\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
}
-TEST(dlext, ns_greylist) {
+TEST(dlext, ns_greylist_enabled) {
ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
const std::string ns_search_path = get_testlib_root() + "/private_namespace_libs";
android_create_namespace("namespace",
nullptr,
ns_search_path.c_str(),
- ANDROID_NAMESPACE_TYPE_ISOLATED,
+ ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED,
nullptr,
nullptr);
ASSERT_STREQ("dlopen failed: library \"libnativehelper.so\" not found", dlerror());
}
+TEST(dlext, ns_greylist_disabled_by_default) {
+ ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
+
+ const std::string ns_search_path = get_testlib_root() + "/private_namespace_libs";
+
+ android_namespace_t* ns =
+ android_create_namespace("namespace",
+ nullptr,
+ ns_search_path.c_str(),
+ ANDROID_NAMESPACE_TYPE_ISOLATED,
+ nullptr,
+ nullptr);
+
+ ASSERT_TRUE(android_link_namespaces(ns, nullptr, g_core_shared_libs.c_str())) << dlerror();
+
+ android_dlextinfo extinfo;
+ extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+ extinfo.library_namespace = ns;
+
+ android_set_application_target_sdk_version(__ANDROID_API_M__);
+ void* handle = android_dlopen_ext("libnativehelper.so", RTLD_NOW, &extinfo);
+ ASSERT_TRUE(handle == nullptr);
+ ASSERT_STREQ("dlopen failed: library \"libnativehelper.so\" not found", dlerror());
+}
+
TEST(dlext, ns_cyclic_namespaces) {
// Test that ns1->ns2->ns1 link does not break the loader
ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
dlclose(handle2);
}
+TEST(dlext, ns_shared_links_and_paths) {
+ // Create parent namespace (isolated, not shared)
+ android_namespace_t* ns_isolated =
+ android_create_namespace("private_isolated",
+ nullptr,
+ (get_testlib_root() + "/private_namespace_libs").c_str(),
+ ANDROID_NAMESPACE_TYPE_ISOLATED,
+ (get_testlib_root() + "/public_namespace_libs").c_str(),
+ nullptr);
+ ASSERT_TRUE(ns_isolated != nullptr) << dlerror();
+ ASSERT_TRUE(android_link_namespaces(ns_isolated, nullptr, g_core_shared_libs.c_str())) << dlerror();
+
+ // Create shared namespace with ns_isolated parent
+ android_namespace_t* ns_shared =
+ android_create_namespace("private_shared",
+ nullptr,
+ nullptr,
+ ANDROID_NAMESPACE_TYPE_SHARED | ANDROID_NAMESPACE_TYPE_ISOLATED,
+ nullptr,
+ ns_isolated);
+ ASSERT_TRUE(ns_shared != nullptr) << dlerror();
+
+ // 1. Load a library in ns_shared to check that it has inherited
+ // search path and the link to the default namespace.
+ android_dlextinfo extinfo;
+ extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+ extinfo.library_namespace = ns_shared;
+
+ {
+ void* handle = android_dlopen_ext("libnstest_private.so", RTLD_NOW, &extinfo);
+ ASSERT_TRUE(handle != nullptr) << dlerror();
+ const char** ns_private_extern_string = static_cast<const char**>(dlsym(handle, "g_private_extern_string"));
+ ASSERT_TRUE(ns_private_extern_string != nullptr) << dlerror();
+ ASSERT_STREQ("This string is from private namespace", *ns_private_extern_string);
+
+ dlclose(handle);
+ }
+ // 2. Load another test library by absolute path to check that
+ // it has inherited permitted_when_isolated_path
+ {
+ void* handle = android_dlopen_ext(
+ (get_testlib_root() + "/public_namespace_libs/libnstest_public.so").c_str(),
+ RTLD_NOW,
+ &extinfo);
+
+ ASSERT_TRUE(handle != nullptr) << dlerror();
+ const char** ns_public_extern_string = static_cast<const char**>(dlsym(handle, "g_public_extern_string"));
+ ASSERT_TRUE(ns_public_extern_string != nullptr) << dlerror();
+ ASSERT_STREQ("This string is from public namespace", *ns_public_extern_string);
+
+ dlclose(handle);
+ }
+
+ // 3. Check that it is still isolated.
+ {
+ void* handle = android_dlopen_ext(
+ (get_testlib_root() + "/libtest_empty.so").c_str(),
+ RTLD_NOW,
+ &extinfo);
+
+ ASSERT_TRUE(handle == nullptr);
+ }
+}
+
TEST(dlext, ns_shared_dlclose) {
android_set_application_target_sdk_version(42U); // something > 23
// mips doesn't support ifuncs
#if !defined(__mips__)
+TEST(dlfcn, ifunc_variable) {
+ typedef const char* (*fn_ptr)();
+
+ // ifunc's choice depends on whether IFUNC_CHOICE has a value
+ // first check the set case
+ setenv("IFUNC_CHOICE", "set", 1);
+ // preload libtest_ifunc_variable_impl.so
+ void* handle_impl = dlopen("libtest_ifunc_variable_impl.so", RTLD_NOW);
+ void* handle = dlopen("libtest_ifunc_variable.so", RTLD_NOW);
+ ASSERT_TRUE(handle != nullptr) << dlerror();
+ const char** foo_ptr = reinterpret_cast<const char**>(dlsym(handle, "foo"));
+ fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
+ ASSERT_TRUE(foo_ptr != nullptr) << dlerror();
+ ASSERT_TRUE(foo_library_ptr != nullptr) << dlerror();
+ ASSERT_EQ(strncmp("set", *foo_ptr, 3), 0);
+ ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0);
+ dlclose(handle);
+ dlclose(handle_impl);
+
+ // then check the unset case
+ unsetenv("IFUNC_CHOICE");
+ handle_impl = dlopen("libtest_ifunc_variable_impl.so", RTLD_NOW);
+ handle = dlopen("libtest_ifunc_variable.so", RTLD_NOW);
+ ASSERT_TRUE(handle != nullptr) << dlerror();
+ foo_ptr = reinterpret_cast<const char**>(dlsym(handle, "foo"));
+ foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
+ ASSERT_TRUE(foo_ptr != nullptr) << dlerror();
+ ASSERT_TRUE(foo_library_ptr != nullptr) << dlerror();
+ ASSERT_EQ(strncmp("unset", *foo_ptr, 5), 0);
+ ASSERT_EQ(strncmp("unset", foo_library_ptr(), 5), 0);
+ dlclose(handle);
+ dlclose(handle_impl);
+}
+
TEST(dlfcn, ifunc) {
typedef const char* (*fn_ptr)();
// first check the set case
setenv("IFUNC_CHOICE", "set", 1);
void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
- ASSERT_TRUE(handle != nullptr);
+ ASSERT_TRUE(handle != nullptr) << dlerror();
fn_ptr foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
- ASSERT_TRUE(foo_ptr != nullptr);
- ASSERT_TRUE(foo_library_ptr != nullptr);
+ ASSERT_TRUE(foo_ptr != nullptr) << dlerror();
+ ASSERT_TRUE(foo_library_ptr != nullptr) << dlerror();
ASSERT_EQ(strncmp("set", foo_ptr(), 3), 0);
ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0);
dlclose(handle);
// then check the unset case
unsetenv("IFUNC_CHOICE");
handle = dlopen("libtest_ifunc.so", RTLD_NOW);
- ASSERT_TRUE(handle != nullptr);
+ ASSERT_TRUE(handle != nullptr) << dlerror();
foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
- ASSERT_TRUE(foo_ptr != nullptr);
- ASSERT_TRUE(foo_library_ptr != nullptr);
+ ASSERT_TRUE(foo_ptr != nullptr) << dlerror();
+ ASSERT_TRUE(foo_library_ptr != nullptr) << dlerror();
ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0);
- ASSERT_EQ(strncmp("unset", foo_library_ptr(), 3), 0);
+ ASSERT_EQ(strncmp("unset", foo_library_ptr(), 5), 0);
dlclose(handle);
}
-// ld.gold for arm produces incorrect binary (see http://b/27930475 for details)
-#if defined(__arm__)
-TEST(dlfcn, KNOWN_FAILURE_ON_BIONIC(ifunc_ctor_call)) {
-#else
TEST(dlfcn, ifunc_ctor_call) {
-#endif
typedef const char* (*fn_ptr)();
void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
dlclose(handle);
}
-// ld.gold for arm produces incorrect binary (see http://b/27930475 for details)
-#if defined(__arm__)
-TEST(dlfcn, KNOWN_FAILURE_ON_BIONIC(ifunc_ctor_call_rtld_lazy)) {
-#else
TEST(dlfcn, ifunc_ctor_call_rtld_lazy) {
-#endif
typedef const char* (*fn_ptr)();
void* handle = dlopen("libtest_ifunc.so", RTLD_LAZY);
--- /dev/null
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <elf.h>
+
+#include <gtest/gtest.h>
+
+// https://github.com/android-ndk/ndk/issues/377
+TEST(elf, have_ELF_ST_INFO_macros) {
+ uint8_t info;
+
+ // 0x0f
+ info = ELF32_ST_INFO(STB_LOCAL, STT_HIPROC);
+ ASSERT_EQ(STB_LOCAL, ELF32_ST_BIND(info));
+ ASSERT_EQ(STT_HIPROC, ELF32_ST_TYPE(info));
+
+ // 0x0f
+ info = ELF64_ST_INFO(STB_LOCAL, STT_HIPROC);
+ ASSERT_EQ(STB_LOCAL, ELF64_ST_BIND(info));
+ ASSERT_EQ(STT_HIPROC, ELF64_ST_TYPE(info));
+
+ // 0xf0
+ info = ELF32_ST_INFO(STB_LOCAL, STT_HIPROC);
+ ASSERT_EQ(STB_LOCAL, ELF32_ST_BIND(info));
+ ASSERT_EQ(STT_HIPROC, ELF32_ST_TYPE(info));
+
+ // 0xf0
+ info = ELF64_ST_INFO(STB_LOCAL, STT_HIPROC);
+ ASSERT_EQ(STB_LOCAL, ELF64_ST_BIND(info));
+ ASSERT_EQ(STT_HIPROC, ELF64_ST_TYPE(info));
+}
#endif // __BIONIC__
}
-// this buffer overflow. TODO: Fix clang.
TEST_F(DEATHTEST, strlcpy_fortified2) {
#if defined(__BIONIC__)
foo myfoo;
#endif // __BIONIC__
}
-// this buffer overflow. TODO: Fix clang.
TEST_F(DEATHTEST, strlcat_fortified2) {
#if defined(__BIONIC__)
foo myfoo;
ASSERT_FORTIFY(sprintf(buf, "%s", source_buf));
}
-#ifdef __clang__
-// Exists upstream, but hasn't been pulled in yet.
-#if __has_attribute(alloc_size)
-#error "Reenable this test"
-#endif
+#ifdef __clang__ && !__has_attribute(alloc_size)
+// TODO: remove this after Clang prebuilt rebase.
#else
// This test is disabled in clang because clang doesn't properly detect
// this buffer overflow. TODO: Fix clang.
gtest_filter_str = "-bionic_selftest*";
} else {
// Find if '-' for NEGATIVE_PATTERNS exists.
- if (gtest_filter_str.find("-") != std::string::npos) {
+ if (gtest_filter_str.find('-') != std::string::npos) {
gtest_filter_str += ":bionic_selftest*";
} else {
gtest_filter_str += ":-bionic_selftest*";
return result;
}
-#define LEAK_TEST(test_case_name, test_name) \
- static void __leak_test__##test_case_name##__##test_name(); \
- TEST(test_case_name, test_name) { \
- auto previous_size = GetMappingSize(); \
- __leak_test__##test_case_name##__##test_name(); \
- auto current_size = GetMappingSize(); \
- if (current_size > previous_size) { \
- FAIL() << "increase in process map size: " << previous_size << " -> " << current_size; \
- } \
- } \
- static void __leak_test__##test_case_name##__##test_name()
-
-LEAK_TEST(leak, smoke) {
- // Do nothing.
+static void WaitUntilAllExited(pid_t* pids, size_t pid_count) {
+ // Wait until all children have exited.
+ bool alive = true;
+ while (alive) {
+ alive = false;
+ for (size_t i = 0; i < pid_count; ++i) {
+ if (pids[i] != 0) {
+ if (kill(pids[i], 0) == 0) {
+ alive = true;
+ } else {
+ EXPECT_EQ(errno, ESRCH);
+ pids[i] = 0; // Skip in next loop.
+ }
+ }
+ }
+ }
}
-LEAK_TEST(leak, xfail) {
- UNUSED(mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
+class LeakChecker {
+ public:
+ LeakChecker() {
+ Reset();
+ }
+
+ ~LeakChecker() {
+ Check();
+ }
+
+ void Reset() {
+ previous_size_ = GetMappingSize();
+ }
+
+ void DumpTo(std::ostream& os) const {
+ os << previous_size_;
+ }
+
+ private:
+ size_t previous_size_;
+
+ void Check() {
+ auto current_size = GetMappingSize();
+ if (current_size > previous_size_) {
+ FAIL() << "increase in process map size: " << previous_size_ << " -> " << current_size;
+ }
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const LeakChecker& lc) {
+ lc.DumpTo(os);
+ return os;
}
// http://b/36045112
-LEAK_TEST(pthread_leak, join) {
+TEST(pthread_leak, join) {
+ LeakChecker lc;
for (int i = 0; i < 100; ++i) {
pthread_t thread;
ASSERT_EQ(0, pthread_create(&thread, nullptr, [](void*) -> void* { return nullptr; }, nullptr));
}
// http://b/36045112
-LEAK_TEST(pthread_leak, detach) {
- pthread_barrier_t barrier;
- constexpr int thread_count = 100;
- ASSERT_EQ(0, pthread_barrier_init(&barrier, nullptr, thread_count + 1));
- for (int i = 0; i < thread_count; ++i) {
- pthread_t thread;
- const auto thread_function = +[](void* barrier) -> void* {
- pthread_barrier_wait(static_cast<pthread_barrier_t*>(barrier));
- return nullptr;
- };
- ASSERT_EQ(0, pthread_create(&thread, nullptr, thread_function, &barrier));
- ASSERT_EQ(0, pthread_detach(thread));
+TEST(pthread_leak, detach) {
+ LeakChecker lc;
+
+ for (size_t pass = 0; pass < 2; ++pass) {
+ pthread_barrier_t barrier;
+ constexpr int thread_count = 100;
+ ASSERT_EQ(pthread_barrier_init(&barrier, nullptr, thread_count + 1), 0);
+
+ // Start child threads.
+ struct thread_data { pthread_barrier_t* barrier; pid_t* tid; };
+ pid_t tids[thread_count];
+ for (int i = 0; i < thread_count; ++i) {
+ thread_data* td = new thread_data{&barrier, &tids[i]};
+ const auto thread_function = +[](void* ptr) -> void* {
+ thread_data* data = static_cast<thread_data*>(ptr);
+ *data->tid = gettid();
+ pthread_barrier_wait(data->barrier);
+ // Doing this delete allocates new VMAs for jemalloc bookkeeping,
+ // but the two-pass nature of this test means we can check that
+ // it's a pool rather than an unbounded leak.
+ delete data;
+ return nullptr;
+ };
+ pthread_t thread;
+ ASSERT_EQ(0, pthread_create(&thread, nullptr, thread_function, td));
+ ASSERT_EQ(0, pthread_detach(thread));
+ }
+
+ pthread_barrier_wait(&barrier);
+ ASSERT_EQ(pthread_barrier_destroy(&barrier), 0);
+
+ WaitUntilAllExited(tids, arraysize(tids));
+
+ // houdini keeps a thread pool, so we ignore the first pass while the
+ // pool fills, but then on the second pass require that the "pool" isn't
+ // actually an unbounded leak. https://issuetracker.google.com/37920774.
+ if (pass == 0) lc.Reset();
}
-
- pthread_barrier_wait(&barrier);
-
- // Give the threads some time to exit.
- std::this_thread::sleep_for(100ms);
}
cc_test_library {
name: "libtest_ifunc",
defaults: ["bionic_testlib_defaults"],
- srcs: ["dlopen_testlib_ifunc.c"],
+ srcs: ["dlopen_testlib_ifunc.cpp"],
- // TODO(dimitry): clang does not support ifunc attribute
- clang: false,
arch: {
mips: {
enabled: false,
enabled: false,
},
},
+
+ target: {
+ android: {
+ shared_libs: ["libdl"],
+ },
+ host: {
+ host_ldlibs: ["-ldl"],
+ },
+ },
+}
+
+cc_test_library {
+ name: "libtest_ifunc_variable",
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["dlopen_testlib_ifunc_variable.cpp"],
+ shared_libs: [ "libtest_ifunc_variable_impl" ],
+
+ arch: {
+ mips: {
+ enabled: false,
+ },
+ mips64: {
+ enabled: false,
+ },
+ },
+
+ target: {
+ android: {
+ shared_libs: ["libdl"],
+ },
+ host: {
+ host_ldlibs: ["-ldl"],
+ },
+ },
+}
+
+cc_test_library {
+ name: "libtest_ifunc_variable_impl",
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["dlopen_testlib_ifunc_variable_impl.cpp"],
+
+ arch: {
+ mips: {
+ enabled: false,
+ },
+ mips64: {
+ enabled: false,
+ },
+ },
+
+ target: {
+ android: {
+ shared_libs: ["libdl"],
+ },
+ host: {
+ host_ldlibs: ["-ldl"],
+ },
+ },
}
// -----------------------------------------------------------------------------
include $(CLEAR_VARS)
-LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE := libdlext_test_zip_zipaligned
LOCAL_MODULE_SUFFIX := .zip
-LOCAL_MODULE_TAGS := tests
LOCAL_MODULE_PATH := $($(bionic_2nd_arch_prefix)TARGET_OUT_DATA_NATIVE_TESTS)/bionic-loader-test-libs/libdlext_test_zip
LOCAL_2ND_ARCH_VAR_PREFIX := $(bionic_2nd_arch_prefix)
include $(BUILD_SYSTEM)/base_rules.mk
my_shared_libs := \
- $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libdlext_test_zip.so \
- $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libatest_simple_zip.so
+ $(call intermediates-dir-for,SHARED_LIBRARIES,libdlext_test_zip,,,$(bionic_2nd_arch_prefix))/libdlext_test_zip.so \
+ $(call intermediates-dir-for,SHARED_LIBRARIES,libatest_simple_zip,,,$(bionic_2nd_arch_prefix))/libatest_simple_zip.so
-$(LOCAL_BUILT_MODULE) : $(my_shared_libs) | $(BIONIC_TESTS_ZIPALIGN)
+$(LOCAL_BUILT_MODULE): PRIVATE_SHARED_LIBS := $(my_shared_libs)
+$(LOCAL_BUILT_MODULE): $(my_shared_libs) $(BIONIC_TESTS_ZIPALIGN)
@echo "Aligning zip: $@"
$(hide) rm -rf $(dir $@) && mkdir -p $(dir $@)/libdir
- $(hide) cp $^ $(dir $@)/libdir
+ $(hide) cp $(PRIVATE_SHARED_LIBS) $(dir $@)/libdir
$(hide) (cd $(dir $@) && touch empty_file.txt && zip -qrD0 $(notdir $@).unaligned empty_file.txt libdir/*.so)
$(hide) $(BIONIC_TESTS_ZIPALIGN) 4096 $@.unaligned $@
include $(CLEAR_VARS)
-LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE := libdlext_test_runpath_zip_zipaligned
LOCAL_MODULE_SUFFIX := .zip
-LOCAL_MODULE_TAGS := tests
LOCAL_MODULE_PATH := $($(bionic_2nd_arch_prefix)TARGET_OUT_DATA_NATIVE_TESTS)/bionic-loader-test-libs/libdlext_test_runpath_zip
LOCAL_2ND_ARCH_VAR_PREFIX := $(bionic_2nd_arch_prefix)
include $(BUILD_SYSTEM)/base_rules.mk
-my_shared_libs := \
- $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_d_zip.so \
- $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_b.so \
- $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_a.so \
- $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_c.so \
- $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_x.so
-
+lib_d := $(call intermediates-dir-for,SHARED_LIBRARIES,libtest_dt_runpath_d_zip,,,$(bionic_2nd_arch_prefix))/libtest_dt_runpath_d_zip.so
+lib_a := $(call intermediates-dir-for,SHARED_LIBRARIES,libtest_dt_runpath_a,,,$(bionic_2nd_arch_prefix))/libtest_dt_runpath_a.so
+lib_b := $(call intermediates-dir-for,SHARED_LIBRARIES,libtest_dt_runpath_b,,,$(bionic_2nd_arch_prefix))/libtest_dt_runpath_b.so
+lib_c := $(call intermediates-dir-for,SHARED_LIBRARIES,libtest_dt_runpath_c,,,$(bionic_2nd_arch_prefix))/libtest_dt_runpath_c.so
+lib_x := $(call intermediates-dir-for,SHARED_LIBRARIES,libtest_dt_runpath_x,,,$(bionic_2nd_arch_prefix))/libtest_dt_runpath_x.so
-$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_D := \
- $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_d_zip.so
-$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_A := \
- $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_a.so
-$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_B := \
- $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_b.so
-$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_C := \
- $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_c.so
-$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_X := \
- $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libtest_dt_runpath_x.so
-$(LOCAL_BUILT_MODULE) : $(my_shared_libs) | $(BIONIC_TESTS_ZIPALIGN)
+$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_D := $(lib_d)
+$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_A := $(lib_a)
+$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_B := $(lib_b)
+$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_C := $(lib_c)
+$(LOCAL_BUILT_MODULE) : PRIVATE_LIB_X := $(lib_x)
+$(LOCAL_BUILT_MODULE) : $(lib_d) $(lib_a) $(lib_b) $(lib_c) $(lib_x) $(BIONIC_TESTS_ZIPALIGN)
@echo "Aligning zip: $@"
$(hide) rm -rf $(dir $@) && mkdir -p $(dir $@)/libdir && \
mkdir -p $(dir $@)/libdir/dt_runpath_a && mkdir -p $(dir $@)/libdir/dt_runpath_b_c_x
if (return_value != 0) {
CloseArchive(handle);
fprintf(stderr, "Unable to open '%s': %s\n", argv[2], ErrorCodeString(return_value));
- return false;
+ return 1;
}
FILE* zip_dst = fopen(argv[3], "we");
* limitations under the License.
*/
+#include <dlfcn.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
-static int g_flag = 0;
+static uintptr_t g_flag = 0;
static void __attribute__((constructor)) init_flag() {
- g_flag = 1;
+ g_flag = reinterpret_cast<uintptr_t>(dlsym(RTLD_DEFAULT, "dlsym"));
}
static const char* is_ctor_called() __attribute__ ((ifunc("is_ctor_called_ifun")));
-const char* foo() __attribute__ ((ifunc ("foo_ifunc")));
+extern "C" const char* foo() __attribute__ ((ifunc ("foo_ifunc")));
// Static linker creates GLOBAL/IFUNC symbol and JUMP_SLOT relocation type for plt segment
-const char* is_ctor_called_jump_slot() __attribute__ ((ifunc("is_ctor_called_ifun")));
+extern "C" const char* is_ctor_called_jump_slot() __attribute__ ((ifunc("is_ctor_called_ifun")));
-const char* is_ctor_called_irelative() {
+extern "C" const char* is_ctor_called_irelative() {
// Call internal ifunc-resolved function with IRELATIVE reloc
return is_ctor_called();
}
-const char* return_true() {
+extern "C" const char* return_true() {
return "true";
}
-const char* return_false() {
+extern "C" const char* return_false() {
return "false";
}
-const char* f1() {
+extern "C" const char* f1() {
return "unset";
}
-const char* f2() {
+extern "C" const char* f2() {
return "set";
}
-void* is_ctor_called_ifun() {
+typedef const char* (*fn_ptr)();
+
+extern "C" fn_ptr is_ctor_called_ifun() {
return g_flag == 0 ? return_false : return_true;
}
-void* foo_ifunc() {
+extern "C" fn_ptr foo_ifunc() {
char* choice = getenv("IFUNC_CHOICE");
return choice == NULL ? f1 : f2;
}
-const char* foo_library() {
+extern "C" const char* foo_library() {
return foo();
}
--- /dev/null
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+extern "C" const char* foo;
+
+extern "C" const char* foo_library() {
+ return foo;
+}
--- /dev/null
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dlfcn.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static uintptr_t g_flag = 0;
+
+static void __attribute__((constructor)) init_flag() {
+ g_flag = reinterpret_cast<uintptr_t>(dlsym(RTLD_DEFAULT, "dlsym"));
+}
+
+static const char* is_ctor_called() __attribute__ ((ifunc("is_ctor_called_ifun")));
+
+extern "C" const char* foo() __attribute__ ((ifunc ("foo_ifunc")));
+
+// Static linker creates GLOBAL/IFUNC symbol and JUMP_SLOT relocation type for plt segment
+extern "C" const char* is_ctor_called_jump_slot() __attribute__ ((ifunc("is_ctor_called_ifun")));
+
+extern "C" const char* is_ctor_called_irelative() {
+ // Call internal ifunc-resolved function with IRELATIVE reloc
+ return is_ctor_called();
+}
+
+extern "C" const char* var_true = "true";
+extern "C" const char* var_false = "false";
+
+extern "C" const char* v1 = "unset";
+extern "C" const char* v2 = "set";
+
+extern "C" void* is_ctor_called_ifun() {
+ return g_flag == 0 ? &var_false : &var_true;
+}
+
+extern "C" void* foo_ifunc() {
+ char* choice = getenv("IFUNC_CHOICE");
+ return choice == NULL ? &v1 : &v2;
+}
delete[] values_64;
delete[] values_ldouble;
}
+
+TEST(malloc, mallopt_smoke) {
+ errno = 0;
+ ASSERT_EQ(0, mallopt(-1000, 1));
+ // mallopt doesn't set errno.
+ ASSERT_EQ(0, errno);
+}
} else {
ASSERT_EQ(0, result);
}
- arg->data->finished_mask |= (1 << arg->id);
- if (arg->data->finished_mask == ((1 << arg->data->thread_count) - 1)) {
+ int mask = arg->data->finished_mask.fetch_or(1 << arg->id);
+ mask |= 1 << arg->id;
+ if (mask == ((1 << arg->data->thread_count) - 1)) {
ASSERT_EQ(1, arg->data->serial_thread_count);
arg->data->finished_iteration_count++;
arg->data->finished_mask = 0;
cd ${ANDROID_BUILD_TOP}
export ANDROID_DATA=${TARGET_OUT_DATA}
export ANDROID_ROOT=${TARGET_OUT}
- export LD_LIBRARY_PATH=${HOST_OUT}/obj/lib/
${HOST_OUT}/nativetest64/bionic-unit-tests-glibc/bionic-unit-tests-glibc $@
)
exit 0
RunCmpBufferOverreadTest(DoMemcmpTest, DoMemcmpFailTest);
}
+static void DoMemchrTest(uint8_t* buf, size_t len) {
+ if (len >= 1) {
+ int value = len % 128;
+ int search_value = (len % 128) + 1;
+ memset(buf, value, len);
+ // The buffer does not contain the search value.
+ ASSERT_EQ(nullptr, memchr(buf, search_value, len));
+ if (len >= 2) {
+ buf[0] = search_value;
+ // The search value is the first element in the buffer.
+ ASSERT_EQ(&buf[0], memchr(buf, search_value, len));
+
+ buf[0] = value;
+ buf[len - 1] = search_value;
+ // The search value is the last element in the buffer.
+ ASSERT_EQ(&buf[len - 1], memchr(buf, search_value, len));
+ }
+ }
+}
+
+TEST(STRING_TEST, memchr_align) {
+ RunSingleBufferAlignTest(MEDIUM, DoMemchrTest);
+}
+
+TEST(STRING_TEST, memchr_overread) {
+ RunSingleBufferOverreadTest(DoMemchrTest);
+}
+
static void DoStrchrTest(uint8_t* buf, size_t len) {
if (len >= 1) {
char value = 32 + (len % 96);
char search_value = 33 + (len % 96);
memset(buf, value, len - 1);
- buf[len-1] = '\0';
- ASSERT_EQ(NULL, strchr(reinterpret_cast<char*>(buf), search_value));
- ASSERT_EQ(reinterpret_cast<char*>(&buf[len-1]), strchr(reinterpret_cast<char*>(buf), '\0'));
+ buf[len - 1] = '\0';
+ // The buffer does not contain the search value.
+ ASSERT_EQ(nullptr, strchr(reinterpret_cast<char*>(buf), search_value));
+ // Search for the special '\0' character.
+ ASSERT_EQ(reinterpret_cast<char*>(&buf[len - 1]), strchr(reinterpret_cast<char*>(buf), '\0'));
if (len >= 2) {
buf[0] = search_value;
- ASSERT_EQ(reinterpret_cast<char*>(&buf[0]), strchr(reinterpret_cast<char*>(buf), search_value));
+ // The search value is the first element in the buffer.
+ ASSERT_EQ(reinterpret_cast<char*>(&buf[0]), strchr(reinterpret_cast<char*>(buf),
+ search_value));
+
buf[0] = value;
- buf[len-2] = search_value;
- ASSERT_EQ(reinterpret_cast<char*>(&buf[len-2]), strchr(reinterpret_cast<char*>(buf), search_value));
+ buf[len - 2] = search_value;
+ // The search value is the second to last element in the buffer.
+ // The last element is the '\0' character.
+ ASSERT_EQ(reinterpret_cast<char*>(&buf[len - 2]), strchr(reinterpret_cast<char*>(buf),
+ search_value));
}
}
}
RunSingleBufferOverreadTest(DoStrchrTest);
}
+static void DoStrrchrTest(uint8_t* buf, size_t len) {
+ if (len >= 1) {
+ char value = 32 + (len % 96);
+ char search_value = 33 + (len % 96);
+ memset(buf, value, len - 1);
+ buf[len - 1] = '\0';
+ // The buffer does not contain the search value.
+ ASSERT_EQ(nullptr, strrchr(reinterpret_cast<char*>(buf), search_value));
+ // Search for the special '\0' character.
+ ASSERT_EQ(reinterpret_cast<char*>(&buf[len - 1]), strrchr(reinterpret_cast<char*>(buf), '\0'));
+ if (len >= 2) {
+ buf[0] = search_value;
+ // The search value is the first element in the buffer.
+ ASSERT_EQ(reinterpret_cast<char*>(&buf[0]), strrchr(reinterpret_cast<char*>(buf),
+ search_value));
+
+ buf[0] = value;
+ buf[len - 2] = search_value;
+ // The search value is the second to last element in the buffer.
+ // The last element is the '\0' character.
+ ASSERT_EQ(reinterpret_cast<char*>(&buf[len - 2]), strrchr(reinterpret_cast<char*>(buf),
+ search_value));
+ }
+ }
+}
+
+TEST(STRING_TEST, strrchr_align) {
+ RunSingleBufferAlignTest(MEDIUM, DoStrrchrTest);
+}
+
+TEST(STRING_TEST, strrchr_overread) {
+ RunSingleBufferOverreadTest(DoStrrchrTest);
+}
+
static void TestBasename(const char* in, const char* expected_out) {
errno = 0;
const char* out = basename(in);
ASSERT_EQ(0, sigaction(SIGALRM, &action, &oldaction)) << strerror(errno);
alarm(5);
- run_watchpoint_test<Uint128_t>(watchpoint_imprecise_child, 8, 8);
+ run_watchpoint_test<Uint128_t>(watchpoint_imprecise_child, 8, sizeof(void*));
ASSERT_EQ(0, sigaction(SIGALRM, &oldaction, nullptr)) << strerror(errno);
}
ASSERT_EQ(-1, semtimedop(-1, nullptr, 0, nullptr));
ASSERT_TRUE(errno == EINVAL || errno == ENOSYS);
}
+
+TEST(sys_sem, union_semun) {
+ // https://github.com/android-ndk/ndk/issues/400
+#if defined(__BIONIC__)
+ semun arg;
+ semid_ds i1;
+ seminfo i2;
+ unsigned short a[] = { 1u, 2u };
+ arg.val = 123;
+ arg.buf = &i1;
+ arg.array = a;
+ arg.__buf = &i2;
+#else
+ // glibc already mostly removed this cruft (although it's still in <linux/sem.h>).
+#endif
+}
#if defined(__linux__)
+#include <sys/sysmacros.h>
+
struct map_record {
uintptr_t addr_start;
uintptr_t addr_end;
--- /dev/null
+../../libc/versioner-dependencies
\ No newline at end of file
#include <llvm/ADT/IntrusiveRefCntPtr.h>
#include <llvm/ADT/SmallVector.h>
#include <llvm/ADT/StringRef.h>
+#include <llvm/Config/config.h>
#include "Arch.h"
#include "DeclarationDatabase.h"
}
clang::CompilerInstance Compiler;
+
+// Remove the workaround once b/35936936 is fixed.
+#if LLVM_VERSION_MAJOR >= 5
+ Compiler.setInvocation(std::move(invocation));
+#else
Compiler.setInvocation(invocation.release());
+#endif
+
Compiler.setDiagnostics(diags.get());
Compiler.setVirtualFileSystem(vfs);
#include <llvm/ADT/StringRef.h>
+#include <android-base/file.h>
#include <android-base/macros.h>
#include <android-base/parseint.h>
}
}
+// versioner uses a prebuilt version of clang, which is not up-to-date wrt/
+// container annotations. So disable container overflow checking. b/37775238
+extern "C" const char* __asan_default_options() {
+ return "detect_container_overflow=0";
+}
+
int main(int argc, char** argv) {
std::string cwd = getWorkingDir() + "/";
bool default_args = true;
platform_dir = versioner_dir + "/platforms";
}
} else {
- // Intentional leak.
- header_dir = realpath(argv[optind], nullptr);
+ if (!android::base::Realpath(argv[optind], &header_dir)) {
+ err(1, "failed to get realpath for path '%s'", argv[optind]);
+ }
if (argc - optind == 2) {
dependency_dir = argv[optind + 1];