From 57b2a63fc8bda87d8f2417ec8c10c0f1d3e0607d Mon Sep 17 00:00:00 2001 From: Rashed Abdel-Tawab Date: Sun, 15 Apr 2018 10:18:26 -0700 Subject: [PATCH 01/21] libc: Mark libstdc++ as vendor available A lot of blobs still link this even on 8.1, so allow devices to build a vendor copy of it. Change-Id: I2349478ec0507e3a5136fe89f15e7dc4bfc1a03e Signed-off-by: V1t0rrr --- libc/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/libc/Android.bp b/libc/Android.bp index 97146aa6f8..7304aa2a2e 100644 --- a/libc/Android.bp +++ b/libc/Android.bp @@ -1998,6 +1998,7 @@ cc_library { name: "libstdc++", static_ndk_lib: true, static_libs: ["libasync_safe"], + vendor_available: true, static: { system_shared_libs: [], From 3850689ca849e5a7f51535e9fe41b52997799b7a Mon Sep 17 00:00:00 2001 From: "Christopher R. Palmer" Date: Sat, 8 Apr 2017 22:40:01 +0200 Subject: [PATCH 02/21] linker: Add support for dynamic SHIM libraries Author: Christopher R. Palmer Date: Tue Nov 3 16:44:44 2015 -0500 linker: Add support for dynamic "shim" libs Add a new environment variable LD_SHIM_LIBS that is a colon (":") separated list of vertical bar ("|") separated pairs. The pairs are the name for a soinfo reference (executable or shared library) followed by the name of the shim library to load. For example: LD_SHIM_LIBS=rmt_storage|libshim_ioprio.so:/system/lib/libicuuv.so|libshim_icu53.so will instruct the linker to load the dynamic library libshim_ioprio.so whenver rmt_storage is executed [*] and will load libshim_icu53.so whenever any executable or other shared library links against /system/lib/libicuuv.so. There are no restrictions against circular references. In this example, libshim_icu53.so can link against libicuuv.so which provides a simple and convenient means of adding compatibility symbols. [*] Note that the absolute path is not available to the linker and therefore using the name of executables does depend on the invocation and therefore should only be used if absolutely necessary. That is, running /system/bin/rmt_storage would not load any shim libs in this example because it does not match the name of the invocation of the command. If you have trouble determining the sonames being loaded, you can also set the environment variable LD_DEBUG=1 which will cause additional information to be logged to help trace the detection of the shim libs. Change-Id: I0ef80fa466167f7bcb7dac90842bef1c3cf879b6 Author: Christopher R. Palmer Date: Sun Nov 15 14:26:32 2015 -0500 linker: Fix the fact that shim libs do not properly call constructors Change-Id: I34333e13443a154e675b853fa41442351bc4243a Author: Christopher R. Palmer Date: Tue Dec 1 07:10:36 2015 -0500 linker: Don't try to walk the g_active_shim_libs when doing dlsym This is a bug in the original shim_lib implementation which was doing the shim lib resolution both when loading the libraries and when doing the dynamic symbol resolution. Change-Id: Ib2df0498cf551b3bbd37d7c351410b9908eb1795 Author: Christopher R. Palmer Date: Sun Nov 29 08:28:10 2015 -0500 linker: Reset the active shim libs each time we do a dlopen We use the active libs to avoid recursively trying to load the same library: A -> shimlibs add B -> depends on A -> shimlibs add B -> ... However, when we repeatedly dlopen the same library we need to reset the active shim libs to avoid failing to add B the second time we dlopen A. Change-Id: I27580e3d6a53858e8bca025d6c85f981cffbea06 Author: Danny Baumann Date: Fri Dec 11 10:29:16 2015 +0100 Make shim lib load failure non-fatal. Instead, print an appropriate warning message. Aborting symbol resolution on shim lib load failure leads to weird symbol lookup failures, because symbols in libraries referenced after the one loading the shim won't be loaded anymore without a log message stating why that happened. Change-Id: Ic3ad7095ddae7ea1039cb6a18603d5cde8a16143 Author: Christopher R. Palmer Date: Sat Dec 12 06:10:09 2015 -0500 bionic: Do not allow LD_SHIM_LIBS for setuid executables That's really not safe... Change-Id: If79af951830966fc21812cd0f60a8998a752a941 Author: Christopher R. Palmer Date: Sun Feb 14 11:38:44 2016 -0500 bionic: linker: Load shim libs *before* the self-linked libs By loading them earlier, this allows us to override a symbol in a library that is being directly linked. I believe this explains why some people have had problems shimming one lib but when the changet he shim to be against a different lib it magically works. It also makes it possible to override some symbols that were nearly impossible to override before this change. For example, it is pretty much impossible to override a symbol in libutils without this change because it's loaded almost everywhere so no matter where you try to place the shimming, it will be too late and the other symbol will have priority. In particularly, this is necessary to be able to correctly shim the VectorImpl symbols for dlx. Change-Id: I461ca416bc288e28035352da00fde5f34f8d9ffa Author: Chirayu Desai Date: Thu Aug 25 19:02:41 2016 +0530 linker: Update find_library call for shimlibs commits 0cdef7e7f3c6837b56a969120d9098463d1df8d8 "Respect caller DT_RUNPATH in dlopen()." and 42d5fcb9f494eb45de3b6bf759f4a18076e84728 "Introducing linker namespaces" added new arguments to find_library, add them here. Change-Id: I8f35a45b00d14f8b2ce01a0a96d2dc7759be04a6 Author: Chippa-a Date: Sat Aug 27 14:56:30 2016 +0200 linker: Update LD_SHIM_LIBS parser function * Upgrade the code using the same changes as 42d5fcb9f494eb45de3b6bf759f4a18076e84728 bda20e78f0f314dbbf0f0bbcf0740cf2d6a4b85e Change-Id: Ic8be0871945bd9feccd0f94a6770f3cc78a70a0f Author: Danny Baumann Date: Wed Sep 7 16:54:06 2016 +0200 Inject shim libs as if they were DT_NEEDED. The previous separate approach had one flaw: If the shim lib requires another lib that's already loaded, find_library_internal() would return the previously loaded copy, but the later load action would fail as the ELF reader map of the initial loading round was already discarded and thus a new ElfReader instance for the soinfo instance was created, which didn't know about the previous reading/loading state. Change-Id: Ib224dbd35d114197097e3dee14a077cc9130fedb Author: jrior001 Date: Fri Oct 7 19:36:51 2016 -0400 linker: load shims prior to DT_NEEDED check This allows shims to override existing symbols, not just inject new symbols. Change-Id: Ib9216bcc651d8d38999c593babb94d76dc1dbc95 Author: Adrian DC Date: Sat, 8 Apr 2017 22:40:01 +0200 * Adapt to latest AOSP Oreo bionic linker changes * Additional header to avoid unused function Change-Id: Ib9216bcc651d8d38999c593babb94d76dc1dbc95 Author: Paul Keith Date: Thu Feb 15 21:57:33 2018 +0100 linker: Move shims to TARGET_LD_SHIM_LIBS * To reduce security exposure, let's set this at compile time, and block off all the code unless the board flag is set Change-Id: Ieec5f5d9e0f39a798fd48eae037ecffe9502474c Author: Nich Date: Fri Jun 8 09:48:17 2018 +0800 linker: Provide soinfo path of the shimmed binary This is a forward port of part of the original change that was missed out since the initial port of the shim logic to O. Change-Id: I1f7ff98472cfef5cb2d2bcb303082784898cd0c6 Author: Nich Date: Tue Jun 5 13:36:43 2018 +0800 linker: Remove unused find_libraries declaration commit "Inject shim libs as if they were DT_NEEDED." removed references to the forward declaration. Change-Id: I5f1aaa3a96f2af3edef07d4ea4e204b586424631 Author: Nich Date: Sun Jun 10 00:45:51 2018 +0800 linker: Make shim reference path absolute This way, we can filter out non-existent binaries, and ensure we get its absolute path before matching with get_realpath(). This for one allows the use of symlinks in TARGET_LD_SHIM_LIBS. Change-Id: I823815271b3257965534b6b87d8ea36ffb68bc08 Author: Nich Date: Fri Jun 15 03:59:05 2018 +0800 linker: Ensure active matching pairs Change-Id: I54c666b4560dbfb40839b0bf9132a7fd8d3ed2dd Author: Nich Date: Thu Jun 21 01:58:10 2018 +0800 linker: Don't involve shim in for_each_dt_needed for_each_dt_needed may have other usages that shouldn't involve the shim, for example, in the unloading of soinfos. Change-Id: Id38de183d90c3f707767bdca032a5ea2bc82fde8 Author: Jiyong Park Date: Fri Jan 25 18:18:01 2019 +0900 Call realpath(3) only when the path is accessible for read Suppress the SELinux denial log spam by not calling realpath(3) when the path does not exist or is not accessible for read, and then not auditing access(2) failure. Change-Id: I729ecb8ea0bb581069eb849bae7cd28e6ab636cc Change-Id: Ic3ad7095ddae7ea1039cb6a18603d5cde8a16152 Signed-off-by: Wang Han <416810799@qq.com> --- linker/Android.bp | 3 ++ linker/linker.cpp | 71 ++++++++++++++++++++++++++++++++++++++++++ linker/linker.h | 20 ++++++++++++ linker/linker_main.cpp | 11 +++++++ 4 files changed, 105 insertions(+) diff --git a/linker/Android.bp b/linker/Android.bp index d5e7367f4f..63d4daee83 100644 --- a/linker/Android.bp +++ b/linker/Android.bp @@ -70,6 +70,9 @@ cc_object { // Configuration for the linker binary and any of its static libraries. cc_defaults { name: "linker_defaults", + defaults: [ + "shim_libs_defaults", + ], arch: { arm: { cflags: ["-D__work_around_b_24465209__"], diff --git a/linker/linker.cpp b/linker/linker.cpp index c6588d2cd4..5df379936e 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -655,6 +655,68 @@ enum walk_action_result_t : uint32_t { kWalkSkip = 2 }; +#ifdef LD_SHIM_LIBS +// g_ld_all_shim_libs maintains the references to memory as it used +// in the soinfo structures and in the g_active_shim_libs list. + +static std::vector g_ld_all_shim_libs; + +// g_active_shim_libs are all shim libs that are still eligible +// to be loaded. We must remove a shim lib from the list before +// we load the library to avoid recursive loops (load shim libA +// for libB where libA also links against libB). +static linked_list_t g_active_shim_libs; + +static void reset_g_active_shim_libs(void) { + g_active_shim_libs.clear(); + for (const auto& pair : g_ld_all_shim_libs) { + g_active_shim_libs.push_back(&pair); + } +} + +void parse_LD_SHIM_LIBS(const char* path) { + g_ld_all_shim_libs.clear(); + if (path != nullptr) { + for (const auto& pair : android::base::Split(path, ":")) { + std::vector pieces = android::base::Split(pair, "|"); + if (pieces.size() != 2) continue; + // If the path can be resolved, resolve it + char buf[PATH_MAX]; + std::string resolved_path = pieces[0]; + if (access(pieces[0].c_str(), R_OK) != 0) { + if (errno == ENOENT) { + // no need to test for non-existing path. skip. + continue; + } + // If not accessible, don't call realpath as it will just cause + // SELinux denial spam. Use the path unresolved. + } else if (realpath(pieces[0].c_str(), buf) != nullptr) { + resolved_path = buf; + } + auto desc = std::pair(resolved_path, pieces[1]); + g_ld_all_shim_libs.push_back(desc); + } + } + reset_g_active_shim_libs(); +} + +std::vector shim_matching_pairs(const char* path) { + std::vector matched_pairs; + + g_active_shim_libs.for_each([&](const ShimDescriptor* a_pair) { + if (a_pair->first == path) { + matched_pairs.push_back(a_pair); + } + }); + + g_active_shim_libs.remove_if([&](const ShimDescriptor* a_pair) { + return a_pair->first == path; + }); + + return matched_pairs; +} +#endif + // This function walks down the tree of soinfo dependencies // in breadth-first order and // * calls action(soinfo* si) for each node, and @@ -1269,6 +1331,12 @@ static bool load_library(android_namespace_t* ns, } #endif +#ifdef LD_SHIM_LIBS + for_each_matching_shim(realpath.c_str(), [&](const char* name) { + load_tasks->push_back(LoadTask::create(name, si, ns, task->get_readers_map())); + }); +#endif + for_each_dt_needed(task->get_elf_reader(), [&](const char* name) { LD_LOG(kLogDlopen, "load_library(ns=%s, task=%s): Adding DT_NEEDED task: %s", ns->get_name(), task->get_name(), name); @@ -2158,6 +2226,9 @@ void* do_dlopen(const char* name, int flags, } ProtectedDataGuard guard; +#ifdef LD_SHIM_LIBS + reset_g_active_shim_libs(); +#endif soinfo* si = find_library(ns, translated_name, flags, extinfo, caller); loading_trace.End(); diff --git a/linker/linker.h b/linker/linker.h index a80342479c..17126c6dde 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -42,6 +42,10 @@ #include "linker_logger.h" #include "linker_soinfo.h" +#ifdef LD_SHIM_LIBS +#include "linker_debug.h" +#endif + #include #include @@ -81,6 +85,22 @@ soinfo* find_containing_library(const void* p); int open_executable(const char* path, off64_t* file_offset, std::string* realpath); +#ifdef LD_SHIM_LIBS +typedef std::pair ShimDescriptor; +void parse_LD_SHIM_LIBS(const char* path); +std::vector shim_matching_pairs(const char* path); + +template +void for_each_matching_shim(const char* path, F action) { + if (path == nullptr) return; + INFO("Finding shim libs for \"%s\"", path); + for (const auto& one_pair : shim_matching_pairs(path)) { + INFO("Injecting shim lib \"%s\" as needed for %s", one_pair->second.c_str(), path); + action(one_pair->second.c_str()); + } +} +#endif + void do_android_get_LD_LIBRARY_PATH(char*, size_t); void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path); void* do_dlopen(const char* name, diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp index 9e5be345db..73947e161f 100644 --- a/linker/linker_main.cpp +++ b/linker/linker_main.cpp @@ -447,6 +447,11 @@ static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load parse_LD_LIBRARY_PATH(ldpath_env); parse_LD_PRELOAD(ldpreload_env); +#ifdef LD_SHIM_LIBS + // Read from TARGET_LD_SHIM_LIBS + parse_LD_SHIM_LIBS(LD_SHIM_LIBS); +#endif + std::vector namespaces = init_default_namespaces(exe_info.path.c_str()); if (!si->prelink_image()) __linker_cannot_link(g_argv[0]); @@ -472,6 +477,12 @@ static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load ++ld_preloads_count; } +#ifdef LD_SHIM_LIBS + for_each_matching_shim(si->get_realpath(), [&](const char* name) { + needed_library_name_list.push_back(name); + }); +#endif + for_each_dt_needed(si, [&](const char* name) { needed_library_name_list.push_back(name); }); From ee94752f8551d70cb7c4f3d512debfe565e0c38f Mon Sep 17 00:00:00 2001 From: Roopesh Rajashekharaiah Nataraja Date: Tue, 23 Jan 2018 15:31:48 -0800 Subject: [PATCH 03/21] Add inaddr.h header file Signed-off-by: minaripenguin --- libc/include/arpa/inet.h | 1 + libc/include/bits/in_addr.h | 3 +-- libc/include/inaddr.h | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 libc/include/inaddr.h diff --git a/libc/include/arpa/inet.h b/libc/include/arpa/inet.h index db054c9e1d..7716b94457 100644 --- a/libc/include/arpa/inet.h +++ b/libc/include/arpa/inet.h @@ -33,6 +33,7 @@ #include #include #include +#include __BEGIN_DECLS diff --git a/libc/include/bits/in_addr.h b/libc/include/bits/in_addr.h index 30eb04b668..3e46dad2b0 100644 --- a/libc/include/bits/in_addr.h +++ b/libc/include/bits/in_addr.h @@ -36,8 +36,7 @@ #include #include -/** An integral type representing an IPv4 address. */ -typedef uint32_t in_addr_t; +#include /** A structure representing an IPv4 address. */ struct in_addr { diff --git a/libc/include/inaddr.h b/libc/include/inaddr.h new file mode 100644 index 0000000000..524addabf6 --- /dev/null +++ b/libc/include/inaddr.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _INADDR_H_ +#define _INADDR_H_ + +#include + +typedef uint32_t in_addr_t; + +#endif From 23d202af703e5d8f6f79ac13c186c08b3e094af6 Mon Sep 17 00:00:00 2001 From: Benjamin Lerman Date: Tue, 27 Sep 2022 11:35:52 +0200 Subject: [PATCH 04/21] fdsan: fix overflow in FdTableImpl::at Change-Id: Ia687eb52a9c5469225550316f884c229a2218724 --- libc/bionic/fdsan.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libc/bionic/fdsan.cpp b/libc/bionic/fdsan.cpp index 48e8674d6d..66d40d824d 100644 --- a/libc/bionic/fdsan.cpp +++ b/libc/bionic/fdsan.cpp @@ -101,7 +101,7 @@ FdEntry* FdTableImpl::at(size_t idx) { } size_t offset = idx - inline_fds; - if (local_overflow->len < offset) { + if (local_overflow->len <= offset) { return nullptr; } return &local_overflow->entries[offset]; From 0ae0bfd4f019092cae9110130da41fe8fcf8bbe3 Mon Sep 17 00:00:00 2001 From: Suchang Woo Date: Thu, 19 May 2022 10:33:29 +0900 Subject: [PATCH 05/21] Fix it to call the lambda function The lambda function is converted to bool instead of being called. So, get_transparent_hugepages_supported() returns always true. Test: check whether /sys/kernel/mm/transparent_hugepage/enabled is accessed via strace. Bug: http://b/233137490 Signed-off-by: Suchang Woo Change-Id: I88b0d18d8ceb2300482043391eed4ae7041866ca --- linker/linker_transparent_hugepage_support.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linker/linker_transparent_hugepage_support.cpp b/linker/linker_transparent_hugepage_support.cpp index 65ba4cd893..0631577999 100644 --- a/linker/linker_transparent_hugepage_support.cpp +++ b/linker/linker_transparent_hugepage_support.cpp @@ -39,6 +39,6 @@ bool get_transparent_hugepages_supported() { return false; } return enabled.find("[never]") == std::string::npos; - }; + }(); return transparent_hugepages_supported; } From 96eac66d019e9d84f0da461784f63f9f1a72df8d Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Thu, 22 Dec 2022 16:13:09 -0800 Subject: [PATCH 06/21] Plumb scudo_ring_buffer_size to debuggerd_process_info This is a no-op but will be used in upcoming scudo changes that allow to change the buffer size at process startup time, and as such we will no longer be able to call __scudo_get_ring_buffer_size in debuggerd. Bug: 263287052 Change-Id: I18f166fc136ac8314d748eb80a806defcc25c9fd --- libc/bionic/malloc_common_dynamic.cpp | 2 ++ libc/private/bionic_globals.h | 1 + linker/linker_debuggerd_android.cpp | 1 + 3 files changed, 4 insertions(+) diff --git a/libc/bionic/malloc_common_dynamic.cpp b/libc/bionic/malloc_common_dynamic.cpp index 6c2f4d9415..b2ba825dc9 100644 --- a/libc/bionic/malloc_common_dynamic.cpp +++ b/libc/bionic/malloc_common_dynamic.cpp @@ -371,6 +371,7 @@ static bool InstallHooks(libc_globals* globals, const char* options, const char* extern "C" const char* __scudo_get_stack_depot_addr(); extern "C" const char* __scudo_get_region_info_addr(); extern "C" const char* __scudo_get_ring_buffer_addr(); +extern "C" size_t __scudo_get_ring_buffer_size(); // Initializes memory allocation framework once per process. static void MallocInitImpl(libc_globals* globals) { @@ -383,6 +384,7 @@ static void MallocInitImpl(libc_globals* globals) { __libc_shared_globals()->scudo_stack_depot = __scudo_get_stack_depot_addr(); __libc_shared_globals()->scudo_region_info = __scudo_get_region_info_addr(); __libc_shared_globals()->scudo_ring_buffer = __scudo_get_ring_buffer_addr(); + __libc_shared_globals()->scudo_ring_buffer_size = __scudo_get_ring_buffer_size(); #endif // Prefer malloc debug since it existed first and is a more complete diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h index e105c18d93..aca8626119 100644 --- a/libc/private/bionic_globals.h +++ b/libc/private/bionic_globals.h @@ -110,6 +110,7 @@ struct libc_shared_globals { const char* scudo_stack_depot = nullptr; const char* scudo_region_info = nullptr; const char* scudo_ring_buffer = nullptr; + size_t scudo_ring_buffer_size = 0; HeapTaggingLevel initial_heap_tagging_level = M_HEAP_TAGGING_LEVEL_NONE; }; diff --git a/linker/linker_debuggerd_android.cpp b/linker/linker_debuggerd_android.cpp index cba6345c1b..3d64628581 100644 --- a/linker/linker_debuggerd_android.cpp +++ b/linker/linker_debuggerd_android.cpp @@ -43,6 +43,7 @@ static debugger_process_info get_process_info() { .scudo_stack_depot = __libc_shared_globals()->scudo_stack_depot, .scudo_region_info = __libc_shared_globals()->scudo_region_info, .scudo_ring_buffer = __libc_shared_globals()->scudo_ring_buffer, + .scudo_ring_buffer_size = __libc_shared_globals()->scudo_ring_buffer_size, }; } #endif From b4de3e646ddc0bfd016e2dfd887186f6df99c8cb Mon Sep 17 00:00:00 2001 From: Danny Lin Date: Sat, 20 Mar 2021 22:02:38 -0700 Subject: [PATCH 07/21] Switch to jemalloc memory allocator Overall, jemalloc performs significantly better than Scudo in Bionic's real-world memory_replay traces (all times in milliseconds): +----------------+-------+----------+ | Trace | Scudo | jemalloc | +----------------+-------+----------+ | SQL | 27 | 21 | | Angry Birds 2 | 2236 | 1501 | | Camera | 4251 | 979 | | Candy Crush | 2197 | 1325 | | Gmail | 594 | 463 | | Maps | 434 | 344 | | Photos | 1330 | 477 | | PUBG | 666 | 416 | | surfaceflinger | 221 | 192 | | system_server | 1921 | 1416 | | SystemUI | 102 | 79 | | YouTube | 363 | 294 | +----------------+-------+----------+ jemalloc also tends to use slightly less memory than Scudo for most traces. These tests were conducted on desktop x86 Linux with glibc and the latest stable version of each allocator, but they should still be relevant. RSS values in KiB: +----------------+--------+----------+ | Trace | Scudo | jemalloc | +----------------+--------+----------+ | Angry Birds 2 | 793948 | 746992 | | Camera | 219372 | 251888 | | Candy Crush | 548288 | 550148 | | Gmail | 195236 | 193048 | | Maps | 159860 | 159816 | | Photos | 175436 | 171872 | | PUBG | 233752 | 223572 | | surfaceflinger | 94736 | 107068 | | system_server | 471048 | 484392 | | SystemUI | 54432 | 60740 | | YouTube | 139376 | 142252 | +----------------+--------+----------+ While not representative of real-world usage, jemalloc also performs fairly well in synthetic benchmarks (all times in nanoseconds): +-----------------+---------+----------+ | Benchmark | Scudo | jemalloc | +-----------------+---------+----------+ | alloc 8 | 87.9 | 60.1 | | alloc 16 | 87.9 | 60 | | alloc 32 | 88.6 | 60.7 | | alloc 64 | 88.6 | 59.7 | | alloc 512 | 89.2 | 60 | | alloc 1024 | 89.4 | 59.8 | | alloc 8192 | 89.8 | 65.2 | | alloc 16384 | 92.7 | 69.1 | | alloc 32768 | 97.2 | 74 | | alloc 65536 | 109 | 83.8 | | alloc 131072 | 41536 | 42720 | | alloc40x 8 | 2156 | 2556 | | alloc40x 16 | 2155 | 2244 | | alloc40x 32 | 2234 | 2312 | | alloc40x 64 | 2234 | 2289 | | alloc40x 512 | 2274 | 8171 | | alloc40x 1024 | 2397 | 2162 | | alloc40x 8192 | 3550 | 78880 | | alloc40x 16384 | 3732 | 124454 | | alloc40x 32768 | 3849 | 275460 | | alloc40x 65536 | 4987 | 727598 | | alloc40x 131072 | 2745207 | 3067980 | | alloc8192 1x | 464 | 454 | | alloc8192 2x | 510 | 488 | | alloc8192 3x | 587 | 523 | | alloc8192 4x | 665 | 557 | | alloc8192 5x | 742 | 598 | | alloc8192 6x | 818 | 633 | | alloc8192 7x | 884 | 669 | | alloc8192 8x | 960 | 699 | | alloc8192 9x | 1045 | 734 | | alloc8192 10x | 1131 | 770 | | alloc8192 11x | 1207 | 806 | | alloc8192 12x | 1282 | 841 | | alloc8192 13x | 1363 | 877 | | alloc8192 14x | 1442 | 912 | | alloc8192 15x | 1512 | 944 | | alloc8192 16x | 1587 | 978 | | alloc8192 24x | 2256 | 21195 | | alloc8192 32x | 2867 | 45446 | | alloc8192 40x | 3522 | 71618 | | alloc8192 48x | 4126 | 89740 | | alloc8192 56x | 4786 | 114990 | | alloc8192 64x | 5412 | 141082 | | alloc8192 72x | 6049 | 170742 | | alloc8192 80x | 6712 | 198480 | | alloc8192 88x | 7331 | 221557 | | alloc8192 96x | 7976 | 251462 | | alloc8192 104x | 8581 | 281626 | | alloc8192 112x | 9245 | 313164 | | alloc8192 120x | 9914 | 353147 | | alloc8192 128x | 10514 | 376625 | | alloc8192 136x | 11187 | 408194 | | alloc8192 144x | 11802 | 445694 | | alloc8192 160x | 13083 | 514547 | | alloc8192 176x | 14414 | 582501 | | alloc8192 192x | 15746 | 654346 | | alloc8192 208x | 17044 | 712620 | | alloc8192 224x | 18405 | 769963 | | alloc8192 240x | 19744 | 843969 | | alloc8192 256x | 21160 | 917803 | +-----------------+---------+----------+ Scudo performs fairly well for a hardened memory allocator, but we're optimizing for performance. Full benchmark data with graphs: https://docs.google.com/spreadsheets/d/1LG_kxaK5cI14gGtnyM-nNNmfpMdV9Vh-LtYoq7H5J4s/edit Change-Id: Ia4901eedfaa2c9779678c5b6532979de4919ee01 Signed-off-by: Pranav Vashi Signed-off-by: Anush02198 --- libc/Android.bp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libc/Android.bp b/libc/Android.bp index 7304aa2a2e..b6551f5513 100644 --- a/libc/Android.bp +++ b/libc/Android.bp @@ -126,9 +126,6 @@ cc_defaults { malloc_pattern_fill_contents: { cflags: ["-DSCUDO_PATTERN_FILL_CONTENTS"], }, - malloc_not_svelte: { - cflags: ["-DUSE_SCUDO"], - }, }, lto: { @@ -161,7 +158,6 @@ cc_defaults { "libc_jemalloc_wrapper", ], header_libs: ["gwp_asan_headers"], - product_variables: libc_scudo_product_variables, } // Functions not implemented by jemalloc directly, or that need to From a682ecb40bca0b46422b4e55062fc3ce3e198ca9 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Thu, 2 Jun 2022 15:20:23 -0700 Subject: [PATCH 08/21] Verify that allocated memory is always zeroed. Test: New unit tests pass on scudo. Test: New unit tests fail on original jemalloc. Test: New unit tests pass on modified jemalloc. Change-Id: Id62ab74f649c0f7c14a951235fe79972926ecec0 Signed-off-by: minaripenguin37 Signed-off-by: Anush02198 --- libc/Android.bp | 19 +++--- tests/malloc_test.cpp | 131 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 8 deletions(-) diff --git a/libc/Android.bp b/libc/Android.bp index b6551f5513..0313993a2c 100644 --- a/libc/Android.bp +++ b/libc/Android.bp @@ -126,6 +126,9 @@ cc_defaults { malloc_pattern_fill_contents: { cflags: ["-DSCUDO_PATTERN_FILL_CONTENTS"], }, + //malloc_not_svelte: { + //cflags: ["-DUSE_SCUDO"], + //}, }, lto: { @@ -134,14 +137,14 @@ cc_defaults { } libc_scudo_product_variables = { - malloc_not_svelte: { - cflags: ["-DUSE_SCUDO"], - whole_static_libs: ["libscudo"], - exclude_static_libs: [ - "libjemalloc5", - "libc_jemalloc_wrapper", - ], - }, + //malloc_not_svelte: { + //cflags: ["-DUSE_SCUDO"], + //whole_static_libs: ["libscudo"], + //exclude_static_libs: [ + //"libjemalloc5", + //"libc_jemalloc_wrapper", + //], + //}, } // Defaults for native allocator libs/includes to make it diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp index 69f8506fdf..7f0e9a6c24 100644 --- a/tests/malloc_test.cpp +++ b/tests/malloc_test.cpp @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -1519,3 +1520,133 @@ TEST(malloc, realloc_mte_crash_b206701345) { } } } + +void VerifyAllocationsAreZero(std::function alloc_func, std::string function_name, + std::vector& test_sizes, size_t max_allocations) { + // Vector of zero'd data used for comparisons. Make it twice the larges size. + std::vector zero(test_sizes.back() * 2, 0); + + SCOPED_TRACE(testing::Message() << function_name << " failed to zero memory"); + + for (size_t test_size : test_sizes) { + std::vector ptrs(max_allocations); + for (size_t i = 0; i < ptrs.size(); i++) { + SCOPED_TRACE(testing::Message() << "size " << test_size << " at iteration " << i); + ptrs[i] = alloc_func(test_size); + ASSERT_TRUE(ptrs[i] != nullptr); + size_t alloc_size = malloc_usable_size(ptrs[i]); + ASSERT_LE(alloc_size, zero.size()); + ASSERT_EQ(0, memcmp(ptrs[i], zero.data(), alloc_size)); + + // Set the memory to non-zero to make sure if the pointer + // is reused it's still zero. + memset(ptrs[i], 0xab, alloc_size); + } + // Free the pointers. + for (size_t i = 0; i < ptrs.size(); i++) { + free(ptrs[i]); + } + for (size_t i = 0; i < ptrs.size(); i++) { + SCOPED_TRACE(testing::Message() << "size " << test_size << " at iteration " << i); + ptrs[i] = malloc(test_size); + ASSERT_TRUE(ptrs[i] != nullptr); + size_t alloc_size = malloc_usable_size(ptrs[i]); + ASSERT_LE(alloc_size, zero.size()); + ASSERT_EQ(0, memcmp(ptrs[i], zero.data(), alloc_size)); + } + // Free all of the pointers later to maximize the chance of reusing from + // the first loop. + for (size_t i = 0; i < ptrs.size(); i++) { + free(ptrs[i]); + } + } +} + +// Verify that small and medium allocations are always zero. +TEST(malloc, zeroed_allocations_small_medium_sizes) { + constexpr size_t kMaxAllocations = 1024; + std::vector test_sizes = {16, 48, 128, 1024, 4096, 65536}; + VerifyAllocationsAreZero([](size_t size) -> void* { return malloc(size); }, "malloc", test_sizes, + kMaxAllocations); + + VerifyAllocationsAreZero([](size_t size) -> void* { return memalign(64, size); }, "memalign", + test_sizes, kMaxAllocations); + + VerifyAllocationsAreZero( + [](size_t size) -> void* { + void* ptr; + if (posix_memalign(&ptr, 64, size) == 0) { + return ptr; + } + return nullptr; + }, + "posix_memalign", test_sizes, kMaxAllocations); +} + +// Verify that large allocations are always zero. +TEST(malloc, zeroed_allocations_large_sizes) { + constexpr size_t kMaxAllocations = 20; + std::vector test_sizes = {1000000, 2000000, 3000000, 4000000}; + VerifyAllocationsAreZero([](size_t size) -> void* { return malloc(size); }, "malloc", test_sizes, + kMaxAllocations); + + VerifyAllocationsAreZero([](size_t size) -> void* { return memalign(64, size); }, "memalign", + test_sizes, kMaxAllocations); + + VerifyAllocationsAreZero( + [](size_t size) -> void* { + void* ptr; + if (posix_memalign(&ptr, 64, size) == 0) { + return ptr; + } + return nullptr; + }, + "posix_memalign", test_sizes, kMaxAllocations); +} + +TEST(malloc, zeroed_allocations_realloc) { + // Vector of zero'd data used for comparisons. + constexpr size_t kMaxMemorySize = 131072; + std::vector zero(kMaxMemorySize, 0); + + constexpr size_t kMaxAllocations = 1024; + std::vector test_sizes = {16, 48, 128, 1024, 4096, 65536}; + // Do a number of allocations and set them to non-zero. + for (size_t test_size : test_sizes) { + std::vector ptrs(kMaxAllocations); + for (size_t i = 0; i < kMaxAllocations; i++) { + ptrs[i] = malloc(test_size); + ASSERT_TRUE(ptrs[i] != nullptr); + + // Set the memory to non-zero to make sure if the pointer + // is reused it's still zero. + memset(ptrs[i], 0xab, malloc_usable_size(ptrs[i])); + } + // Free the pointers. + for (size_t i = 0; i < kMaxAllocations; i++) { + free(ptrs[i]); + } + } + + // Do the reallocs to a larger size and verify the rest of the allocation + // is zero. + constexpr size_t kInitialSize = 8; + for (size_t test_size : test_sizes) { + std::vector ptrs(kMaxAllocations); + for (size_t i = 0; i < kMaxAllocations; i++) { + ptrs[i] = malloc(kInitialSize); + ASSERT_TRUE(ptrs[i] != nullptr); + size_t orig_alloc_size = malloc_usable_size(ptrs[i]); + + ptrs[i] = realloc(ptrs[i], test_size); + ASSERT_TRUE(ptrs[i] != nullptr); + size_t new_alloc_size = malloc_usable_size(ptrs[i]); + char* ptr = reinterpret_cast(ptrs[i]); + ASSERT_EQ(0, memcmp(&ptr[orig_alloc_size], zero.data(), new_alloc_size - orig_alloc_size)) + << "realloc from " << kInitialSize << " to size " << test_size << " at iteration " << i; + } + for (size_t i = 0; i < kMaxAllocations; i++) { + free(ptrs[i]); + } + } +} From 0bdbeab5932eb3b376f22fa47999a23763589845 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Wed, 18 Jan 2023 15:08:37 -0800 Subject: [PATCH 09/21] Only run mallopt_smoke test on bionic. Even though glibc has mallopt, there is no way to guarantee that we use an invalid argument. Since this test is only really useful for bionic, only run it on bionic. Test: Ran glibc and verified the test is skipped. Change-Id: If991e8804b21c83f3d7e3b15a0b60e48da331567 --- tests/malloc_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp index 7f0e9a6c24..4546e24c80 100644 --- a/tests/malloc_test.cpp +++ b/tests/malloc_test.cpp @@ -662,13 +662,13 @@ TEST(malloc, verify_alignment) { } TEST(malloc, mallopt_smoke) { -#if !defined(ANDROID_HOST_MUSL) +#if defined(__BIONIC__) errno = 0; ASSERT_EQ(0, mallopt(-1000, 1)); // mallopt doesn't set errno. ASSERT_EQ(0, errno); #else - GTEST_SKIP() << "musl doesn't have mallopt"; + GTEST_SKIP() << "bionic-only test"; #endif } From 58172d45ebcfb20823c8a1ed1e97d94cf234f9a5 Mon Sep 17 00:00:00 2001 From: Chia-hung Duan Date: Tue, 9 Aug 2022 01:55:44 +0000 Subject: [PATCH 10/21] Add a malloc rss benchmark The behavior of this benchmark includes three steps: 1. Use up to 16 MB by allocating blocks with given size in each thread. 2. Release the all blocks in random order. 3. Use up to 1.6 MB by allocating blocks with given size in each thread. This is used to see how the allocator manages the free blocks and we can measure the impact of randomization property used by the allocator. Test: Run malloc-rss-benchmark $NUM_THREADS $ALLOC_SIZE Change-Id: Ib68562996905839ee4367b1b059714e2325ca03e --- benchmarks/Android.bp | 20 ++++ benchmarks/NOTICE | 28 +++++ benchmarks/malloc_rss_benchmark.cpp | 165 ++++++++++++++++++++++++++++ 3 files changed, 213 insertions(+) create mode 100644 benchmarks/malloc_rss_benchmark.cpp diff --git a/benchmarks/Android.bp b/benchmarks/Android.bp index 5dfc38f5cd..17d2d68f94 100644 --- a/benchmarks/Android.bp +++ b/benchmarks/Android.bp @@ -156,3 +156,23 @@ cc_test { ], data: ["test_suites/*"], } + +cc_binary { + name: "malloc-rss-benchmark", + srcs: [ + "malloc_rss_benchmark.cpp", + ], + + shared_libs: [ + "libbase", + ], + + target: { + android: { + static_libs: [ + "libmeminfo", + "libprocinfo", + ], + }, + }, +} diff --git a/benchmarks/NOTICE b/benchmarks/NOTICE index f720e2331d..e46a6242f3 100644 --- a/benchmarks/NOTICE +++ b/benchmarks/NOTICE @@ -178,3 +178,31 @@ SUCH DAMAGE. ------------------------------------------------------------------- +Copyright (C) 2022 The Android Open Source Project +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +------------------------------------------------------------------- + diff --git a/benchmarks/malloc_rss_benchmark.cpp b/benchmarks/malloc_rss_benchmark.cpp new file mode 100644 index 0000000000..58f61d971a --- /dev/null +++ b/benchmarks/malloc_rss_benchmark.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#if defined(__BIONIC__) +#include +#include +#include +#endif + +constexpr size_t kMaxThreads = 8; +// The max number of bytes that can be allocated by a thread. Note that each +// allocator may have its own limitation on each size allocation. For example, +// Scudo has a 256 MB limit for each size-class in the primary allocator. The +// amount of memory allocated should not exceed the limit in each allocator. +constexpr size_t kMaxBytes = 1 << 24; +constexpr size_t kMaxLen = kMaxBytes; +void* MemPool[kMaxThreads][kMaxLen]; + +void dirtyMem(void* ptr, size_t bytes) { + memset(ptr, 1U, bytes); +} + +void ThreadTask(int id, size_t allocSize) { + // In the following, we will first allocate blocks with kMaxBytes of memory + // and release all of them in random order. In the end, we will do another + // round of allocations until it reaches 1/10 kMaxBytes. + + // Total number of blocks + const size_t maxCounts = kMaxBytes / allocSize; + // The number of blocks in the end + const size_t finalCounts = maxCounts / 10; + + for (size_t i = 0; i < maxCounts; ++i) { + MemPool[id][i] = malloc(allocSize); + if (MemPool[id][i] == 0) { + std::cout << "Allocation failure." + "Please consider reducing the number of threads" + << std::endl; + exit(1); + } + dirtyMem(MemPool[id][i], allocSize); + } + + // Each allocator may apply different strategies to manage the free blocks and + // each strategy may have different impacts on future memory usage. For + // example, managing free blocks in simple FIFO list may have its memory usage + // highly correlated with the blocks releasing pattern. Therefore, release the + // blocks in random order to observe the impact of free blocks handling. + unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); + std::shuffle(MemPool[id], MemPool[id] + maxCounts, std::default_random_engine(seed)); + for (size_t i = 0; i < maxCounts; ++i) { + free(MemPool[id][i]); + MemPool[id][i] = nullptr; + } + + for (size_t i = 0; i < finalCounts; ++i) { + MemPool[id][i] = malloc(allocSize); + dirtyMem(MemPool[id][i], allocSize); + } +} + +void StressSizeClass(size_t numThreads, size_t allocSize) { + // We would like to see the minimum memory usage under aggressive page + // releasing. + mallopt(M_DECAY_TIME, 0); + + std::thread* threads[kMaxThreads]; + for (size_t i = 0; i < numThreads; ++i) threads[i] = new std::thread(ThreadTask, i, allocSize); + + for (size_t i = 0; i < numThreads; ++i) { + threads[i]->join(); + delete threads[i]; + } + + // Do an explicit purge to ensure we will be more likely to get the actual + // in-use memory. + mallopt(M_PURGE, 0); + + android::meminfo::ProcMemInfo proc_mem(getpid()); + const std::vector& maps = proc_mem.MapsWithoutUsageStats(); + uint64_t rss_bytes = 0; + uint64_t vss_bytes = 0; + + for (auto& vma : maps) { + if (vma.name == "[anon:libc_malloc]" || android::base::StartsWith(vma.name, "[anon:scudo:") || + android::base::StartsWith(vma.name, "[anon:GWP-ASan")) { + android::meminfo::Vma update_vma(vma); + if (!proc_mem.FillInVmaStats(update_vma)) { + std::cout << "Failed to parse VMA" << std::endl; + exit(1); + } + rss_bytes += update_vma.usage.rss; + vss_bytes += update_vma.usage.vss; + } + } + + std::cout << "RSS: " << rss_bytes / (1024.0 * 1024.0) << " MB" << std::endl; + std::cout << "VSS: " << vss_bytes / (1024.0 * 1024.0) << " MB" << std::endl; + + for (size_t i = 0; i < numThreads; ++i) { + for (size_t j = 0; j < kMaxLen; ++j) free(MemPool[i][j]); + } +} + +int main(int argc, char* argv[]) { + if (argc != 3) { + std::cerr << "usage: " << argv[0] << " $NUM_THREADS $ALLOC_SIZE" << std::endl; + return 1; + } + + size_t numThreads = atoi(argv[1]); + size_t allocSize = atoi(argv[2]); + + if (numThreads == 0 || allocSize == 0) { + std::cerr << "Please provide valid $NUM_THREADS and $ALLOC_SIZE" << std::endl; + return 1; + } + + if (numThreads > kMaxThreads) { + std::cerr << "The max number of threads is " << kMaxThreads << std::endl; + return 1; + } + + StressSizeClass(numThreads, allocSize); + + return 0; +} From 5d3fe36e99f7bf0090cb430f151246f7bbeefc8c Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Tue, 28 Feb 2023 12:45:54 -0800 Subject: [PATCH 11/21] Add support for M_PURGE_ALL. This is a new mallopt option that will force purge absolutely everything no matter how long it takes to purge. Wrote a unit test for the new mallopt, and added a test to help verify that new mallopt parameters do not conflict with each other. Modified some benchmarks to use this new parameter so that we can get better RSS data. Bug: 243851006 Test: All unit tests pass. Test: Ran changed benchmarks. Change-Id: I1b46a5e6253538108e052d11ee46fd513568adec --- benchmarks/malloc_benchmark.cpp | 4 +-- benchmarks/malloc_map_benchmark.cpp | 4 +-- benchmarks/malloc_rss_benchmark.cpp | 2 +- libc/bionic/jemalloc_wrapper.cpp | 2 +- libc/include/malloc.h | 10 ++++++- tests/malloc_test.cpp | 41 +++++++++++++++++++++++++++++ 6 files changed, 56 insertions(+), 7 deletions(-) diff --git a/benchmarks/malloc_benchmark.cpp b/benchmarks/malloc_benchmark.cpp index 18ba52386a..1c7329c695 100644 --- a/benchmarks/malloc_benchmark.cpp +++ b/benchmarks/malloc_benchmark.cpp @@ -40,7 +40,7 @@ static void BM_mallopt_purge(benchmark::State& state) { static size_t sizes[] = {8, 16, 32, 64, 128, 1024, 4096, 16384, 65536, 131072, 1048576}; static int pagesize = getpagesize(); mallopt(M_DECAY_TIME, 1); - mallopt(M_PURGE, 0); + mallopt(M_PURGE_ALL, 0); for (auto _ : state) { state.PauseTiming(); std::vector ptrs; @@ -63,7 +63,7 @@ static void BM_mallopt_purge(benchmark::State& state) { ptrs.clear(); state.ResumeTiming(); - mallopt(M_PURGE, 0); + mallopt(M_PURGE_ALL, 0); } mallopt(M_DECAY_TIME, 0); } diff --git a/benchmarks/malloc_map_benchmark.cpp b/benchmarks/malloc_map_benchmark.cpp index ba4d62c0bf..5757325392 100644 --- a/benchmarks/malloc_map_benchmark.cpp +++ b/benchmarks/malloc_map_benchmark.cpp @@ -69,7 +69,7 @@ static void MapBenchmark(benchmark::State& state, size_t num_elements) { for (auto _ : state) { #if defined(__BIONIC__) state.PauseTiming(); - mallopt(M_PURGE, 0); + mallopt(M_PURGE_ALL, 0); uint64_t rss_bytes_before = 0; Gather(&rss_bytes_before); state.ResumeTiming(); @@ -80,7 +80,7 @@ static void MapBenchmark(benchmark::State& state, size_t num_elements) { } #if defined(__BIONIC__) state.PauseTiming(); - mallopt(M_PURGE, 0); + mallopt(M_PURGE_ALL, 0); Gather(&rss_bytes); // Try and record only the memory used in the map. rss_bytes -= rss_bytes_before; diff --git a/benchmarks/malloc_rss_benchmark.cpp b/benchmarks/malloc_rss_benchmark.cpp index 58f61d971a..4b34e72f7c 100644 --- a/benchmarks/malloc_rss_benchmark.cpp +++ b/benchmarks/malloc_rss_benchmark.cpp @@ -112,7 +112,7 @@ void StressSizeClass(size_t numThreads, size_t allocSize) { // Do an explicit purge to ensure we will be more likely to get the actual // in-use memory. - mallopt(M_PURGE, 0); + mallopt(M_PURGE_ALL, 0); android::meminfo::ProcMemInfo proc_mem(getpid()); const std::vector& maps = proc_mem.MapsWithoutUsageStats(); diff --git a/libc/bionic/jemalloc_wrapper.cpp b/libc/bionic/jemalloc_wrapper.cpp index ef488eecc9..ce3f314203 100644 --- a/libc/bionic/jemalloc_wrapper.cpp +++ b/libc/bionic/jemalloc_wrapper.cpp @@ -102,7 +102,7 @@ int je_mallopt(int param, int value) { } } return 1; - } else if (param == M_PURGE) { + } else if (param == M_PURGE || param == M_PURGE_ALL) { // Only clear the current thread cache since there is no easy way to // clear the caches of other threads. // This must be done first so that cleared allocations get purged diff --git a/libc/include/malloc.h b/libc/include/malloc.h index 40786fad69..c3f261398c 100644 --- a/libc/include/malloc.h +++ b/libc/include/malloc.h @@ -183,7 +183,15 @@ int malloc_info(int __must_be_zero, FILE* __fp) __INTRODUCED_IN(23); * Available since API level 28. */ #define M_PURGE (-101) - +/** + * mallopt() option to immediately purge all possible memory back to + * the kernel. This call can take longer than a normal purge since it + * examines everything. In some cases, it can take more than twice the + * time of a M_PURGE call. The value is ignored. + * + * Available since API level 34. + */ +#define M_PURGE_ALL (-300) /** * mallopt() option to tune the allocator's choice of memory tags to diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp index 4546e24c80..1e58d826db 100644 --- a/tests/malloc_test.cpp +++ b/tests/malloc_test.cpp @@ -36,7 +36,10 @@ #include #include #include +#include #include +#include +#include #include #include @@ -695,6 +698,44 @@ TEST(malloc, mallopt_purge) { #endif } +TEST(malloc, mallopt_purge_all) { +#if defined(__BIONIC__) + SKIP_WITH_HWASAN << "hwasan does not implement mallopt"; + errno = 0; + ASSERT_EQ(1, mallopt(M_PURGE_ALL, 0)); +#else + GTEST_SKIP() << "bionic-only test"; +#endif +} + +// Verify that all of the mallopt values are unique. +TEST(malloc, mallopt_unique_params) { +#if defined(__BIONIC__) + std::vector> params{ + std::make_pair(M_DECAY_TIME, "M_DECAY_TIME"), + std::make_pair(M_PURGE, "M_PURGE"), + std::make_pair(M_PURGE_ALL, "M_PURGE_ALL"), + std::make_pair(M_MEMTAG_TUNING, "M_MEMTAG_TUNING"), + std::make_pair(M_THREAD_DISABLE_MEM_INIT, "M_THREAD_DISABLE_MEM_INIT"), + std::make_pair(M_CACHE_COUNT_MAX, "M_CACHE_COUNT_MAX"), + std::make_pair(M_CACHE_SIZE_MAX, "M_CACHE_SIZE_MAX"), + std::make_pair(M_TSDS_COUNT_MAX, "M_TSDS_COUNT_MAX"), + std::make_pair(M_BIONIC_ZERO_INIT, "M_BIONIC_ZERO_INIT"), + std::make_pair(M_BIONIC_SET_HEAP_TAGGING_LEVEL, "M_BIONIC_SET_HEAP_TAGGING_LEVEL"), + }; + + std::unordered_map all_params; + for (const auto& param : params) { + EXPECT_TRUE(all_params.count(param.first) == 0) + << "mallopt params " << all_params[param.first] << " and " << param.second + << " have the same value " << param.first; + all_params.insert(param); + } +#else + GTEST_SKIP() << "bionic-only test"; +#endif +} + #if defined(__BIONIC__) static void GetAllocatorVersion(bool* allocator_scudo) { TemporaryFile tf; From 6ed2d42339ff2e5627d967a4030b10f679deef8a Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Wed, 15 Mar 2023 15:20:57 -0700 Subject: [PATCH 12/21] Fix stack use-after-scope in async_safe_log. The buffer filled in by strerror_r needs to stay in scope while it is pointed to by str. Bug: 273807460 Change-Id: I494ca8b8aca2b28ec2f0f3da72d845db99633553 --- libc/async_safe/async_safe_log.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libc/async_safe/async_safe_log.cpp b/libc/async_safe/async_safe_log.cpp index 2380e686d9..d31fe0303d 100644 --- a/libc/async_safe/async_safe_log.cpp +++ b/libc/async_safe/async_safe_log.cpp @@ -345,6 +345,7 @@ static void out_vformat(Out& o, const char* format, va_list args) { /* conversion specifier */ const char* str = buffer; + char strerror_buf[256]; if (c == 's') { /* string */ str = va_arg(args, const char*); @@ -359,8 +360,7 @@ static void out_vformat(Out& o, const char* format, va_list args) { buffer[1] = 'x'; format_integer(buffer + 2, sizeof(buffer) - 2, value, 'x'); } else if (c == 'm') { - char buf[256]; - str = strerror_r(errno, buf, sizeof(buf)); + str = strerror_r(errno, strerror_buf, sizeof(strerror_buf)); } else if (c == 'd' || c == 'i' || c == 'o' || c == 'u' || c == 'x' || c == 'X') { /* integers - first read value from stack */ uint64_t value; From b3584543d88518b94bdd113465bf733297ce2905 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Mon, 20 Mar 2023 16:31:18 -0700 Subject: [PATCH 13/21] Fix mte build breakage. The strerror_buf is way too large, so instead of using a separate buffer for just this string, reuse the already existing buffer. Increase the buffer size to cover the maximum errno string. Add a unit test to verify that none of the errno values are cut off in the async_safe_format_buffer function when passing %m. Bug: 274474681 Test: New unit test passes. Test: Changing the buffer to a small value and verify that the test fails. Change-Id: I4cb4652709582a8a6b958e12de5d923ec950e6b6 --- libc/async_safe/async_safe_log.cpp | 5 ++--- tests/async_safe_test.cpp | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/libc/async_safe/async_safe_log.cpp b/libc/async_safe/async_safe_log.cpp index d31fe0303d..420560f7b0 100644 --- a/libc/async_safe/async_safe_log.cpp +++ b/libc/async_safe/async_safe_log.cpp @@ -254,7 +254,7 @@ static void out_vformat(Out& o, const char* format, va_list args) { bool alternate = false; size_t bytelen = sizeof(int); int slen; - char buffer[32]; /* temporary buffer used to format numbers */ + char buffer[64]; // temporary buffer used to format numbers/format errno string char c; @@ -345,7 +345,6 @@ static void out_vformat(Out& o, const char* format, va_list args) { /* conversion specifier */ const char* str = buffer; - char strerror_buf[256]; if (c == 's') { /* string */ str = va_arg(args, const char*); @@ -360,7 +359,7 @@ static void out_vformat(Out& o, const char* format, va_list args) { buffer[1] = 'x'; format_integer(buffer + 2, sizeof(buffer) - 2, value, 'x'); } else if (c == 'm') { - str = strerror_r(errno, strerror_buf, sizeof(strerror_buf)); + strerror_r(errno, buffer, sizeof(buffer)); } else if (c == 'd' || c == 'i' || c == 'o' || c == 'u' || c == 'x' || c == 'X') { /* integers - first read value from stack */ uint64_t value; diff --git a/tests/async_safe_test.cpp b/tests/async_safe_test.cpp index f52387e97d..dc4db07dc0 100644 --- a/tests/async_safe_test.cpp +++ b/tests/async_safe_test.cpp @@ -16,6 +16,8 @@ #include +#include + #if defined(__BIONIC__) #include #endif // __BIONIC__ @@ -227,3 +229,19 @@ TEST(async_safe_log, buffer_overrun) { GTEST_SKIP() << "bionic-only test"; #endif // __BIONIC__ } + +// Verify that using %m is never cut off. +TEST(async_safe_format_buffer, percent_m_fits_in_buffer) { +#if defined(__BIONIC__) + for (int i = 0; i < 256; i++) { + errno = i; + char async_buf[256]; + async_safe_format_buffer(async_buf, sizeof(async_buf), "%m"); + char strerror_buf[1024]; + strerror_r(errno, strerror_buf, sizeof(strerror_buf)); + ASSERT_STREQ(strerror_buf, async_buf); + } +#else // __BIONIC__ + GTEST_SKIP() << "bionic-only test"; +#endif // __BIONIC__ +} From ec96dad323ed2b0184a83cac2cbad6e1498d3d0c Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Tue, 31 Jan 2023 01:31:52 +0000 Subject: [PATCH 14/21] Purge memory. Some operations wind up allocating then freeing a significant amount of memory. So after those operations, do a purge so that the RSS of the process is not artificially inflated. Bug: 262321164 Test: Ran unit tests. Test: Verified after this change, the RSS does not go up after running Test: am dumpheap -n . Change-Id: I08477f8ce12c06fd2a068f536a81f4a577d619e2 --- libc/malloc_debug/malloc_debug.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp index 9f38946af6..c350056be0 100644 --- a/libc/malloc_debug/malloc_debug.cpp +++ b/libc/malloc_debug/malloc_debug.cpp @@ -399,6 +399,9 @@ void debug_get_malloc_leak_info(uint8_t** info, size_t* overall_size, size_t* in void debug_free_malloc_leak_info(uint8_t* info) { g_dispatch->free(info); + // Purge the memory that was freed since a significant amount of + // memory could have been allocated and freed. + g_dispatch->mallopt(M_PURGE, 0); } size_t debug_malloc_usable_size(void* pointer) { @@ -975,6 +978,10 @@ static void write_dump(int fd) { dprintf(fd, "%s", content.c_str()); } dprintf(fd, "END\n"); + + // Purge the memory that was allocated and freed during this operation + // since it can be large enough to expand the RSS significantly. + g_dispatch->mallopt(M_PURGE, 0); } bool debug_write_malloc_leak_info(FILE* fp) { From 161b85ae6cdd76786f094735b3223ecb31ea909b Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Wed, 22 Mar 2023 13:47:27 -0700 Subject: [PATCH 15/21] Move M_PURGE to M_PURGE_ALL. Since it doesn't matter if these calls take a little longer than before, use the more thorough but slightly longer purge mechanism. Test: Unit tests pass. Change-Id: Ifab7166a9682a13231746b78717d52673d13be1b --- libc/malloc_debug/malloc_debug.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp index c350056be0..7177a1e31f 100644 --- a/libc/malloc_debug/malloc_debug.cpp +++ b/libc/malloc_debug/malloc_debug.cpp @@ -401,7 +401,7 @@ void debug_free_malloc_leak_info(uint8_t* info) { g_dispatch->free(info); // Purge the memory that was freed since a significant amount of // memory could have been allocated and freed. - g_dispatch->mallopt(M_PURGE, 0); + g_dispatch->mallopt(M_PURGE_ALL, 0); } size_t debug_malloc_usable_size(void* pointer) { @@ -981,7 +981,7 @@ static void write_dump(int fd) { // Purge the memory that was allocated and freed during this operation // since it can be large enough to expand the RSS significantly. - g_dispatch->mallopt(M_PURGE, 0); + g_dispatch->mallopt(M_PURGE_ALL, 0); } bool debug_write_malloc_leak_info(FILE* fp) { From 514b352ba4532e2fe70a93ed980c74ec41798417 Mon Sep 17 00:00:00 2001 From: Danny Lin Date: Thu, 22 Jul 2021 16:12:55 -0700 Subject: [PATCH 16/21] linker: Add support for opening zip files by fd paths In some cases, it can be useful to load libraries from zip files that are only available by fd reference. For example, file descriptors of APKs containing native libraries may be sent via Binder IPC for clients to use. Unfortunately, while this linker does support loading libraries from file descriptors using android_dlopen_ext, using that API is not an option because our dlopen calls originate from JNI loadLibrary requests in ART. This is necessary for compatibility with Google Play Services' dynamic module system (Dynamite) without weakening the SELinux sandbox to allow other apps to open module APKs from /data/user_de/0/com.google.android.gms/app_chimera/m. Change-Id: If44d5c3faf4f50e4704688b520b197ff151ae05a Signed-off-by: Pranav Vashi --- linker/linker.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index 5df379936e..76450f87bd 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -904,14 +904,14 @@ class ZipArchiveCache { ZipArchiveCache() {} ~ZipArchiveCache(); - bool get_or_open(const char* zip_path, ZipArchiveHandle* handle); + bool get_or_open(const char* zip_path, int zip_fd, ZipArchiveHandle* handle); private: DISALLOW_COPY_AND_ASSIGN(ZipArchiveCache); std::unordered_map cache_; }; -bool ZipArchiveCache::get_or_open(const char* zip_path, ZipArchiveHandle* handle) { +bool ZipArchiveCache::get_or_open(const char* zip_path, int zip_fd, ZipArchiveHandle* handle) { std::string key(zip_path); auto it = cache_.find(key); @@ -920,7 +920,7 @@ bool ZipArchiveCache::get_or_open(const char* zip_path, ZipArchiveHandle* handle return true; } - int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC)); + int fd = zip_fd != -1 ? dup(zip_fd) : TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC)); if (fd == -1) { return false; } @@ -971,13 +971,19 @@ static int open_library_in_zipfile(ZipArchiveCache* zip_archive_cache, const char* zip_path = buf; const char* file_path = &buf[separator - path + 2]; - int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC)); + int fd; + if (!strncmp("/proc/self/fd/", zip_path, strlen("/proc/self/fd/")) && + sscanf(zip_path, "/proc/self/fd/%d", &fd) == 1) { + fd = dup(fd); + } else { + fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC)); + } if (fd == -1) { return -1; } ZipArchiveHandle handle; - if (!zip_archive_cache->get_or_open(zip_path, &handle)) { + if (!zip_archive_cache->get_or_open(zip_path, fd, &handle)) { // invalid zip-file (?) close(fd); return -1; From 7807a6d964e3e331c59e078f0d8de4e100051080 Mon Sep 17 00:00:00 2001 From: John Galt Date: Wed, 22 Mar 2023 10:14:20 -0400 Subject: [PATCH 17/21] async_safe: build with full LTO Needed to bring back full LTO on libandroid_runtime defaults. Dropped due to ThinLTO breakage not present on Full LTO. Signed-off-by: Pranav Vashi --- libc/async_safe/Android.bp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libc/async_safe/Android.bp b/libc/async_safe/Android.bp index 531317d152..fe89687caa 100644 --- a/libc/async_safe/Android.bp +++ b/libc/async_safe/Android.bp @@ -39,6 +39,9 @@ cc_library_static { "com.android.virt", ], min_sdk_version: "apex_inherit", + lto: { + full: true, + }, } cc_library_headers { From 39b1e38943c738cad64b2ddd573456d2dcb73b8b Mon Sep 17 00:00:00 2001 From: ShevT Date: Thu, 4 Aug 2022 16:25:10 +0300 Subject: [PATCH 18/21] libc: Add TARGET_ALTERNATIVE_FUTEX_WAITERS Using the flag fixes OnePlus / MI camera portrait mode Change-Id: If40b96c9e8ae934bea798c15b139d8cdddc04f68 Signed-off-by: Pranav Vashi --- libc/Android.bp | 5 ++++- libc/bionic/pthread_cond.cpp | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/libc/Android.bp b/libc/Android.bp index 0313993a2c..e049951791 100644 --- a/libc/Android.bp +++ b/libc/Android.bp @@ -1252,7 +1252,10 @@ cc_library_static { // ======================================================== cc_library_static { - defaults: ["libc_defaults"], + defaults: [ + "libc_defaults", + "target_alternative_futex_waiters_defaults" + ], srcs: [ "bionic/bionic_elf_tls.cpp", "bionic/pthread_atfork.cpp", diff --git a/libc/bionic/pthread_cond.cpp b/libc/bionic/pthread_cond.cpp index 793dcd9421..5e88814557 100644 --- a/libc/bionic/pthread_cond.cpp +++ b/libc/bionic/pthread_cond.cpp @@ -116,9 +116,13 @@ struct pthread_cond_internal_t { } #if defined(__LP64__) +#if defined(TARGET_ALTERNATIVE_FUTEX_WAITERS) + char __reserved[44]; +#else atomic_uint waiters; char __reserved[40]; #endif +#endif }; static_assert(sizeof(pthread_cond_t) == sizeof(pthread_cond_internal_t), @@ -143,7 +147,9 @@ int pthread_cond_init(pthread_cond_t* cond_interface, const pthread_condattr_t* atomic_init(&cond->state, init_state); #if defined(__LP64__) +#if !defined(TARGET_ALTERNATIVE_FUTEX_WAITERS) atomic_init(&cond->waiters, 0); +#endif #endif return 0; @@ -169,9 +175,11 @@ static int __pthread_cond_pulse(pthread_cond_internal_t* cond, int thread_count) // synchronization. And it doesn't help even if we use any fence here. #if defined(__LP64__) +#if !defined(TARGET_ALTERNATIVE_FUTEX_WAITERS) if (atomic_load_explicit(&cond->waiters, memory_order_relaxed) == 0) { return 0; } +#endif #endif // The increase of value should leave flags alone, even if the value can overflows. @@ -191,7 +199,9 @@ static int __pthread_cond_timedwait(pthread_cond_internal_t* cond, pthread_mutex unsigned int old_state = atomic_load_explicit(&cond->state, memory_order_relaxed); #if defined(__LP64__) +#if !defined(TARGET_ALTERNATIVE_FUTEX_WAITERS) atomic_fetch_add_explicit(&cond->waiters, 1, memory_order_relaxed); +#endif #endif pthread_mutex_unlock(mutex); @@ -199,7 +209,9 @@ static int __pthread_cond_timedwait(pthread_cond_internal_t* cond, pthread_mutex use_realtime_clock, abs_timeout_or_null); #if defined(__LP64__) +#if !defined(TARGET_ALTERNATIVE_FUTEX_WAITERS) atomic_fetch_sub_explicit(&cond->waiters, 1, memory_order_relaxed); +#endif #endif pthread_mutex_lock(mutex); From 60fd843dcb443e4bcef48383592fb8be49f2a271 Mon Sep 17 00:00:00 2001 From: Gabor Meszaros Date: Fri, 21 Jan 2022 13:54:21 +0100 Subject: [PATCH 19/21] libc:Enable thinLTO for note_memtag_heap_async & note_memtag_heap_sync Somehow this fixes build with GLOBAL_THINLTO=1 Change-Id: I4c7b8ffb6fe01fe91d08d144dca4c4b60bf6dd7e Signed-off-by: Pranav Vashi Signed-off-by: strwbrry143 Signed-off-by: minaripenguin37 --- libc/Android.bp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libc/Android.bp b/libc/Android.bp index e049951791..76f6f14779 100644 --- a/libc/Android.bp +++ b/libc/Android.bp @@ -2230,7 +2230,9 @@ cc_library_static { } }, sdk_version: "minimum", - + lto: { + thin: true, + }, defaults: ["crt_and_memtag_defaults"], } @@ -2242,7 +2244,9 @@ cc_library_static { } }, sdk_version: "minimum", - + lto: { + thin: true, + }, defaults: ["crt_and_memtag_defaults"], } From 909ce28f955f5e2c58b5bf927ce25f2b90f689d6 Mon Sep 17 00:00:00 2001 From: dkati Date: Sun, 14 Oct 2018 02:07:04 +0300 Subject: [PATCH 20/21] bionic: Enable -O3 Change-Id: Ia82860326de114d48dea0e8cd93b836f1e826e15 Signed-off-by: Pranav Vashi --- benchmarks/Android.bp | 3 ++- libc/Android.bp | 12 ++++++++++++ libdl/Android.bp | 2 ++ linker/Android.bp | 4 ++++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/benchmarks/Android.bp b/benchmarks/Android.bp index 17d2d68f94..61e1f41711 100644 --- a/benchmarks/Android.bp +++ b/benchmarks/Android.bp @@ -33,7 +33,7 @@ license { cc_defaults { name: "bionic-benchmarks-defaults", cflags: [ - "-O2", + "-O3", "-fno-builtin", "-Wall", "-Wextra", @@ -86,6 +86,7 @@ cc_defaults { "-Wextra", "-Werror", "-Wunused", + "-O3", ], } diff --git a/libc/Android.bp b/libc/Android.bp index 76f6f14779..4fdd46cfe1 100644 --- a/libc/Android.bp +++ b/libc/Android.bp @@ -55,6 +55,7 @@ libc_common_flags = [ "-Wno-deprecated-declarations", "-Wno-gcc-compat", "-Wframe-larger-than=2048", + "-O3", // Try to catch typical 32-bit assumptions that break with 64-bit pointers. "-Werror=pointer-to-int-cast", @@ -271,6 +272,7 @@ cc_library_static { "-DWILDABBR=\"\"", "-DNO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU", "-Dlint", + "-O3", ], local_include_dirs: ["tzcode/"], @@ -380,6 +382,7 @@ cc_library_static { "-Wno-sign-compare", "-Wno-unused-parameter", "-include freebsd-compat.h", + "-O3", ], local_include_dirs: [ @@ -399,6 +402,7 @@ cc_library_static { "-Wno-sign-compare", "-include freebsd-compat.h", "-Wframe-larger-than=66000", + "-O3", ], local_include_dirs: [ @@ -453,6 +457,7 @@ cc_library_static { "-Wno-unused-parameter", "-DPOSIX_MISTAKE", "-include netbsd-compat.h", + "-O3", ], local_include_dirs: [ @@ -585,6 +590,7 @@ cc_library_static { "-Wno-sign-compare", "-Wno-unused-parameter", "-include openbsd-compat.h", + "-O3", ], local_include_dirs: [ @@ -609,6 +615,7 @@ cc_library_static { "-include openbsd-compat.h", "-Wno-sign-compare", "-Wframe-larger-than=5000", + "-O3", ], local_include_dirs: [ @@ -697,6 +704,7 @@ cc_library_static { "-Wno-sign-compare", "-Wno-unused-parameter", "-include openbsd-compat.h", + "-O3", ], local_include_dirs: [ @@ -745,6 +753,7 @@ cc_library_static { cflags: [ "-Wno-sign-compare", "-include openbsd-compat.h", + "-O3", ], local_include_dirs: [ @@ -771,6 +780,7 @@ cc_library_static { cflags: [ "-U_FORTIFY_SOURCE", "-D__BIONIC_DECLARE_FORTIFY_HELPERS", + "-O3", ], arch: { @@ -1429,6 +1439,7 @@ cc_library_static { cflags: [ "-fvisibility=hidden", "-DLIBC_STATIC", + "-O3", ], whole_static_libs: [ @@ -2092,6 +2103,7 @@ cc_defaults { "-Wno-gcc-compat", "-Wall", "-Werror", + "-O3", ], sanitize: { never: true, diff --git a/libdl/Android.bp b/libdl/Android.bp index 750a6e26f5..19e1b5280f 100644 --- a/libdl/Android.bp +++ b/libdl/Android.bp @@ -34,6 +34,7 @@ cc_library_static { "-Wextra", "-Wunused", "-Werror", + "-O3", ], // For private/CFIShadow.h. @@ -197,6 +198,7 @@ cc_library { "-Wextra", "-Wunused", "-Werror", + "-O3", ], stl: "none", diff --git a/linker/Android.bp b/linker/Android.bp index 63d4daee83..87d1739f64 100644 --- a/linker/Android.bp +++ b/linker/Android.bp @@ -43,6 +43,7 @@ cc_object { "-Wextra", "-Wno-unused", "-Werror", + "-O3", ], srcs: [ @@ -266,6 +267,8 @@ cc_defaults { "-Wl,-soname,ld-android.so", ], + cflags: ["-O3"], + // we are going to link libc++_static manually because // when stl is not set to "none" build system adds libdl // to the list of static libraries which needs to be @@ -429,6 +432,7 @@ cc_library { "-Wextra", "-Wunused", "-Werror", + "-O3", ], stl: "none", From 250a7c2e28f9ee5a8b3ecbed7f40e6ae064e92da Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Fri, 19 Aug 2022 13:09:18 +0900 Subject: [PATCH 21/21] Use liblog_for_runtime_apex instead of liblog liblog_for_runtime_apex is a static variant of liblog which is explicitly marked as available to the runtime APEX. Any static dependency to liblog from inside the runtime APEX is changed from liblog to liblog_for_runtime_apex. Previously, to support the need for using liblog inside the runtime APEX, the entire (i.e. both static and shared variants) liblog module was marked as available to the runtime APEX, although in reality only the static variant of the library was needed there. This was not only looking dirty, but also has caused a problem like b/241259844. To fix this, liblog is separated into two parts. (1) liblog and (2) liblog_for_runtime_apex. (1) no longer is available to the runtime APEX and is intended to be depended on in most cases: either from the non-updatable platform, or from other APEXes. (2) is a static library which is explicitly marked as available to the runtime APEX and also visible to certain modules that are included in the runtime APEX. Bug: 241259844 Test: m and check that liblog depends on stub library of libc Change-Id: Ib21f6e64da0c7592341b97b95ca8485d7c29ac4d --- linker/Android.bp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linker/Android.bp b/linker/Android.bp index 87d1739f64..408c158d52 100644 --- a/linker/Android.bp +++ b/linker/Android.bp @@ -119,7 +119,7 @@ cc_defaults { "libasync_safe", - "liblog", + "liblog_for_runtime_apex", ], // We need to access Bionic private headers in the linker. @@ -501,7 +501,7 @@ cc_test { static_libs: [ "libasync_safe", "libbase", - "liblog", + "liblog_for_runtime_apex", ], arch: {