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(&params);
114   StringBufferArena = moz_create_arena_with_params(&params);
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