Bug Summary

File:out/../deps/v8/src/execution/v8threads.cc
Warning:line 145, column 3
Value stored to 'from' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name v8threads.cc -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/home/maurizio/node-v18.6.0/out -resource-dir /usr/local/lib/clang/16.0.0 -D _GLIBCXX_USE_CXX11_ABI=1 -D NODE_OPENSSL_CONF_NAME=nodejs_conf -D NODE_OPENSSL_HAS_QUIC -D V8_GYP_BUILD -D V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP=64 -D __STDC_FORMAT_MACROS -D OPENSSL_NO_PINSHARED -D OPENSSL_THREADS -D V8_TARGET_ARCH_X64 -D V8_HAVE_TARGET_OS -D V8_TARGET_OS_LINUX -D V8_EMBEDDER_STRING="-node.8" -D ENABLE_DISASSEMBLER -D V8_PROMISE_INTERNAL_FIELD_COUNT=1 -D V8_SHORT_BUILTIN_CALLS -D OBJECT_PRINT -D V8_INTL_SUPPORT -D V8_ATOMIC_OBJECT_FIELD_WRITES -D V8_ENABLE_LAZY_SOURCE_POSITIONS -D V8_USE_SIPHASH -D V8_SHARED_RO_HEAP -D V8_WIN64_UNWINDING_INFO -D V8_ENABLE_REGEXP_INTERPRETER_THREADED_DISPATCH -D V8_SNAPSHOT_COMPRESSION -D V8_ENABLE_WEBASSEMBLY -D V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS -D V8_ALLOCATION_FOLDING -D V8_ALLOCATION_SITE_TRACKING -D V8_SCRIPTORMODULE_LEGACY_LIFETIME -D V8_ADVANCED_BIGINT_ALGORITHMS -D ICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_STATIC -D UCONFIG_NO_SERVICE=1 -D U_ENABLE_DYLOAD=0 -D U_STATIC_IMPLEMENTATION=1 -D U_HAVE_STD_STRING=1 -D UCONFIG_NO_BREAK_ITERATION=0 -I ../deps/v8 -I ../deps/v8/include -I /home/maurizio/node-v18.6.0/out/Release/obj/gen/inspector-generated-output-root -I ../deps/v8/third_party/inspector_protocol -I /home/maurizio/node-v18.6.0/out/Release/obj/gen -I /home/maurizio/node-v18.6.0/out/Release/obj/gen/generate-bytecode-output-root -I ../deps/icu-small/source/i18n -I ../deps/icu-small/source/common -I ../deps/v8/third_party/zlib -I ../deps/v8/third_party/zlib/google -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8 -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/x86_64-redhat-linux -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/backward -internal-isystem /usr/local/lib/clang/16.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-unused-parameter -Wno-return-type -std=gnu++17 -fdeprecated-macro -fdebug-compilation-dir=/home/maurizio/node-v18.6.0/out -ferror-limit 19 -fno-rtti -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-08-22-142216-507842-1 -x c++ ../deps/v8/src/execution/v8threads.cc
1// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/execution/v8threads.h"
6
7#include "include/v8-locker.h"
8#include "src/api/api.h"
9#include "src/debug/debug.h"
10#include "src/execution/execution.h"
11#include "src/execution/isolate-inl.h"
12#include "src/execution/stack-guard.h"
13#include "src/init/bootstrapper.h"
14#include "src/objects/visitors.h"
15#include "src/regexp/regexp-stack.h"
16
17namespace v8 {
18
19namespace {
20
21// Track whether this V8 instance has ever called v8::Locker. This allows the
22// API code to verify that the lock is always held when V8 is being entered.
23base::AtomicWord g_locker_was_ever_used_ = 0;
24
25} // namespace
26
27// Once the Locker is initialized, the current thread will be guaranteed to have
28// the lock for a given isolate.
29void Locker::Initialize(v8::Isolate* isolate) {
30 DCHECK_NOT_NULL(isolate)((void) 0);
31 has_lock_ = false;
32 top_level_ = true;
33 isolate_ = reinterpret_cast<i::Isolate*>(isolate);
34
35 // Record that the Locker has been used at least once.
36 base::Relaxed_Store(&g_locker_was_ever_used_, 1);
37 isolate_->set_was_locker_ever_used();
38
39 // Get the big lock if necessary.
40 if (!isolate_->thread_manager()->IsLockedByCurrentThread()) {
41 isolate_->thread_manager()->Lock();
42 has_lock_ = true;
43
44 // This may be a locker within an unlocker in which case we have to
45 // get the saved state for this thread and restore it.
46 if (isolate_->thread_manager()->RestoreThread()) {
47 top_level_ = false;
48 }
49 }
50 DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread())((void) 0);
51}
52
53bool Locker::IsLocked(v8::Isolate* isolate) {
54 DCHECK_NOT_NULL(isolate)((void) 0);
55 i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
56 return internal_isolate->thread_manager()->IsLockedByCurrentThread();
57}
58
59// static
60bool Locker::IsActive() { return WasEverUsed(); }
61
62// static
63bool Locker::WasEverUsed() {
64 return base::Relaxed_Load(&g_locker_was_ever_used_) != 0;
65}
66
67Locker::~Locker() {
68 DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread())((void) 0);
69 if (has_lock_) {
70 if (top_level_) {
71 isolate_->thread_manager()->FreeThreadResources();
72 } else {
73 isolate_->thread_manager()->ArchiveThread();
74 }
75 isolate_->thread_manager()->Unlock();
76 }
77}
78
79void Unlocker::Initialize(v8::Isolate* isolate) {
80 DCHECK_NOT_NULL(isolate)((void) 0);
81 isolate_ = reinterpret_cast<i::Isolate*>(isolate);
82 DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread())((void) 0);
83 isolate_->thread_manager()->ArchiveThread();
84 isolate_->thread_manager()->Unlock();
85}
86
87Unlocker::~Unlocker() {
88 DCHECK(!isolate_->thread_manager()->IsLockedByCurrentThread())((void) 0);
89 isolate_->thread_manager()->Lock();
90 isolate_->thread_manager()->RestoreThread();
91}
92
93namespace internal {
94
95void ThreadManager::InitThread(const ExecutionAccess& lock) {
96 isolate_->InitializeThreadLocal();
97 isolate_->stack_guard()->InitThread(lock);
98 isolate_->debug()->InitThread(lock);
99}
100
101bool ThreadManager::RestoreThread() {
102 DCHECK(IsLockedByCurrentThread())((void) 0);
103 // First check whether the current thread has been 'lazily archived', i.e.
104 // not archived at all. If that is the case we put the state storage we
105 // had prepared back in the free list, since we didn't need it after all.
106 if (lazily_archived_thread_ == ThreadId::Current()) {
107 lazily_archived_thread_ = ThreadId::Invalid();
108 Isolate::PerIsolateThreadData* per_thread =
109 isolate_->FindPerThreadDataForThisThread();
110 DCHECK_NOT_NULL(per_thread)((void) 0);
111 DCHECK(per_thread->thread_state() == lazily_archived_thread_state_)((void) 0);
112 lazily_archived_thread_state_->set_id(ThreadId::Invalid());
113 lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST);
114 lazily_archived_thread_state_ = nullptr;
115 per_thread->set_thread_state(nullptr);
116 return true;
117 }
118
119 // Make sure that the preemption thread cannot modify the thread state while
120 // it is being archived or restored.
121 ExecutionAccess access(isolate_);
122
123 // If there is another thread that was lazily archived then we have to really
124 // archive it now.
125 if (lazily_archived_thread_.IsValid()) {
126 EagerlyArchiveThread();
127 }
128 Isolate::PerIsolateThreadData* per_thread =
129 isolate_->FindPerThreadDataForThisThread();
130 if (per_thread == nullptr || per_thread->thread_state() == nullptr) {
131 // This is a new thread.
132 InitThread(access);
133 return false;
134 }
135 ThreadState* state = per_thread->thread_state();
136 char* from = state->data();
137 from = isolate_->handle_scope_implementer()->RestoreThread(from);
138 from = isolate_->RestoreThread(from);
139 from = Relocatable::RestoreState(isolate_, from);
140 // Stack guard should be restored before Debug, etc. since Debug etc. might
141 // depend on a correct stack guard.
142 from = isolate_->stack_guard()->RestoreStackGuard(from);
143 from = isolate_->debug()->RestoreDebug(from);
144 from = isolate_->regexp_stack()->RestoreStack(from);
145 from = isolate_->bootstrapper()->RestoreState(from);
Value stored to 'from' is never read
146 per_thread->set_thread_state(nullptr);
147 state->set_id(ThreadId::Invalid());
148 state->Unlink();
149 state->LinkInto(ThreadState::FREE_LIST);
150 return true;
151}
152
153void ThreadManager::Lock() {
154 mutex_.Lock();
155 mutex_owner_.store(ThreadId::Current(), std::memory_order_relaxed);
156 DCHECK(IsLockedByCurrentThread())((void) 0);
157}
158
159void ThreadManager::Unlock() {
160 mutex_owner_.store(ThreadId::Invalid(), std::memory_order_relaxed);
161 mutex_.Unlock();
162}
163
164static int ArchiveSpacePerThread() {
165 return HandleScopeImplementer::ArchiveSpacePerThread() +
166 Isolate::ArchiveSpacePerThread() + Debug::ArchiveSpacePerThread() +
167 StackGuard::ArchiveSpacePerThread() +
168 RegExpStack::ArchiveSpacePerThread() +
169 Bootstrapper::ArchiveSpacePerThread() +
170 Relocatable::ArchiveSpacePerThread();
171}
172
173ThreadState::ThreadState(ThreadManager* thread_manager)
174 : id_(ThreadId::Invalid()),
175 data_(nullptr),
176 next_(this),
177 previous_(this),
178 thread_manager_(thread_manager) {}
179
180ThreadState::~ThreadState() { DeleteArray<char>(data_); }
181
182void ThreadState::AllocateSpace() {
183 data_ = NewArray<char>(ArchiveSpacePerThread());
184}
185
186void ThreadState::Unlink() {
187 next_->previous_ = previous_;
188 previous_->next_ = next_;
189}
190
191void ThreadState::LinkInto(List list) {
192 ThreadState* flying_anchor = list == FREE_LIST
193 ? thread_manager_->free_anchor_
194 : thread_manager_->in_use_anchor_;
195 next_ = flying_anchor->next_;
196 previous_ = flying_anchor;
197 flying_anchor->next_ = this;
198 next_->previous_ = this;
199}
200
201ThreadState* ThreadManager::GetFreeThreadState() {
202 ThreadState* gotten = free_anchor_->next_;
203 if (gotten == free_anchor_) {
204 ThreadState* new_thread_state = new ThreadState(this);
205 new_thread_state->AllocateSpace();
206 return new_thread_state;
207 }
208 return gotten;
209}
210
211// Gets the first in the list of archived threads.
212ThreadState* ThreadManager::FirstThreadStateInUse() {
213 return in_use_anchor_->Next();
214}
215
216ThreadState* ThreadState::Next() {
217 if (next_ == thread_manager_->in_use_anchor_) return nullptr;
218 return next_;
219}
220
221// Thread ids must start with 1, because in TLS having thread id 0 can't
222// be distinguished from not having a thread id at all (since NULL is
223// defined as 0.)
224ThreadManager::ThreadManager(Isolate* isolate)
225 : mutex_owner_(ThreadId::Invalid()),
226 lazily_archived_thread_(ThreadId::Invalid()),
227 lazily_archived_thread_state_(nullptr),
228 free_anchor_(nullptr),
229 in_use_anchor_(nullptr),
230 isolate_(isolate) {
231 free_anchor_ = new ThreadState(this);
232 in_use_anchor_ = new ThreadState(this);
233}
234
235ThreadManager::~ThreadManager() {
236 DeleteThreadStateList(free_anchor_);
237 DeleteThreadStateList(in_use_anchor_);
238}
239
240void ThreadManager::DeleteThreadStateList(ThreadState* anchor) {
241 // The list starts and ends with the anchor.
242 for (ThreadState* current = anchor->next_; current != anchor;) {
243 ThreadState* next = current->next_;
244 delete current;
245 current = next;
246 }
247 delete anchor;
248}
249
250void ThreadManager::ArchiveThread() {
251 DCHECK_EQ(lazily_archived_thread_, ThreadId::Invalid())((void) 0);
252 DCHECK(!IsArchived())((void) 0);
253 DCHECK(IsLockedByCurrentThread())((void) 0);
254 ThreadState* state = GetFreeThreadState();
255 state->Unlink();
256 Isolate::PerIsolateThreadData* per_thread =
257 isolate_->FindOrAllocatePerThreadDataForThisThread();
258 per_thread->set_thread_state(state);
259 lazily_archived_thread_ = ThreadId::Current();
260 lazily_archived_thread_state_ = state;
261 DCHECK_EQ(state->id(), ThreadId::Invalid())((void) 0);
262 state->set_id(CurrentId());
263 DCHECK_NE(state->id(), ThreadId::Invalid())((void) 0);
264}
265
266void ThreadManager::EagerlyArchiveThread() {
267 DCHECK(IsLockedByCurrentThread())((void) 0);
268 ThreadState* state = lazily_archived_thread_state_;
269 state->LinkInto(ThreadState::IN_USE_LIST);
270 char* to = state->data();
271 // Ensure that data containing GC roots are archived first, and handle them
272 // in ThreadManager::Iterate(RootVisitor*).
273 to = isolate_->handle_scope_implementer()->ArchiveThread(to);
274 to = isolate_->ArchiveThread(to);
275 to = Relocatable::ArchiveState(isolate_, to);
276 to = isolate_->stack_guard()->ArchiveStackGuard(to);
277 to = isolate_->debug()->ArchiveDebug(to);
278 to = isolate_->regexp_stack()->ArchiveStack(to);
279 to = isolate_->bootstrapper()->ArchiveState(to);
280 lazily_archived_thread_ = ThreadId::Invalid();
281 lazily_archived_thread_state_ = nullptr;
282}
283
284void ThreadManager::FreeThreadResources() {
285 DCHECK(!isolate_->has_pending_exception())((void) 0);
286 DCHECK(!isolate_->external_caught_exception())((void) 0);
287 DCHECK_NULL(isolate_->try_catch_handler())((void) 0);
288 isolate_->handle_scope_implementer()->FreeThreadResources();
289 isolate_->FreeThreadResources();
290 isolate_->debug()->FreeThreadResources();
291 isolate_->stack_guard()->FreeThreadResources();
292 isolate_->regexp_stack()->FreeThreadResources();
293 isolate_->bootstrapper()->FreeThreadResources();
294}
295
296bool ThreadManager::IsArchived() {
297 Isolate::PerIsolateThreadData* data =
298 isolate_->FindPerThreadDataForThisThread();
299 return data != nullptr && data->thread_state() != nullptr;
300}
301
302void ThreadManager::Iterate(RootVisitor* v) {
303 // Expecting no threads during serialization/deserialization
304 for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
305 state = state->Next()) {
306 char* data = state->data();
307 data = HandleScopeImplementer::Iterate(v, data);
308 data = isolate_->Iterate(v, data);
309 data = Relocatable::Iterate(v, data);
310 data = StackGuard::Iterate(v, data);
311 data = Debug::Iterate(v, data);
312 }
313}
314
315void ThreadManager::IterateArchivedThreads(ThreadVisitor* v) {
316 for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
317 state = state->Next()) {
318 char* data = state->data();
319 data += HandleScopeImplementer::ArchiveSpacePerThread();
320 isolate_->IterateThread(v, data);
321 }
322}
323
324ThreadId ThreadManager::CurrentId() { return ThreadId::Current(); }
325
326} // namespace internal
327} // namespace v8