text: // Copyright 2017 The Abseil Authors.
  //
  // 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 "absl/base/internal/malloc_extension.h"
  
  #include <assert.h>
  #include <string.h>
  #include <atomic>
  #include <string>
  
  #include "absl/base/dynamic_annotations.h"
  #include "absl/base/internal/malloc_extension_c.h"
  
  namespace absl {
  namespace base_internal {
  
  // SysAllocator implementation
  SysAllocator::~SysAllocator() {}
  void SysAllocator::GetStats(char* buffer, int) { buffer[0] = 0; }
  
  // Dummy key method to avoid weak vtable.
  void MallocExtensionWriter::UnusedKeyMethod() {}
  
  void StringMallocExtensionWriter::Write(const char* buf, int len) {
    out_->append(buf, len);
  }
  
  // Default implementation -- does nothing
  MallocExtension::~MallocExtension() { }
  bool MallocExtension::VerifyAllMemory() { return true; }
  bool MallocExtension::VerifyNewMemory(const void*) { return true; }
  bool MallocExtension::VerifyArrayNewMemory(const void*) { return true; }
  bool MallocExtension::VerifyMallocMemory(const void*) { return true; }
  
  bool MallocExtension::GetNumericProperty(const char*, size_t*) {
    return false;
  }
  
  bool MallocExtension::SetNumericProperty(const char*, size_t) {
    return false;
  }
  
  void MallocExtension::GetStats(char* buffer, int length) {
    assert(length > 0);
    static_cast<void>(length);
    buffer[0] = '\0';
  }
  
  bool MallocExtension::MallocMemoryStats(int* blocks, size_t* total,
                                          int histogram[kMallocHistogramSize]) {
    *blocks = 0;
    *total = 0;
    memset(histogram, 0, sizeof(*histogram) * kMallocHistogramSize);
    return true;
  }
  
  void MallocExtension::MarkThreadIdle() {
    // Default implementation does nothing
  }
  
  void MallocExtension::MarkThreadBusy() {
    // Default implementation does nothing
  }
  
  SysAllocator* MallocExtension::GetSystemAllocator() {
    return nullptr;
  }
  
  void MallocExtension::SetSystemAllocator(SysAllocator*) {
    // Default implementation does nothing
  }
  
  void MallocExtension::ReleaseToSystem(size_t) {
    // Default implementation does nothing
  }
  
  void MallocExtension::ReleaseFreeMemory() {
    ReleaseToSystem(static_cast<size_t>(-1));   // SIZE_T_MAX
  }
  
  void MallocExtension::SetMemoryReleaseRate(double) {
    // Default implementation does nothing
  }
  
  double MallocExtension::GetMemoryReleaseRate() {
    return -1.0;
  }
  
  size_t MallocExtension::GetEstimatedAllocatedSize(size_t size) {
    return size;
  }
  
  size_t MallocExtension::GetAllocatedSize(const void* p) {
    assert(GetOwnership(p) != kNotOwned);
    static_cast<void>(p);
    return 0;
  }
  
  MallocExtension::Ownership MallocExtension::GetOwnership(const void*) {
    return kUnknownOwnership;
  }
  
  void MallocExtension::GetProperties(MallocExtension::StatLevel,
                                      std::map<std::string, Property>* result) {
    result->clear();
  }
  
  size_t MallocExtension::ReleaseCPUMemory(int) {
    return 0;
  }
  
  // The current malloc extension object.
  
  std::atomic<MallocExtension*> MallocExtension::current_instance_;
  
  MallocExtension* MallocExtension::InitModule() {
    MallocExtension* ext = new MallocExtension;
    current_instance_.store(ext, std::memory_order_release);
    return ext;
  }
  
  void MallocExtension::Register(MallocExtension* implementation) {
    InitModuleOnce();
    // When running under valgrind, our custom malloc is replaced with
    // valgrind's one and malloc extensions will not work.  (Note:
    // callers should be responsible for checking that they are the
    // malloc that is really being run, before calling Register.  This
    // is just here as an extra sanity check.)
    // Under compiler-based ThreadSanitizer RunningOnValgrind() returns true,
    // but we still want to use malloc extensions.
  #ifndef THREAD_SANITIZER
    if (RunningOnValgrind()) {
      return;
    }
  #endif  // #ifndef THREAD_SANITIZER
    current_instance_.store(implementation, std::memory_order_release);
  }
  void MallocExtension::GetHeapSample(MallocExtensionWriter*) {}
  
  void MallocExtension::GetHeapGrowthStacks(MallocExtensionWriter*) {}
  
  void MallocExtension::GetFragmentationProfile(MallocExtensionWriter*) {}
  
  }  // namespace base_internal
  }  // namespace absl
  
  // These are C shims that work on the current instance.
  
  #define C_SHIM(fn, retval, paramlist, arglist)                           \
    extern "C" retval MallocExtension_##fn paramlist {                     \
      return absl::base_internal::MallocExtension::instance()->fn arglist; \
    }
  
  C_SHIM(VerifyAllMemory, int, (void), ());
  C_SHIM(VerifyNewMemory, int, (const void* p), (p));
  C_SHIM(VerifyArrayNewMemory, int, (const void* p), (p));
  C_SHIM(VerifyMallocMemory, int, (const void* p), (p));
  C_SHIM(
      MallocMemoryStats, int,
      (int* blocks, size_t* total,
       int histogram[absl::base_internal::MallocExtension::kMallocHistogramSize]),
      (blocks, total, histogram));
  
  C_SHIM(GetStats, void,
         (char* buffer, int buffer_length), (buffer, buffer_length));
  C_SHIM(GetNumericProperty, int,
         (const char* property, size_t* value), (property, value));
  C_SHIM(SetNumericProperty, int,
         (const char* property, size_t value), (property, value));
  
  C_SHIM(MarkThreadIdle, void, (void), ());
  C_SHIM(MarkThreadBusy, void, (void), ());
  C_SHIM(ReleaseFreeMemory, void, (void), ());
  C_SHIM(ReleaseToSystem, void, (size_t num_bytes), (num_bytes));
  C_SHIM(GetEstimatedAllocatedSize, size_t, (size_t size), (size));
  C_SHIM(GetAllocatedSize, size_t, (const void* p), (p));
  
  // Can't use the shim here because of the need to translate the enums.
  extern "C"
  MallocExtension_Ownership MallocExtension_GetOwnership(const void* p) {
    return static_cast<MallocExtension_Ownership>(
        absl::base_internal::MallocExtension::instance()->GetOwnership(p));
  }
  
  // Default implementation just returns size. The expectation is that
  // the linked-in malloc implementation might provide an override of
  // this weak function with a better implementation.
  ABSL_ATTRIBUTE_WEAK ABSL_ATTRIBUTE_NOINLINE size_t nallocx(size_t size, int) {
    return size;
  }
  