brintos

brintos / llvm-project-archived public Read only

0
0
Text · 19.4 KiB · 9e5d065 Raw
682 lines · cpp
1//===-- wrappers_c_test.cpp -------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "common.h"10#include "memtag.h"11#include "scudo/interface.h"12#include "tests/scudo_unit_test.h"13 14#include <errno.h>15#include <limits.h>16#include <malloc.h>17#include <stdlib.h>18#include <unistd.h>19#include <vector>20 21#ifndef __GLIBC_PREREQ22#define __GLIBC_PREREQ(x, y) 023#endif24 25#if SCUDO_FUCHSIA26// Fuchsia only has valloc27#define HAVE_VALLOC 128#elif SCUDO_ANDROID29// Android only has pvalloc/valloc on 32 bit30#if !defined(__LP64__)31#define HAVE_PVALLOC 132#define HAVE_VALLOC 133#endif // !defined(__LP64__)34#else35// All others assumed to support both functions.36#define HAVE_PVALLOC 137#define HAVE_VALLOC 138#endif39 40extern "C" {41void malloc_enable(void);42void malloc_disable(void);43int malloc_iterate(uintptr_t base, size_t size,44                   void (*callback)(uintptr_t base, size_t size, void *arg),45                   void *arg);46void *valloc(size_t size);47void *pvalloc(size_t size);48 49#ifndef SCUDO_ENABLE_HOOKS_TESTS50#define SCUDO_ENABLE_HOOKS_TESTS 051#endif52 53#if (SCUDO_ENABLE_HOOKS_TESTS == 1) && (SCUDO_ENABLE_HOOKS == 0)54#error "Hooks tests should have hooks enabled as well!"55#endif56 57struct AllocContext {58  void *Ptr;59  size_t Size;60};61struct DeallocContext {62  void *Ptr;63};64struct ReallocContext {65  void *AllocPtr;66  void *DeallocPtr;67  size_t Size;68};69static AllocContext AC;70static DeallocContext DC;71static ReallocContext RC;72 73#if (SCUDO_ENABLE_HOOKS_TESTS == 1)74__attribute__((visibility("default"))) void __scudo_allocate_hook(void *Ptr,75                                                                  size_t Size) {76  AC.Ptr = Ptr;77  AC.Size = Size;78}79__attribute__((visibility("default"))) void __scudo_deallocate_hook(void *Ptr) {80  DC.Ptr = Ptr;81}82__attribute__((visibility("default"))) void83__scudo_realloc_allocate_hook(void *OldPtr, void *NewPtr, size_t Size) {84  // Verify that __scudo_realloc_deallocate_hook is called first and set the85  // right pointer.86  EXPECT_EQ(OldPtr, RC.DeallocPtr);87  RC.AllocPtr = NewPtr;88  RC.Size = Size;89 90  // Note that this is only used for testing. In general, only one pair of hooks91  // will be invoked in `realloc`. if __scudo_realloc_*_hook are not defined,92  // it'll call the general hooks only. To make the test easier, we call the93  // general one here so that either case (whether __scudo_realloc_*_hook are94  // defined) will be verified without separating them into different tests.95  __scudo_allocate_hook(NewPtr, Size);96}97__attribute__((visibility("default"))) void98__scudo_realloc_deallocate_hook(void *Ptr) {99  RC.DeallocPtr = Ptr;100 101  // See the comment in the __scudo_realloc_allocate_hook above.102  __scudo_deallocate_hook(Ptr);103}104#endif // (SCUDO_ENABLE_HOOKS_TESTS == 1)105}106 107class ScudoWrappersCTest : public Test {108protected:109  void SetUp() override {110    if (SCUDO_ENABLE_HOOKS && !SCUDO_ENABLE_HOOKS_TESTS)111      printf("Hooks are enabled but hooks tests are disabled.\n");112  }113 114  void invalidateHookPtrs() {115    if (SCUDO_ENABLE_HOOKS_TESTS) {116      void *InvalidPtr = reinterpret_cast<void *>(0xdeadbeef);117      AC.Ptr = InvalidPtr;118      DC.Ptr = InvalidPtr;119      RC.AllocPtr = RC.DeallocPtr = InvalidPtr;120    }121  }122  void verifyAllocHookPtr(UNUSED void *Ptr) {123    if (SCUDO_ENABLE_HOOKS_TESTS)124      EXPECT_EQ(Ptr, AC.Ptr);125  }126  void verifyAllocHookSize(UNUSED size_t Size) {127    if (SCUDO_ENABLE_HOOKS_TESTS)128      EXPECT_EQ(Size, AC.Size);129  }130  void verifyDeallocHookPtr(UNUSED void *Ptr) {131    if (SCUDO_ENABLE_HOOKS_TESTS)132      EXPECT_EQ(Ptr, DC.Ptr);133  }134  void verifyReallocHookPtrs(UNUSED void *OldPtr, void *NewPtr, size_t Size) {135    if (SCUDO_ENABLE_HOOKS_TESTS) {136      EXPECT_EQ(OldPtr, RC.DeallocPtr);137      EXPECT_EQ(NewPtr, RC.AllocPtr);138      EXPECT_EQ(Size, RC.Size);139    }140  }141};142using ScudoWrappersCDeathTest = ScudoWrappersCTest;143 144// Note that every C allocation function in the test binary will be fulfilled145// by Scudo (this includes the gtest APIs, etc.), which is a test by itself.146// But this might also lead to unexpected side-effects, since the allocation and147// deallocation operations in the TEST functions will coexist with others (see148// the EXPECT_DEATH comment below).149 150// We have to use a small quarantine to make sure that our double-free tests151// trigger. Otherwise EXPECT_DEATH ends up reallocating the chunk that was just152// freed (this depends on the size obviously) and the following free succeeds.153 154static const size_t Size = 100U;155 156TEST_F(ScudoWrappersCDeathTest, Malloc) {157  void *P = malloc(Size);158  EXPECT_NE(P, nullptr);159  EXPECT_LE(Size, malloc_usable_size(P));160  EXPECT_EQ(reinterpret_cast<uintptr_t>(P) % FIRST_32_SECOND_64(8U, 16U), 0U);161  verifyAllocHookPtr(P);162  verifyAllocHookSize(Size);163 164  // An update to this warning in Clang now triggers in this line, but it's ok165  // because the check is expecting a bad pointer and should fail.166#if defined(__has_warning) && __has_warning("-Wfree-nonheap-object")167#pragma GCC diagnostic push168#pragma GCC diagnostic ignored "-Wfree-nonheap-object"169#endif170  EXPECT_DEATH(171      free(reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(P) | 1U)), "");172#if defined(__has_warning) && __has_warning("-Wfree-nonheap-object")173#pragma GCC diagnostic pop174#endif175 176  free(P);177  verifyDeallocHookPtr(P);178 179  // Verify a double free causes an abort.180  // Don't simply free(P) since EXPECT_DEATH will do a number of181  // allocations before creating a new process. There is a possibility182  // that the previously freed P is reused, therefore, in the new183  // process doing free(P) is not a double free.184  EXPECT_DEATH(185      {186        // Note: volatile here prevents the calls from being optimized out.187        void *volatile Ptr = malloc(Size);188        free(Ptr);189        free(Ptr);190      },191      "");192 193  P = malloc(0U);194  EXPECT_NE(P, nullptr);195  free(P);196 197  errno = 0;198  EXPECT_EQ(malloc(SIZE_MAX), nullptr);199  EXPECT_EQ(errno, ENOMEM);200}201 202TEST_F(ScudoWrappersCTest, Calloc) {203  void *P = calloc(1U, Size);204  EXPECT_NE(P, nullptr);205  EXPECT_LE(Size, malloc_usable_size(P));206  verifyAllocHookPtr(P);207  verifyAllocHookSize(Size);208  for (size_t I = 0; I < Size; I++)209    EXPECT_EQ((reinterpret_cast<uint8_t *>(P))[I], 0U);210  free(P);211  verifyDeallocHookPtr(P);212 213  P = calloc(1U, 0U);214  EXPECT_NE(P, nullptr);215  free(P);216  P = calloc(0U, 1U);217  EXPECT_NE(P, nullptr);218  free(P);219 220  errno = 0;221  EXPECT_EQ(calloc(SIZE_MAX, 1U), nullptr);222  EXPECT_EQ(errno, ENOMEM);223  errno = 0;224  EXPECT_EQ(calloc(static_cast<size_t>(LONG_MAX) + 1U, 2U), nullptr);225  if (SCUDO_ANDROID)226    EXPECT_EQ(errno, ENOMEM);227  errno = 0;228  EXPECT_EQ(calloc(SIZE_MAX, SIZE_MAX), nullptr);229  EXPECT_EQ(errno, ENOMEM);230}231 232TEST_F(ScudoWrappersCTest, SmallAlign) {233  // Allocating pointers by the powers of 2 from 1 to 0x10000234  // Using powers of 2 due to memalign using powers of 2 and test more sizes235  constexpr size_t MaxSize = 0x10000;236  std::vector<void *> ptrs;237  // Reserving space to prevent further allocation during the test238  ptrs.reserve((scudo::getLeastSignificantSetBitIndex(MaxSize) + 1) *239               (scudo::getLeastSignificantSetBitIndex(MaxSize) + 1) * 3);240  for (size_t Size = 1; Size <= MaxSize; Size <<= 1) {241    for (size_t Align = 1; Align <= MaxSize; Align <<= 1) {242      for (size_t Count = 0; Count < 3; ++Count) {243        void *P = memalign(Align, Size);244        EXPECT_TRUE(reinterpret_cast<uintptr_t>(P) % Align == 0);245        ptrs.push_back(P);246      }247    }248  }249  for (void *ptr : ptrs)250    free(ptr);251}252 253TEST_F(ScudoWrappersCTest, Memalign) {254  void *P;255  for (size_t I = FIRST_32_SECOND_64(2U, 3U); I <= 18U; I++) {256    const size_t Alignment = 1U << I;257 258    P = memalign(Alignment, Size);259    EXPECT_NE(P, nullptr);260    EXPECT_LE(Size, malloc_usable_size(P));261    EXPECT_EQ(reinterpret_cast<uintptr_t>(P) % Alignment, 0U);262    verifyAllocHookPtr(P);263    verifyAllocHookSize(Size);264    free(P);265    verifyDeallocHookPtr(P);266 267    P = nullptr;268    EXPECT_EQ(posix_memalign(&P, Alignment, Size), 0);269    EXPECT_NE(P, nullptr);270    EXPECT_LE(Size, malloc_usable_size(P));271    EXPECT_EQ(reinterpret_cast<uintptr_t>(P) % Alignment, 0U);272    verifyAllocHookPtr(P);273    verifyAllocHookSize(Size);274    free(P);275    verifyDeallocHookPtr(P);276  }277 278  EXPECT_EQ(memalign(4096U, SIZE_MAX), nullptr);279  EXPECT_EQ(posix_memalign(&P, 15U, Size), EINVAL);280  EXPECT_EQ(posix_memalign(&P, 4096U, SIZE_MAX), ENOMEM);281 282  // Android's memalign accepts non power-of-2 alignments, and 0.283  if (SCUDO_ANDROID) {284    for (size_t Alignment = 0U; Alignment <= 128U; Alignment++) {285      P = memalign(Alignment, 1024U);286      EXPECT_NE(P, nullptr);287      verifyAllocHookPtr(P);288      verifyAllocHookSize(Size);289      free(P);290      verifyDeallocHookPtr(P);291    }292  }293}294 295TEST_F(ScudoWrappersCTest, AlignedAlloc) {296  const size_t Alignment = 4096U;297  void *P = aligned_alloc(Alignment, Alignment * 4U);298  EXPECT_NE(P, nullptr);299  EXPECT_LE(Alignment * 4U, malloc_usable_size(P));300  EXPECT_EQ(reinterpret_cast<uintptr_t>(P) % Alignment, 0U);301  verifyAllocHookPtr(P);302  verifyAllocHookSize(Alignment * 4U);303  free(P);304  verifyDeallocHookPtr(P);305 306  errno = 0;307  P = aligned_alloc(Alignment, Size);308  EXPECT_EQ(P, nullptr);309  EXPECT_EQ(errno, EINVAL);310}311 312TEST_F(ScudoWrappersCDeathTest, Realloc) {313  invalidateHookPtrs();314  // realloc(nullptr, N) is malloc(N)315  void *P = realloc(nullptr, Size);316  EXPECT_NE(P, nullptr);317  verifyAllocHookPtr(P);318  verifyAllocHookSize(Size);319  free(P);320  verifyDeallocHookPtr(P);321 322  invalidateHookPtrs();323  P = malloc(Size);324  EXPECT_NE(P, nullptr);325  // realloc(P, 0U) is free(P) and returns nullptr326  EXPECT_EQ(realloc(P, 0U), nullptr);327  verifyDeallocHookPtr(P);328 329  P = malloc(Size);330  EXPECT_NE(P, nullptr);331  EXPECT_LE(Size, malloc_usable_size(P));332  memset(P, 0x42, Size);333 334  invalidateHookPtrs();335  void *OldP = P;336  P = realloc(P, Size * 2U);337  EXPECT_NE(P, nullptr);338  EXPECT_LE(Size * 2U, malloc_usable_size(P));339  for (size_t I = 0; I < Size; I++)340    EXPECT_EQ(0x42, (reinterpret_cast<uint8_t *>(P))[I]);341  if (OldP == P) {342    verifyDeallocHookPtr(OldP);343    verifyAllocHookPtr(OldP);344  } else {345    verifyAllocHookPtr(P);346    verifyAllocHookSize(Size * 2U);347    verifyDeallocHookPtr(OldP);348  }349  verifyReallocHookPtrs(OldP, P, Size * 2U);350 351  invalidateHookPtrs();352  OldP = P;353  P = realloc(P, Size / 2U);354  EXPECT_NE(P, nullptr);355  EXPECT_LE(Size / 2U, malloc_usable_size(P));356  for (size_t I = 0; I < Size / 2U; I++)357    EXPECT_EQ(0x42, (reinterpret_cast<uint8_t *>(P))[I]);358  if (OldP == P) {359    verifyDeallocHookPtr(OldP);360    verifyAllocHookPtr(OldP);361  } else {362    verifyAllocHookPtr(P);363    verifyAllocHookSize(Size / 2U);364  }365  verifyReallocHookPtrs(OldP, P, Size / 2U);366  free(P);367 368  EXPECT_DEATH(P = realloc(P, Size), "");369 370  errno = 0;371  EXPECT_EQ(realloc(nullptr, SIZE_MAX), nullptr);372  EXPECT_EQ(errno, ENOMEM);373  P = malloc(Size);374  EXPECT_NE(P, nullptr);375  errno = 0;376  EXPECT_EQ(realloc(P, SIZE_MAX), nullptr);377  EXPECT_EQ(errno, ENOMEM);378  free(P);379 380  // Android allows realloc of memalign pointers.381  if (SCUDO_ANDROID) {382    const size_t Alignment = 1024U;383    P = memalign(Alignment, Size);384    EXPECT_NE(P, nullptr);385    EXPECT_LE(Size, malloc_usable_size(P));386    EXPECT_EQ(reinterpret_cast<uintptr_t>(P) % Alignment, 0U);387    memset(P, 0x42, Size);388 389    P = realloc(P, Size * 2U);390    EXPECT_NE(P, nullptr);391    EXPECT_LE(Size * 2U, malloc_usable_size(P));392    for (size_t I = 0; I < Size; I++)393      EXPECT_EQ(0x42, (reinterpret_cast<uint8_t *>(P))[I]);394    free(P);395  }396}397 398#if !SCUDO_FUCHSIA399TEST_F(ScudoWrappersCTest, MallOpt) {400  errno = 0;401  EXPECT_EQ(mallopt(-1000, 1), 0);402  // mallopt doesn't set errno.403  EXPECT_EQ(errno, 0);404 405  EXPECT_EQ(mallopt(M_PURGE, 0), 1);406 407  EXPECT_EQ(mallopt(M_DECAY_TIME, 1), 1);408  EXPECT_EQ(mallopt(M_DECAY_TIME, 0), 1);409  EXPECT_EQ(mallopt(M_DECAY_TIME, 1), 1);410  EXPECT_EQ(mallopt(M_DECAY_TIME, 0), 1);411 412  if (SCUDO_ANDROID) {413    EXPECT_EQ(mallopt(M_CACHE_COUNT_MAX, 100), 1);414    EXPECT_EQ(mallopt(M_CACHE_SIZE_MAX, 1024 * 1024 * 2), 1);415    EXPECT_EQ(mallopt(M_TSDS_COUNT_MAX, 10), 1);416  }417}418#endif419 420TEST_F(ScudoWrappersCTest, OtherAlloc) {421#if HAVE_PVALLOC422  const size_t PageSize = static_cast<size_t>(sysconf(_SC_PAGESIZE));423 424  void *P = pvalloc(Size);425  EXPECT_NE(P, nullptr);426  EXPECT_EQ(reinterpret_cast<uintptr_t>(P) & (PageSize - 1), 0U);427  EXPECT_LE(PageSize, malloc_usable_size(P));428  verifyAllocHookPtr(P);429  // Size will be rounded up to PageSize.430  verifyAllocHookSize(PageSize);431  free(P);432  verifyDeallocHookPtr(P);433 434  EXPECT_EQ(pvalloc(SIZE_MAX), nullptr);435 436  P = pvalloc(Size);437  EXPECT_NE(P, nullptr);438  EXPECT_EQ(reinterpret_cast<uintptr_t>(P) & (PageSize - 1), 0U);439  free(P);440#endif441 442#if HAVE_VALLOC443  EXPECT_EQ(valloc(SIZE_MAX), nullptr);444#endif445}446 447template<typename FieldType>448void MallInfoTest() {449  // mallinfo is deprecated.450#pragma clang diagnostic push451#pragma clang diagnostic ignored "-Wdeprecated-declarations"452  const FieldType BypassQuarantineSize = 1024U;453  struct mallinfo MI = mallinfo();454  FieldType Allocated = MI.uordblks;455  void *P = malloc(BypassQuarantineSize);456  EXPECT_NE(P, nullptr);457  MI = mallinfo();458  EXPECT_GE(MI.uordblks, Allocated + BypassQuarantineSize);459  EXPECT_GT(MI.hblkhd, static_cast<FieldType>(0));460  FieldType Free = MI.fordblks;461  free(P);462  MI = mallinfo();463  EXPECT_GE(MI.fordblks, Free + BypassQuarantineSize);464#pragma clang diagnostic pop465}466 467#if !SCUDO_FUCHSIA468TEST_F(ScudoWrappersCTest, MallInfo) {469#if SCUDO_ANDROID470  // Android accidentally set the fields to size_t instead of int.471  MallInfoTest<size_t>();472#else473  MallInfoTest<int>();474#endif475}476#endif477 478#if __GLIBC_PREREQ(2, 33) || SCUDO_ANDROID479TEST_F(ScudoWrappersCTest, MallInfo2) {480  const size_t BypassQuarantineSize = 1024U;481  struct mallinfo2 MI = mallinfo2();482  size_t Allocated = MI.uordblks;483  void *P = malloc(BypassQuarantineSize);484  EXPECT_NE(P, nullptr);485  MI = mallinfo2();486  EXPECT_GE(MI.uordblks, Allocated + BypassQuarantineSize);487  EXPECT_GT(MI.hblkhd, 0U);488  size_t Free = MI.fordblks;489  free(P);490  MI = mallinfo2();491  EXPECT_GE(MI.fordblks, Free + BypassQuarantineSize);492}493#endif494 495static uintptr_t BoundaryP;496static size_t Count;497 498static void callback(uintptr_t Base, UNUSED size_t Size, UNUSED void *Arg) {499  if (scudo::archSupportsMemoryTagging()) {500    Base = scudo::untagPointer(Base);501    BoundaryP = scudo::untagPointer(BoundaryP);502  }503  if (Base == BoundaryP)504    Count++;505}506 507// Verify that a block located on an iteration boundary is not mis-accounted.508// To achieve this, we allocate a chunk for which the backing block will be509// aligned on a page, then run the malloc_iterate on both the pages that the510// block is a boundary for. It must only be seen once by the callback function.511TEST_F(ScudoWrappersCTest, MallocIterateBoundary) {512  const size_t PageSize = static_cast<size_t>(sysconf(_SC_PAGESIZE));513#if SCUDO_ANDROID514  // Android uses a 16 byte alignment for both 32 bit and 64 bit.515  const size_t BlockDelta = 16U;516#else517  const size_t BlockDelta = FIRST_32_SECOND_64(8U, 16U);518#endif519  const size_t SpecialSize = PageSize - BlockDelta;520 521  // We aren't guaranteed that any size class is exactly a page wide. So we need522  // to keep making allocations until we get an allocation that starts exactly523  // on a page boundary. The BlockDelta value is expected to be the number of524  // bytes to subtract from a returned pointer to get to the actual start of525  // the pointer in the size class. In practice, this means BlockDelta should526  // be set to the minimum alignment in bytes for the allocation.527  //528  // With a 16-byte block alignment and 4096-byte page size, each allocation has529  // a probability of (1 - (16/4096)) of failing to meet the alignment530  // requirements, and the probability of failing 65536 times is531  // (1 - (16/4096))^65536 < 10^-112. So if we still haven't succeeded after532  // 65536 tries, give up.533  uintptr_t Block;534  void *P = nullptr;535  for (unsigned I = 0; I != 65536; ++I) {536    void *PrevP = P;537    P = malloc(SpecialSize);538    EXPECT_NE(P, nullptr);539    *reinterpret_cast<void **>(P) = PrevP;540    BoundaryP = reinterpret_cast<uintptr_t>(P);541    Block = BoundaryP - BlockDelta;542    if ((Block & (PageSize - 1)) == 0U)543      break;544  }545  EXPECT_EQ((Block & (PageSize - 1)), 0U);546 547  Count = 0U;548  malloc_disable();549  malloc_iterate(Block - PageSize, PageSize, callback, nullptr);550  malloc_iterate(Block, PageSize, callback, nullptr);551  malloc_enable();552  EXPECT_EQ(Count, 1U);553 554  while (P) {555    void *NextP = *reinterpret_cast<void **>(P);556    free(P);557    P = NextP;558  }559}560 561// Fuchsia doesn't have alarm, fork or malloc_info.562#if !SCUDO_FUCHSIA563TEST_F(ScudoWrappersCDeathTest, MallocDisableDeadlock) {564  // We expect heap operations within a disable/enable scope to deadlock.565  EXPECT_DEATH(566      {567        void *P = malloc(Size);568        EXPECT_NE(P, nullptr);569        free(P);570        malloc_disable();571        alarm(1);572        P = malloc(Size);573        malloc_enable();574      },575      "");576}577 578TEST_F(ScudoWrappersCTest, MallocInfo) {579  // Use volatile so that the allocations don't get optimized away.580  void *volatile P1 = malloc(1234);581  void *volatile P2 = malloc(4321);582 583  char Buffer[16384];584  FILE *F = fmemopen(Buffer, sizeof(Buffer), "w+");585  EXPECT_NE(F, nullptr);586  errno = 0;587  EXPECT_EQ(malloc_info(0, F), 0);588  EXPECT_EQ(errno, 0);589  fclose(F);590  EXPECT_EQ(strncmp(Buffer, "<malloc version=\"scudo-", 23), 0);591  std::string expected;592  expected =593      "<alloc size=\"" + std::to_string(malloc_usable_size(P1)) + "\" count=\"";594  EXPECT_NE(nullptr, strstr(Buffer, expected.c_str()));595  expected =596      "<alloc size=\"" + std::to_string(malloc_usable_size(P2)) + "\" count=\"";597  EXPECT_NE(nullptr, strstr(Buffer, expected.c_str()));598 599  free(P1);600  free(P2);601}602 603TEST_F(ScudoWrappersCDeathTest, Fork) {604  void *P;605  pid_t Pid = fork();606  EXPECT_GE(Pid, 0) << strerror(errno);607  if (Pid == 0) {608    P = malloc(Size);609    EXPECT_NE(P, nullptr);610    memset(P, 0x42, Size);611    free(P);612    _exit(0);613  }614  waitpid(Pid, nullptr, 0);615  P = malloc(Size);616  EXPECT_NE(P, nullptr);617  memset(P, 0x42, Size);618  free(P);619 620  // fork should stall if the allocator has been disabled.621  EXPECT_DEATH(622      {623        malloc_disable();624        alarm(1);625        Pid = fork();626        EXPECT_GE(Pid, 0);627      },628      "");629}630 631static pthread_mutex_t Mutex;632static pthread_cond_t Conditional = PTHREAD_COND_INITIALIZER;633static bool Ready;634 635static void *enableMalloc(UNUSED void *Unused) {636  // Initialize the allocator for this thread.637  void *P = malloc(Size);638  EXPECT_NE(P, nullptr);639  memset(P, 0x42, Size);640  free(P);641 642  // Signal the main thread we are ready.643  pthread_mutex_lock(&Mutex);644  Ready = true;645  pthread_cond_signal(&Conditional);646  pthread_mutex_unlock(&Mutex);647 648  // Wait for the malloc_disable & fork, then enable the allocator again.649  sleep(1);650  malloc_enable();651 652  return nullptr;653}654 655TEST_F(ScudoWrappersCTest, DisableForkEnable) {656  pthread_t ThreadId;657  Ready = false;658  EXPECT_EQ(pthread_create(&ThreadId, nullptr, &enableMalloc, nullptr), 0);659 660  // Wait for the thread to be warmed up.661  pthread_mutex_lock(&Mutex);662  while (!Ready)663    pthread_cond_wait(&Conditional, &Mutex);664  pthread_mutex_unlock(&Mutex);665 666  // Disable the allocator and fork. fork should succeed after malloc_enable.667  malloc_disable();668  pid_t Pid = fork();669  EXPECT_GE(Pid, 0);670  if (Pid == 0) {671    void *P = malloc(Size);672    EXPECT_NE(P, nullptr);673    memset(P, 0x42, Size);674    free(P);675    _exit(0);676  }677  waitpid(Pid, nullptr, 0);678  EXPECT_EQ(pthread_join(ThreadId, 0), 0);679}680 681#endif // SCUDO_FUCHSIA682