blob: 79e40723765f8fb3c67cb290456fa8ac8df83e91 [file] [log] [blame] [edit]
/*
* Copyright (C) 2009 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 <errno.h>
#include <stdatomic.h>
#include <platform/bionic/malloc.h>
#include <private/bionic_globals.h>
#include "gwp_asan_wrappers.h"
#include "malloc_limit.h"
#if !defined(LIBC_STATIC)
#include <stdio.h>
#include <private/bionic_defs.h>
#include "malloc_heapprofd.h"
extern bool gZygoteChild;
extern _Atomic bool gZygoteChildProfileable;
bool WriteMallocLeakInfo(FILE* fp);
bool GetMallocLeakInfo(android_mallopt_leak_info_t* leak_info);
bool FreeMallocLeakInfo(android_mallopt_leak_info_t* leak_info);
#endif
// =============================================================================
// Platform-internal mallopt variant.
// =============================================================================
#if !defined(LIBC_STATIC)
__BIONIC_WEAK_FOR_NATIVE_BRIDGE
#endif
extern "C" bool android_mallopt(int opcode, void* arg, size_t arg_size) {
// Functionality available in both static and dynamic libc.
if (opcode == M_GET_DECAY_TIME_ENABLED) {
if (arg == nullptr || arg_size != sizeof(bool)) {
errno = EINVAL;
return false;
}
*reinterpret_cast<bool*>(arg) = atomic_load(&__libc_globals->decay_time_enabled);
return true;
}
if (opcode == M_INITIALIZE_GWP_ASAN) {
if (arg == nullptr || arg_size != sizeof(android_mallopt_gwp_asan_options_t)) {
errno = EINVAL;
return false;
}
return EnableGwpAsan(*reinterpret_cast<android_mallopt_gwp_asan_options_t*>(arg));
}
if (opcode == M_MEMTAG_STACK_IS_ON) {
if (arg == nullptr || arg_size != sizeof(bool)) {
errno = EINVAL;
return false;
}
*reinterpret_cast<bool*>(arg) = atomic_load(&__libc_memtag_stack);
return true;
}
if (opcode == M_SET_ALLOCATION_LIMIT_BYTES) {
return LimitEnable(arg, arg_size);
}
#if defined(LIBC_STATIC)
errno = ENOTSUP;
return false;
#else
if (opcode == M_SET_ZYGOTE_CHILD) {
if (arg != nullptr || arg_size != 0) {
errno = EINVAL;
return false;
}
gZygoteChild = true;
return true;
}
if (opcode == M_INIT_ZYGOTE_CHILD_PROFILING) {
if (arg != nullptr || arg_size != 0) {
errno = EINVAL;
return false;
}
atomic_store_explicit(&gZygoteChildProfileable, true, memory_order_release);
// Also check if heapprofd should start profiling from app startup.
HeapprofdInitZygoteChildProfiling();
return true;
}
if (opcode == M_GET_PROCESS_PROFILEABLE) {
if (arg == nullptr || arg_size != sizeof(bool)) {
errno = EINVAL;
return false;
}
// Native processes are considered profileable. Zygote children are considered
// profileable only when appropriately tagged.
*reinterpret_cast<bool*>(arg) =
!gZygoteChild || atomic_load_explicit(&gZygoteChildProfileable, memory_order_acquire);
return true;
}
if (opcode == M_WRITE_MALLOC_LEAK_INFO_TO_FILE) {
if (arg == nullptr || arg_size != sizeof(FILE*)) {
errno = EINVAL;
return false;
}
return WriteMallocLeakInfo(reinterpret_cast<FILE*>(arg));
}
if (opcode == M_GET_MALLOC_LEAK_INFO) {
if (arg == nullptr || arg_size != sizeof(android_mallopt_leak_info_t)) {
errno = EINVAL;
return false;
}
return GetMallocLeakInfo(reinterpret_cast<android_mallopt_leak_info_t*>(arg));
}
if (opcode == M_FREE_MALLOC_LEAK_INFO) {
if (arg == nullptr || arg_size != sizeof(android_mallopt_leak_info_t)) {
errno = EINVAL;
return false;
}
return FreeMallocLeakInfo(reinterpret_cast<android_mallopt_leak_info_t*>(arg));
}
// Try heapprofd's mallopt, as it handles options not covered here.
return HeapprofdMallopt(opcode, arg, arg_size);
#endif
}