Bug Summary

File:out/../deps/v8/src/compiler/graph-reducer.cc
Warning:line 220, column 7
Called C++ object pointer is null

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 graph-reducer.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 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/generate-bytecode-output-root -I /home/maurizio/node-v18.6.0/out/Release/obj/gen -I ../deps/icu-small/source/i18n -I ../deps/icu-small/source/common -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/compiler/graph-reducer.cc
1// Copyright 2014 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/compiler/graph-reducer.h"
6
7#include <functional>
8#include <limits>
9
10#include "src/codegen/tick-counter.h"
11#include "src/compiler/graph.h"
12#include "src/compiler/js-heap-broker.h"
13#include "src/compiler/node-observer.h"
14#include "src/compiler/node-properties.h"
15#include "src/compiler/node.h"
16#include "src/compiler/verifier.h"
17
18namespace v8 {
19namespace internal {
20namespace compiler {
21
22enum class GraphReducer::State : uint8_t {
23 kUnvisited,
24 kRevisit,
25 kOnStack,
26 kVisited
27};
28
29
30void Reducer::Finalize() {}
31
32Reduction Reducer::Reduce(Node* node,
33 ObserveNodeManager* observe_node_manager) {
34 Reduction reduction = Reduce(node);
35 if (V8_UNLIKELY(observe_node_manager && reduction.Changed())(__builtin_expect(!!(observe_node_manager && reduction
.Changed()), 0))
) {
36 observe_node_manager->OnNodeChanged(reducer_name(), node,
37 reduction.replacement());
38 }
39 return reduction;
40}
41
42GraphReducer::GraphReducer(Zone* zone, Graph* graph, TickCounter* tick_counter,
43 JSHeapBroker* broker, Node* dead,
44 ObserveNodeManager* observe_node_manager)
45 : graph_(graph),
46 dead_(dead),
47 state_(graph, 4),
48 reducers_(zone),
49 revisit_(zone),
50 stack_(zone),
51 tick_counter_(tick_counter),
52 broker_(broker),
53 observe_node_manager_(observe_node_manager) {
54 if (dead != nullptr) {
55 NodeProperties::SetType(dead_, Type::None());
56 }
57}
58
59GraphReducer::~GraphReducer() = default;
60
61
62void GraphReducer::AddReducer(Reducer* reducer) {
63 reducers_.push_back(reducer);
64}
65
66
67void GraphReducer::ReduceNode(Node* node) {
68 DCHECK(stack_.empty())((void) 0);
69 DCHECK(revisit_.empty())((void) 0);
70 Push(node);
71 for (;;) {
72 if (!stack_.empty()) {
73 // Process the node on the top of the stack, potentially pushing more or
74 // popping the node off the stack.
75 ReduceTop();
76 } else if (!revisit_.empty()) {
77 // If the stack becomes empty, revisit any nodes in the revisit queue.
78 node = revisit_.front();
79 revisit_.pop();
80 if (state_.Get(node) == State::kRevisit) {
81 // state can change while in queue.
82 Push(node);
83 }
84 } else {
85 // Run all finalizers.
86 for (Reducer* const reducer : reducers_) reducer->Finalize();
87
88 // Check if we have new nodes to revisit.
89 if (revisit_.empty()) break;
90 }
91 }
92 DCHECK(revisit_.empty())((void) 0);
93 DCHECK(stack_.empty())((void) 0);
94}
95
96
97void GraphReducer::ReduceGraph() { ReduceNode(graph()->end()); }
98
99
100Reduction GraphReducer::Reduce(Node* const node) {
101 auto skip = reducers_.end();
102 for (auto i = reducers_.begin(); i != reducers_.end();) {
103 if (i != skip) {
104 tick_counter_->TickAndMaybeEnterSafepoint();
105 Reduction reduction = (*i)->Reduce(node, observe_node_manager_);
106 if (!reduction.Changed()) {
107 // No change from this reducer.
108 } else if (reduction.replacement() == node) {
109 // {replacement} == {node} represents an in-place reduction. Rerun
110 // all the other reducers for this node, as now there may be more
111 // opportunities for reduction.
112 if (FLAG_trace_turbo_reduction) {
113 UnparkedScopeIfNeeded unparked(broker_);
114 // TODO(neis): Disallow racy handle dereference once we stop
115 // supporting --no-local-heaps --no-concurrent-inlining.
116 AllowHandleDereference allow_deref;
117 StdoutStream{} << "- In-place update of #" << *node << " by reducer "
118 << (*i)->reducer_name() << std::endl;
119 }
120 skip = i;
121 i = reducers_.begin();
122 continue;
123 } else {
124 // {node} was replaced by another node.
125 if (FLAG_trace_turbo_reduction) {
126 UnparkedScopeIfNeeded unparked(broker_);
127 // TODO(neis): Disallow racy handle dereference once we stop
128 // supporting --no-local-heaps --no-concurrent-inlining.
129 AllowHandleDereference allow_deref;
130 StdoutStream{} << "- Replacement of #" << *node << " with #"
131 << *(reduction.replacement()) << " by reducer "
132 << (*i)->reducer_name() << std::endl;
133 }
134 return reduction;
135 }
136 }
137 ++i;
138 }
139 if (skip == reducers_.end()) {
140 // No change from any reducer.
141 return Reducer::NoChange();
142 }
143 // At least one reducer did some in-place reduction.
144 return Reducer::Changed(node);
145}
146
147
148void GraphReducer::ReduceTop() {
149 NodeState& entry = stack_.top();
150 Node* node = entry.node;
151 DCHECK_EQ(State::kOnStack, state_.Get(node))((void) 0);
152
153 if (node->IsDead()) return Pop(); // Node was killed while on stack.
154
155 Node::Inputs node_inputs = node->inputs();
156
157 // Recurse on an input if necessary.
158 int start = entry.input_index < node_inputs.count() ? entry.input_index : 0;
159 for (int i = start; i < node_inputs.count(); ++i) {
160 Node* input = node_inputs[i];
161 if (input != node && Recurse(input)) {
162 entry.input_index = i + 1;
163 return;
164 }
165 }
166 for (int i = 0; i < start; ++i) {
167 Node* input = node_inputs[i];
168 if (input != node && Recurse(input)) {
169 entry.input_index = i + 1;
170 return;
171 }
172 }
173
174 // Remember the max node id before reduction.
175 NodeId const max_id = static_cast<NodeId>(graph()->NodeCount() - 1);
176
177 // All inputs should be visited or on stack. Apply reductions to node.
178 Reduction reduction = Reduce(node);
179
180 // If there was no reduction, pop {node} and continue.
181 if (!reduction.Changed()) return Pop();
182
183 // Check if the reduction is an in-place update of the {node}.
184 Node* const replacement = reduction.replacement();
185 if (replacement == node) {
186 for (Node* const user : node->uses()) {
187 DCHECK_IMPLIES(user == node, state_.Get(node) != State::kVisited)((void) 0);
188 Revisit(user);
189 }
190
191 // In-place update of {node}, may need to recurse on an input.
192 node_inputs = node->inputs();
193 for (int i = 0; i < node_inputs.count(); ++i) {
194 Node* input = node_inputs[i];
195 if (input != node && Recurse(input)) {
196 entry.input_index = i + 1;
197 return;
198 }
199 }
200 }
201
202 // After reducing the node, pop it off the stack.
203 Pop();
204
205 // Check if we have a new replacement.
206 if (replacement != node) {
207 Replace(node, replacement, max_id);
208 }
209}
210
211
212void GraphReducer::Replace(Node* node, Node* replacement) {
213 Replace(node, replacement, std::numeric_limits<NodeId>::max());
11
Passing null pointer value via 2nd parameter 'replacement'
12
Calling 'GraphReducer::Replace'
214}
215
216
217void GraphReducer::Replace(Node* node, Node* replacement, NodeId max_id) {
218 if (node == graph()->start()) graph()->SetStart(replacement);
13
Assuming the condition is false
14
Taking false branch
219 if (node == graph()->end()) graph()->SetEnd(replacement);
15
Assuming the condition is false
16
Taking false branch
220 if (replacement->id() <= max_id) {
17
Called C++ object pointer is null
221 // {replacement} is an old node, so unlink {node} and assume that
222 // {replacement} was already reduced and finish.
223 for (Edge edge : node->use_edges()) {
224 Node* const user = edge.from();
225 Verifier::VerifyEdgeInputReplacement(edge, replacement);
226 edge.UpdateTo(replacement);
227 // Don't revisit this node if it refers to itself.
228 if (user != node) Revisit(user);
229 }
230 node->Kill();
231 } else {
232 // Replace all old uses of {node} with {replacement}, but allow new nodes
233 // created by this reduction to use {node}.
234 for (Edge edge : node->use_edges()) {
235 Node* const user = edge.from();
236 if (user->id() <= max_id) {
237 edge.UpdateTo(replacement);
238 // Don't revisit this node if it refers to itself.
239 if (user != node) Revisit(user);
240 }
241 }
242 // Unlink {node} if it's no longer used.
243 if (node->uses().empty()) node->Kill();
244
245 // If there was a replacement, reduce it after popping {node}.
246 Recurse(replacement);
247 }
248}
249
250
251void GraphReducer::ReplaceWithValue(Node* node, Node* value, Node* effect,
252 Node* control) {
253 if (effect == nullptr && node->op()->EffectInputCount() > 0) {
1
Assuming the condition is false
254 effect = NodeProperties::GetEffectInput(node);
255 }
256 if (control == nullptr && node->op()->ControlInputCount() > 0) {
2
Assuming pointer value is null
3
Assuming the condition is false
4
Taking false branch
257 control = NodeProperties::GetControlInput(node);
258 }
259
260 // Requires distinguishing between value, effect and control edges.
261 for (Edge edge : node->use_edges()) {
262 Node* const user = edge.from();
263 DCHECK(!user->IsDead())((void) 0);
264 if (NodeProperties::IsControlEdge(edge)) {
5
Assuming the condition is true
6
Taking true branch
265 if (user->opcode() == IrOpcode::kIfSuccess) {
7
Assuming the condition is true
8
Taking true branch
266 Replace(user, control);
9
Passing null pointer value via 2nd parameter 'replacement'
10
Calling 'GraphReducer::Replace'
267 } else if (user->opcode() == IrOpcode::kIfException) {
268 DCHECK_NOT_NULL(dead_)((void) 0);
269 edge.UpdateTo(dead_);
270 Revisit(user);
271 } else {
272 DCHECK_NOT_NULL(control)((void) 0);
273 edge.UpdateTo(control);
274 Revisit(user);
275 }
276 } else if (NodeProperties::IsEffectEdge(edge)) {
277 DCHECK_NOT_NULL(effect)((void) 0);
278 edge.UpdateTo(effect);
279 Revisit(user);
280 } else {
281 DCHECK_NOT_NULL(value)((void) 0);
282 edge.UpdateTo(value);
283 Revisit(user);
284 }
285 }
286}
287
288
289void GraphReducer::Pop() {
290 Node* node = stack_.top().node;
291 state_.Set(node, State::kVisited);
292 stack_.pop();
293}
294
295
296void GraphReducer::Push(Node* const node) {
297 DCHECK_NE(State::kOnStack, state_.Get(node))((void) 0);
298 state_.Set(node, State::kOnStack);
299 stack_.push({node, 0});
300}
301
302
303bool GraphReducer::Recurse(Node* node) {
304 if (state_.Get(node) > State::kRevisit) return false;
305 Push(node);
306 return true;
307}
308
309
310void GraphReducer::Revisit(Node* node) {
311 if (state_.Get(node) == State::kVisited) {
312 state_.Set(node, State::kRevisit);
313 revisit_.push(node);
314 }
315}
316
317} // namespace compiler
318} // namespace internal
319} // namespace v8