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 "util/Windows.h"
22 #include "vm/HelperThreads.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
InitThreadType()39 bool InitThreadType() { return threadType.init(); }
40
SetThreadType(ThreadType type)41 void SetThreadType(ThreadType type) { threadType.set(type); }
42
GetThreadType(void)43 uint32_t GetThreadType(void) { return threadType.get(); }
44
IsHelperThreadType(uint32_t thread)45 static inline bool IsHelperThreadType(uint32_t thread) {
46 return thread != THREAD_TYPE_NONE && thread != THREAD_TYPE_MAIN;
47 }
48
simulateFailureAfter(Kind kind,uint64_t checks,uint32_t thread,bool always)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
reset()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;
InitLargeAllocLimit()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 #if defined(JS_GC_ALLOW_EXTRA_POISONING)
97 # if defined(DEBUG)
98 bool js::gExtraPoisoningEnabled = true;
99 # else
100 bool js::gExtraPoisoningEnabled = false;
101 # endif
102 #endif
103
104 JS_PUBLIC_DATA arena_id_t js::MallocArena;
105 JS_PUBLIC_DATA arena_id_t js::ArrayBufferContentsArena;
106 JS_PUBLIC_DATA arena_id_t js::StringBufferArena;
107
InitMallocAllocator()108 void js::InitMallocAllocator() {
109 MallocArena = moz_create_arena();
110
111 arena_params_t params;
112 params.mFlags |= ARENA_FLAG_RANDOMIZE_SMALL_ENABLED;
113 ArrayBufferContentsArena = moz_create_arena_with_params(¶ms);
114 StringBufferArena = moz_create_arena_with_params(¶ms);
115 }
116
ShutDownMallocAllocator()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
AssertJSStringBufferInCorrectArena(const void * ptr)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) {
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
JS_Assert(const char * s,const char * file,int ln)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.
AllTheNonBasicVanillaNewAllocations()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__
178