Utility.cpp (5358B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* Various JS utility functions. */ 8 9 #include "js/Utility.h" 10 11 #include "mozilla/Assertions.h" 12 #include "mozilla/Atomics.h" 13 #include "mozilla/Maybe.h" 14 #include "mozilla/ThreadLocal.h" 15 16 #include <stdio.h> 17 18 #include "jstypes.h" 19 20 #include "util/Poison.h" 21 #include "vm/HelperThreads.h" 22 #include "vm/JSContext.h" 23 24 using namespace js; 25 26 using mozilla::Maybe; 27 28 #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) 29 /* For OOM testing functionality in Utility.h. */ 30 namespace js { 31 32 mozilla::Atomic<AutoEnterOOMUnsafeRegion*> AutoEnterOOMUnsafeRegion::owner_; 33 34 namespace oom { 35 36 JS_PUBLIC_DATA FailureSimulator simulator; 37 static MOZ_THREAD_LOCAL(uint32_t) threadType; 38 39 bool InitThreadType() { return threadType.init(); } 40 41 void SetThreadType(ThreadType type) { threadType.set(type); } 42 43 uint32_t GetThreadType(void) { return threadType.get(); } 44 45 static inline bool IsHelperThreadType(uint32_t thread) { 46 return thread != THREAD_TYPE_NONE && thread != THREAD_TYPE_MAIN; 47 } 48 49 void FailureSimulator::simulateFailureAfter(Kind kind, uint64_t checks, 50 uint32_t thread, bool always) { 51 Maybe<AutoLockHelperThreadState> lock; 52 if (IsHelperThreadType(targetThread_) || IsHelperThreadType(thread)) { 53 lock.emplace(); 54 WaitForAllHelperThreads(lock.ref()); 55 } 56 57 MOZ_ASSERT(counter_ + checks > counter_); 58 MOZ_ASSERT(thread > js::THREAD_TYPE_NONE && thread < js::THREAD_TYPE_MAX); 59 targetThread_ = thread; 60 maxChecks_ = counter_ + checks; 61 failAlways_ = always; 62 kind_ = kind; 63 } 64 65 void FailureSimulator::reset() { 66 Maybe<AutoLockHelperThreadState> lock; 67 if (IsHelperThreadType(targetThread_)) { 68 lock.emplace(); 69 WaitForAllHelperThreads(lock.ref()); 70 } 71 72 targetThread_ = THREAD_TYPE_NONE; 73 maxChecks_ = UINT64_MAX; 74 failAlways_ = false; 75 kind_ = Kind::Nothing; 76 } 77 78 } // namespace oom 79 } // namespace js 80 #endif // defined(DEBUG) || defined(JS_OOM_BREAKPOINT) 81 82 #if defined(FUZZING) 83 namespace js { 84 namespace oom { 85 JS_PUBLIC_DATA size_t largeAllocLimit = 0; 86 void InitLargeAllocLimit() { 87 char* limitStr = getenv("MOZ_FUZZ_LARGE_ALLOC_LIMIT"); 88 if (limitStr) { 89 largeAllocLimit = atoll(limitStr); 90 } 91 } 92 } // namespace oom 93 } // namespace js 94 #endif 95 96 JS_PUBLIC_DATA arena_id_t js::MallocArena; 97 JS_PUBLIC_DATA arena_id_t js::BackgroundMallocArena; 98 JS_PUBLIC_DATA arena_id_t js::ArrayBufferContentsArena; 99 JS_PUBLIC_DATA arena_id_t js::StringBufferArena; 100 101 void js::InitMallocAllocator() { 102 arena_params_t mallocArenaParams; 103 mallocArenaParams.mMaxDirtyIncreaseOverride = 5; 104 mallocArenaParams.mLabel = "JS malloc"; 105 MallocArena = moz_create_arena_with_params(&mallocArenaParams); 106 BackgroundMallocArena = moz_create_arena_with_params(&mallocArenaParams); 107 108 arena_params_t params; 109 params.mMaxDirtyIncreaseOverride = 5; 110 params.mFlags |= ARENA_FLAG_RANDOMIZE_SMALL_ENABLED; 111 params.mLabel = "Array buffer contents"; 112 ArrayBufferContentsArena = moz_create_arena_with_params(¶ms); 113 params.mLabel = "String buffer contents"; 114 StringBufferArena = moz_create_arena_with_params(¶ms); 115 } 116 117 void js::ShutDownMallocAllocator() { 118 // Until Bug 1364359 is fixed it is unsafe to call moz_dispose_arena. 119 // moz_dispose_arena(MallocArena); 120 // moz_dispose_arena(ArrayBufferContentsArena); 121 } 122 123 extern void js::AssertJSStringBufferInCorrectArena(const void* ptr) { 124 // `jemalloc_ptr_info()` only exists if MOZ_MEMORY is defined, and it only 125 // returns an arenaId if MOZ_DEBUG is defined. Otherwise, this function is 126 // a no-op. 127 #if defined(MOZ_MEMORY) && defined(MOZ_DEBUG) 128 if (ptr && !TlsContext.get()->nursery().isInside(ptr)) { 129 jemalloc_ptr_info_t ptrInfo{}; 130 jemalloc_ptr_info(ptr, &ptrInfo); 131 MOZ_ASSERT(ptrInfo.tag != TagUnknown); 132 MOZ_ASSERT(ptrInfo.arenaId == js::StringBufferArena); 133 } 134 #endif 135 } 136 137 JS_PUBLIC_API void JS_Assert(const char* s, const char* file, int ln) { 138 MOZ_ReportAssertionFailure(s, file, ln); 139 MOZ_CRASH(); 140 } 141 142 #ifdef __linux__ 143 144 # include <malloc.h> 145 # include <stdlib.h> 146 147 namespace js { 148 149 // This function calls all the vanilla heap allocation functions. It is never 150 // called, and exists purely to help config/check_vanilla_allocations.py. See 151 // that script for more details. 152 extern MOZ_COLD void AllTheNonBasicVanillaNewAllocations() { 153 // posix_memalign and aligned_alloc aren't available on all Linux 154 // configurations. 155 // valloc was deprecated in Android 5.0 156 // char* q; 157 // posix_memalign((void**)&q, 16, 16); 158 159 intptr_t p = intptr_t(malloc(16)) + intptr_t(calloc(1, 16)) + 160 intptr_t(realloc(nullptr, 16)) + intptr_t(new char) + 161 intptr_t(new char) + intptr_t(new char) + 162 intptr_t(new char[16]) + intptr_t(memalign(16, 16)) + 163 // intptr_t(q) + 164 // intptr_t(aligned_alloc(16, 16)) + 165 // intptr_t(valloc(4096)) + 166 intptr_t(strdup("dummy")); 167 168 printf("%u\n", uint32_t(p)); // make sure |p| is not optimized away 169 170 free((int*)p); // this would crash if ever actually called 171 172 MOZ_CRASH(); 173 } 174 175 } // namespace js 176 177 #endif // __linux__