Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/bionic/bionic/tests/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 9 kB image not shown  

SSL malloc_iterate_test.cpp

  Sprache: C
 

/*
 * Copyright (C) 2018 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.
 */


// (b/291762537): This code uses malloc_usable_size(), and thus can't be
// built with _FORTIFY_SOURCE>=3.
#if defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE >= 3
#undef _FORTIFY_SOURCE
#define _FORTIFY_SOURCE 2
#endif

#include <gtest/gtest.h>

#if defined(__BIONIC__)

#include <inttypes.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

#include <ios>
#include <vector>

#include <android-base/stringprintf.h>
#include <android-base/test_utils.h>
#include <async_safe/log.h>
#include <procinfo/process_map.h>

#include "utils.h"

extern "C" void malloc_disable();
extern "C" void malloc_enable();
extern "C" int malloc_iterate(uintptr_t base, size_t size, void (*callback)(uintptr_t base,
                              size_t size, void* arg), void* arg);

struct AllocDataType {
  void* ptr;
  size_t size;
  size_t size_reported;
  size_t count;
};

constexpr size_t kMaxFailures = 10;
struct TestDataType {
  size_t total_allocated_bytes;
  std::vector<AllocDataType> allocs;
  // This data structure is updated during the callback for malloc_iterate.
  // Since no allocations are allowed in this callback, we have an array to
  // contain any errors encountered to be reported after the call is done.
  AllocDataType failures[kMaxFailures] = {};
  size_t num_failures = 0;
};

static void AllocPtr(TestDataType* test_data, size_t size) {
  test_data->allocs.resize(test_data->allocs.size() + 1);
  AllocDataType* alloc = &test_data->allocs.back();
  void* ptr = malloc(size);
  ASSERT_TRUE(ptr != nullptr);
  alloc->ptr = ptr;
  alloc->size = malloc_usable_size(ptr);
  alloc->size_reported = 0;
  alloc->count = 0;
}

static void FreePtrs(TestDataType* test_data) {
  for (size_t i = 0; i < test_data->allocs.size(); i++) {
    free(test_data->allocs[i].ptr);
  }
}

static void SavePointers(uintptr_t base, size_t size, void* data) {
  TestDataType* test_data = reinterpret_cast<TestDataType*>(data);

  test_data->total_allocated_bytes += size;

  uintptr_t end;
  if (__builtin_add_overflow(base, size, &end)) {
    size_t index = test_data->num_failures;
    if (index < kMaxFailures) {
      test_data->failures[index].ptr = reinterpret_cast<void*>(base);
      test_data->failures[index].size = size;
      test_data->num_failures++;
    }
    return;
  }

  for (size_t i = 0; i < test_data->allocs.size(); i++) {
    uintptr_t ptr = reinterpret_cast<uintptr_t>(test_data->allocs[i].ptr);
    if (ptr >= base && ptr < end) {
      test_data->allocs[i].count++;

      uintptr_t usable_size = end - ptr;
      if (usable_size > test_data->allocs[i].size) {
        // The usable size is greater than the allocated size, so set
        // the size reported to allocated size.
        test_data->allocs[i].size_reported = test_data->allocs[i].size;
      } else {
        test_data->allocs[i].size_reported = usable_size;
      }
      break;
    }
  }
}

static void VerifyPtrs(TestDataType* test_data) {
  test_data->total_allocated_bytes = 0;

  // Find all of the maps that are from the native allocator.
  auto callback = [&](uint64_t start, uint64_t end, uint16_t, uint64_t, ino_t, const char* name,
                      bool) {
    if (strcmp(name, "[anon:libc_malloc]") == 0 || strncmp(name, "[anon:scudo:"12) == 0 ||
        strncmp(name, "[anon:GWP-ASan"14) == 0) {
      malloc_iterate(start, end - start, SavePointers, test_data);
    }
  };

  std::vector<char> buffer(64 * 1024);

  // Avoid doing allocations so that the maps don't change while looking
  // for the pointers.
  malloc_disable();
  bool parsed = android::procinfo::ReadMapFileAsyncSafe("/proc/self/maps", buffer.data(),
                                                        buffer.size(), callback);
  malloc_enable();

  ASSERT_TRUE(parsed) << "Failed to parse /proc/self/maps";

  if (test_data->num_failures != 0) {
    std::string error_msg;
    for (size_t i = 0; i < test_data->num_failures; i++) {
      error_msg +=
          android::base::StringPrintf("Pointer overflow %p size %zu\n", test_data->failures[i].ptr,
                                      test_data->failures[i].size);
    }
    FAIL() << error_msg;
  }

  for (size_t i = 0; i < test_data->allocs.size(); i++) {
    EXPECT_EQ(1UL, test_data->allocs[i].count)
        << "Unable to find allocation of size " << test_data->allocs[i].size;
    if (test_data->allocs[i].count == 1) {
      EXPECT_EQ(test_data->allocs[i].size, test_data->allocs[i].size_reported);
    }
  }
}

static void AllocateSizes(TestDataType* test_data, const std::vector<size_t>& sizes) {
  static constexpr size_t kInitialAllocations = 40;
  static constexpr size_t kNumAllocs = 50;
  for (size_t size : sizes) {
    // Verify that if the tcache is enabled, that tcache pointers
    // are found by allocating and freeing 20 pointers (should be larger
    // than the total number of cache entries).
    for (size_t i = 0; i < kInitialAllocations; i++) {
      void* ptr = malloc(size);
      ASSERT_TRUE(ptr != nullptr);
      memset(ptr, 0, size);
      free(ptr);
    }
    for (size_t i = 0; i < kNumAllocs; i++) {
      AllocPtr(test_data, size);
    }
  }
}
#endif

// Verify that small allocs can be found properly.
TEST(malloc_iterate, small_allocs) {
#if defined(__BIONIC__)
  SKIP_WITH_HWASAN;
  TestDataType test_data;

  // Try to cycle through all of the different small bins.
  // This is specific to the implementation of jemalloc and should be
  // adjusted if a different native memory allocator is used.
  std::vector<size_t> sizes{8,    16,   32,   48,    64,    80,    96,    112,   128,  160,
                            192,  224,  256,  320,   384,   448,   512,   640,   768,  896,
                            1024128015361792,  2048,  2560,  3072,  3584,  40965120,
                            614471688192102401228814336163843276865536};
  AllocateSizes(&test_data, sizes);

  SCOPED_TRACE("");
  VerifyPtrs(&test_data);

  FreePtrs(&test_data);
#else
  GTEST_SKIP() << "bionic-only test";
#endif
}

// Verify that large allocs can be found properly.
TEST(malloc_iterate, large_allocs) {
#if defined(__BIONIC__)
  SKIP_WITH_HWASAN;
  TestDataType test_data;

  // Try some larger sizes.
  std::vector<size_t> sizes{13107226214452428810485762097152};
  AllocateSizes(&test_data, sizes);

  SCOPED_TRACE("");
  VerifyPtrs(&test_data);

  FreePtrs(&test_data);
#else
  GTEST_SKIP() << "bionic-only test";
#endif
}

// Verify that there are no crashes attempting to get pointers from
// non-allocated pointers.
TEST(malloc_iterate, invalid_pointers) {
#if defined(__BIONIC__)
  SKIP_WITH_HWASAN;
  TestDataType test_data = {};

  // Only attempt to get memory data for maps that are not from the native allocator.
  auto callback = [&](uint64_t start, uint64_t end, uint16_t, uint64_t, ino_t, const char* name,
                      bool) {
    if (strcmp(name, "[anon:libc_malloc]") != 0 && strncmp(name, "[anon:scudo:"12) != 0 &&
        strncmp(name, "[anon:GWP-ASan"14) != 0) {
      size_t total = test_data.total_allocated_bytes;
      malloc_iterate(start, end - start, SavePointers, &test_data);
      total = test_data.total_allocated_bytes - total;
      if (total > 0) {
        char buffer[256];
        int len = 0;
        if (name[0] != '\0') {
          len = async_safe_format_buffer(buffer, sizeof(buffer), "Failed on map %s: %zu\n", name,
                                         total);
        } else {
          len = async_safe_format_buffer(buffer, sizeof(buffer),
                                         "Failed on map anon:<%" PRIx64 "-%" PRIx64 ">: %zu\n",
                                         start, end, total);
        }
        if (len > 0) {
          write(STDOUT_FILENO, buffer, len);
        }
      }
    }
  };

  std::vector<char> buffer(64 * 1024);

  // Need to make sure that there are no allocations while reading the
  // maps. Otherwise, it might create a new map during this check and
  // incorrectly think a map is empty while it actually includes real
  // allocations.
  malloc_disable();
  bool parsed = android::procinfo::ReadMapFileAsyncSafe("/proc/self/maps", buffer.data(),
                                                        buffer.size(), callback);
  malloc_enable();

  ASSERT_TRUE(parsed) << "Failed to parse /proc/self/maps";

  ASSERT_EQ(0UL, test_data.total_allocated_bytes);
#else
  GTEST_SKIP() << "bionic-only test";
#endif
}

TEST(malloc_iterate, malloc_disable_prevents_allocs) {
#if defined(__BIONIC__)
  SKIP_WITH_HWASAN;
  pid_t pid;
  if ((pid = fork()) == 0) {
    malloc_disable();
    void* ptr = malloc(1024);
    if (ptr == nullptr) {
      exit(1);
    }
    memset(ptr, 01024);
    exit(0);
  }
  ASSERT_NE(-1, pid);

  // Expect that the malloc will hang forever, and that if the process
  // does not return for two seconds, it is hung.
  sleep(2);
  pid_t wait_pid = TEMP_FAILURE_RETRY(waitpid(pid, nullptr, WNOHANG));
  if (wait_pid <= 0) {
    kill(pid, SIGKILL);
  }
  ASSERT_NE(-1, wait_pid) << "Unknown failure in waitpid.";
  ASSERT_EQ(0, wait_pid) << "malloc_disable did not prevent allocation calls.";
#else
  GTEST_SKIP() << "bionic-only test";
#endif
}

Messung V0.5 in Prozent
C=90 H=93 G=91

¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.19Angebot  (Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-06-28) ¤

*Eine klare Vorstellung vom Zielzustand






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.