Bug Summary

File:root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp
Warning:line 69, column 13
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name DeferGlobalInitializers.cpp -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 -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +sse2 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/angle/targets/translator -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/angle/targets/translator -resource-dir /usr/lib/llvm-21/lib/clang/21 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D _GLIBCXX_ASSERTIONS -D DEBUG=1 -D ANGLE_PLATFORM_EXPORT= -D __NDK_FPABI__= -D ANGLE_SKIP_DXGI_1_2_CHECK -D ANGLE_ENABLE_KEYEDMUTEX -D ANGLE_TRANSLATOR_ESSL_ONLY -D ANGLE_DISABLE_POOL_ALLOC -D ANGLE_ENABLE_APPLE_WORKAROUNDS -D ANGLE_ENABLE_ESSL -D ANGLE_ENABLE_GLSL -D ANGLE_ENABLE_HLSL -D ANGLE_ENABLE_SHARE_CONTEXT_LOCK=1 -D ANGLE_VMA_VERSION=2003000 -D CR_CLANG_REVISION="llvmorg-16-init-6578-g0d30e92f-2" -D DYNAMIC_ANNOTATIONS_ENABLED=0 -D NOMINMAX -D UNICODE -D WINVER=0x0A00 -D _ATL_NO_OPENGL -D _CRT_NONSTDC_NO_WARNINGS -D _CRT_RAND_S -D _CRT_SECURE_NO_DEPRECATE -D _HAS_EXCEPTIONS=0 -D _SCL_SECURE_NO_DEPRECATE -D _SECURE_ATL -D _UNICODE -D _WINSOCK_DEPRECATED_NO_WARNINGS -I /root/firefox-clang/gfx/angle/targets/translator -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/angle/targets/translator -I /root/firefox-clang/gfx/angle/checkout/include -I /root/firefox-clang/gfx/angle/checkout/src -I /root/firefox-clang/gfx/angle/checkout/src/common/third_party/base -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-final-dtor-non-final-class -Wno-implicit-const-int-float-conversion -Wno-range-loop-construct -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2025-06-27-100320-3286336-1 -x c++ /root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp
1//
2// Copyright 2016 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6// DeferGlobalInitializers is an AST traverser that moves global initializers into a separate
7// function that is called in the beginning of main(). This enables initialization of globals with
8// uniforms or non-constant globals, as allowed by the WebGL spec. Some initializers referencing
9// non-constants may need to be unfolded into if statements in HLSL - this kind of steps should be
10// done after DeferGlobalInitializers is run. Note that it's important that the function definition
11// is at the end of the shader, as some globals may be declared after main().
12//
13// It can also initialize all uninitialized globals.
14//
15
16#include "compiler/translator/tree_ops/DeferGlobalInitializers.h"
17
18#include <vector>
19
20#include "compiler/translator/Compiler.h"
21#include "compiler/translator/IntermNode.h"
22#include "compiler/translator/StaticType.h"
23#include "compiler/translator/SymbolTable.h"
24#include "compiler/translator/tree_ops/InitializeVariables.h"
25#include "compiler/translator/tree_util/FindMain.h"
26#include "compiler/translator/tree_util/IntermNode_util.h"
27#include "compiler/translator/tree_util/ReplaceVariable.h"
28
29namespace sh
30{
31
32namespace
33{
34
35constexpr const ImmutableString kInitGlobalsString("initGlobals");
36
37void GetDeferredInitializers(TIntermDeclaration *declaration,
38 bool initializeUninitializedGlobals,
39 bool canUseLoopsToInitialize,
40 bool highPrecisionSupported,
41 bool forceDeferGlobalInitializers,
42 TIntermSequence *deferredInitializersOut,
43 std::vector<const TVariable *> *variablesToReplaceOut,
44 TSymbolTable *symbolTable)
45{
46 // SeparateDeclarations should have already been run.
47 ASSERT(declaration->getSequence()->size() == 1)(declaration->getSequence()->size() == 1 ? static_cast<
void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(
::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv::
LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp"
, __FUNCTION__, 47, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp"
<< ":" << 47 << "): " << "declaration->getSequence()->size() == 1"
))
;
4
Assuming the condition is true
5
'?' condition is true
48
49 TIntermNode *declarator = declaration->getSequence()->back();
50 TIntermBinary *init = declarator->getAsBinaryNode();
51 if (init)
6
Assuming 'init' is non-null
7
Taking true branch
52 {
53 TIntermSymbol *symbolNode = init->getLeft()->getAsSymbolNode();
8
'symbolNode' initialized here
54 ASSERT(symbolNode)(symbolNode ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage
(::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv
::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp"
, __FUNCTION__, 54, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp"
<< ":" << 54 << "): " << "symbolNode"
))
;
9
Assuming 'symbolNode' is null
10
'?' condition is false
11
Assuming the condition is true
12
'?' condition is true
55 TIntermTyped *expression = init->getRight();
56
57 if (expression->getQualifier() != EvqConst || !expression->hasConstantValue() ||
13
Assuming the condition is true
58 forceDeferGlobalInitializers)
59 {
60 // For variables which are not constant, defer their real initialization until
61 // after we initialize uniforms.
62 // Deferral is done also in any cases where the variable can not be converted to a
63 // constant union, since otherwise there's a chance that HLSL output will generate extra
64 // statements from the initializer expression.
65
66 // Change const global to a regular global if its initialization is deferred.
67 // This can happen if ANGLE has not been able to fold the constant expression used
68 // as an initializer.
69 ASSERT(symbolNode->getQualifier() == EvqConst ||(symbolNode->getQualifier() == EvqConst || symbolNode->
getQualifier() == EvqGlobal ? static_cast<void>(0) : (!
((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL)
)) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify
() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp"
, __FUNCTION__, 70, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp"
<< ":" << 70 << "): " << "symbolNode->getQualifier() == EvqConst || symbolNode->getQualifier() == EvqGlobal"
))
14
Called C++ object pointer is null
70 symbolNode->getQualifier() == EvqGlobal)(symbolNode->getQualifier() == EvqConst || symbolNode->
getQualifier() == EvqGlobal ? static_cast<void>(0) : (!
((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL)
)) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify
() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp"
, __FUNCTION__, 70, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp"
<< ":" << 70 << "): " << "symbolNode->getQualifier() == EvqConst || symbolNode->getQualifier() == EvqGlobal"
))
;
71 if (symbolNode->getQualifier() == EvqConst)
72 {
73 variablesToReplaceOut->push_back(&symbolNode->variable());
74 }
75
76 TIntermBinary *deferredInit =
77 new TIntermBinary(EOpAssign, symbolNode->deepCopy(), init->getRight());
78 deferredInitializersOut->push_back(deferredInit);
79
80 // Remove the initializer from the global scope and just declare the global instead.
81 declaration->replaceChildNode(init, symbolNode);
82 }
83 }
84 else if (initializeUninitializedGlobals)
85 {
86 TIntermSymbol *symbolNode = declarator->getAsSymbolNode();
87 ASSERT(symbolNode)(symbolNode ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage
(::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv
::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp"
, __FUNCTION__, 87, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp"
<< ":" << 87 << "): " << "symbolNode"
))
;
88
89 // Ignore ANGLE internal variables and nameless declarations.
90 if (symbolNode->variable().symbolType() == SymbolType::AngleInternal ||
91 symbolNode->variable().symbolType() == SymbolType::Empty)
92 return;
93
94 if (symbolNode->getQualifier() == EvqGlobal)
95 {
96 TIntermSequence initCode;
97 CreateInitCode(symbolNode, canUseLoopsToInitialize, highPrecisionSupported, &initCode,
98 symbolTable);
99 deferredInitializersOut->insert(deferredInitializersOut->end(), initCode.begin(),
100 initCode.end());
101 }
102 }
103}
104
105void InsertInitCallToMain(TIntermBlock *root,
106 TIntermSequence *deferredInitializers,
107 TSymbolTable *symbolTable)
108{
109 TIntermBlock *initGlobalsBlock = new TIntermBlock();
110 initGlobalsBlock->getSequence()->swap(*deferredInitializers);
111
112 TFunction *initGlobalsFunction =
113 new TFunction(symbolTable, kInitGlobalsString, SymbolType::AngleInternal,
114 StaticType::GetBasic<EbtVoid, EbpUndefined>(), false);
115
116 TIntermFunctionPrototype *initGlobalsFunctionPrototype =
117 CreateInternalFunctionPrototypeNode(*initGlobalsFunction);
118 root->getSequence()->insert(root->getSequence()->begin(), initGlobalsFunctionPrototype);
119 TIntermFunctionDefinition *initGlobalsFunctionDefinition =
120 CreateInternalFunctionDefinitionNode(*initGlobalsFunction, initGlobalsBlock);
121 root->appendStatement(initGlobalsFunctionDefinition);
122
123 TIntermSequence emptySequence;
124 TIntermAggregate *initGlobalsCall =
125 TIntermAggregate::CreateFunctionCall(*initGlobalsFunction, &emptySequence);
126
127 TIntermBlock *mainBody = FindMainBody(root);
128 mainBody->getSequence()->insert(mainBody->getSequence()->begin(), initGlobalsCall);
129}
130
131} // namespace
132
133bool DeferGlobalInitializers(TCompiler *compiler,
134 TIntermBlock *root,
135 bool initializeUninitializedGlobals,
136 bool canUseLoopsToInitialize,
137 bool highPrecisionSupported,
138 bool forceDeferGlobalInitializers,
139 TSymbolTable *symbolTable)
140{
141 TIntermSequence deferredInitializers;
142 std::vector<const TVariable *> variablesToReplace;
143
144 // Loop over all global statements and process the declarations. This is simpler than using a
145 // traverser.
146 for (TIntermNode *statement : *root->getSequence())
147 {
148 TIntermDeclaration *declaration = statement->getAsDeclarationNode();
149 if (declaration)
1
Assuming 'declaration' is non-null
2
Taking true branch
150 {
151 GetDeferredInitializers(declaration, initializeUninitializedGlobals,
3
Calling 'GetDeferredInitializers'
152 canUseLoopsToInitialize, highPrecisionSupported,
153 forceDeferGlobalInitializers, &deferredInitializers,
154 &variablesToReplace, symbolTable);
155 }
156 }
157
158 // Add the function with initialization and the call to that.
159 if (!deferredInitializers.empty())
160 {
161 InsertInitCallToMain(root, &deferredInitializers, symbolTable);
162 }
163
164 // Replace constant variables with non-constant global variables.
165 for (const TVariable *var : variablesToReplace)
166 {
167 TType *replacementType = new TType(var->getType());
168 replacementType->setQualifier(EvqGlobal);
169 TVariable *replacement =
170 new TVariable(symbolTable, var->name(), replacementType, var->symbolType());
171 if (!ReplaceVariable(compiler, root, var, replacement))
172 {
173 return false;
174 }
175 }
176
177 return true;
178}
179
180} // namespace sh