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