Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/js/ProfilingFrameIterator.h
Warning:line 165, column 10
Excessive padding in 'struct JS::ProfilingFrameIterator::Frame' (8 padding bytes, where 0 is optimal). Optimal fields order: stackAddress, , activation, endStackAddress, label, interpreterScript, realmID, kind, sourceId, line, column, consider reordering the fields or adding explicit padding members

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O3 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_js_src_builtin4.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 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/js/src/builtin -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/js/src/builtin -resource-dir /usr/lib/llvm-23/lib/clang/23 -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 -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D WASM_SUPPORTS_HUGE_MEMORY -D JS_CACHEIR_SPEW -D JS_STRUCTURED_SPEW -D JS_HAS_CTYPES -D FFI_BUILDING -D EXPORT_JS_API -D MOZ_HAS_MOZGLUE -D MOZ_SUPPORT_LEAKCHECKING -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/js/src -I /root/firefox-clang/js/src -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/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -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-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-character-conversion -std=gnu++20 -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 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ Unified_cpp_js_src_builtin4.cpp
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5#ifndef js_ProfilingFrameIterator_h
6#define js_ProfilingFrameIterator_h
7
8#include "mozilla/Assertions.h"
9#include "mozilla/Attributes.h"
10#include "mozilla/Maybe.h"
11
12#include "jstypes.h"
13
14#include "js/GCAnnotations.h"
15#include "js/ProfilingCategory.h"
16#include "js/TypeDecls.h"
17
18namespace js {
19class Activation;
20namespace jit {
21class JitActivation;
22class JSJitProfilingFrameIterator;
23class JitcodeGlobalEntry;
24
25// Information about a single frame in a JIT call stack, returned by
26// JitcodeGlobalEntry::callStackAtAddr.
27struct CallStackFrameInfo {
28 // The function name or label for this frame.
29 const char* label;
30 // The script source ID for this frame. Used to identify which script source
31 // this frame belongs to.
32 uint32_t sourceId;
33 // Line number (1-origin, 0 means no line info available)
34 uint32_t line;
35 // Column number (1-origin, 0 means no column info available)
36 uint32_t column;
37};
38
39} // namespace jit
40namespace wasm {
41class ProfilingFrameIterator;
42} // namespace wasm
43} // namespace js
44
45namespace JS {
46
47// This iterator can be used to walk the stack of a thread suspended at an
48// arbitrary pc. To provide accurate results, profiling must have been enabled
49// (via EnableRuntimeProfilingStack) before executing the callstack being
50// unwound.
51//
52// Note that the caller must not do anything that could cause GC to happen while
53// the iterator is alive, since this could invalidate Ion code and cause its
54// contents to become out of date.
55class MOZ_NON_PARAM JS_PUBLIC_API ProfilingFrameIterator {
56 public:
57 enum class Kind : bool { JSJit, Wasm };
58
59 private:
60 JSContext* cx_;
61 mozilla::Maybe<uint64_t> samplePositionInProfilerBuffer_;
62 js::Activation* activation_;
63 // For each JitActivation, this records the lowest (most recent) stack
64 // address. This will usually be either the exitFP of the activation or the
65 // frame or stack pointer of currently executing JIT/Wasm code. The Gecko
66 // profiler uses this to skip native frames between the activation and
67 // endStackAddress_.
68 void* endStackAddress_ = nullptr;
69 Kind kind_ = Kind::JSJit;
70
71 static const unsigned StorageSpace = 9 * sizeof(void*);
72 alignas(void*) unsigned char storage_[StorageSpace];
73
74 void* storage() { return storage_; }
75 const void* storage() const { return storage_; }
76
77 js::wasm::ProfilingFrameIterator& wasmIter() {
78 MOZ_ASSERT(!done())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!done())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!done()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!done()", "/root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/js/ProfilingFrameIterator.h"
, 78); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!done()" ")")
; do { MOZ_CrashSequence(__null, 78); __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
79 MOZ_ASSERT(isWasm())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isWasm())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isWasm()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isWasm()", "/root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/js/ProfilingFrameIterator.h"
, 79); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isWasm()" ")"
); do { MOZ_CrashSequence(__null, 79); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
80 return *static_cast<js::wasm::ProfilingFrameIterator*>(storage());
81 }
82 const js::wasm::ProfilingFrameIterator& wasmIter() const {
83 MOZ_ASSERT(!done())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!done())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!done()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!done()", "/root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/js/ProfilingFrameIterator.h"
, 83); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!done()" ")")
; do { MOZ_CrashSequence(__null, 83); __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
84 MOZ_ASSERT(isWasm())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isWasm())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isWasm()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isWasm()", "/root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/js/ProfilingFrameIterator.h"
, 84); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isWasm()" ")"
); do { MOZ_CrashSequence(__null, 84); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
85 return *static_cast<const js::wasm::ProfilingFrameIterator*>(storage());
86 }
87
88 js::jit::JSJitProfilingFrameIterator& jsJitIter() {
89 MOZ_ASSERT(!done())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!done())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!done()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!done()", "/root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/js/ProfilingFrameIterator.h"
, 89); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!done()" ")")
; do { MOZ_CrashSequence(__null, 89); __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
90 MOZ_ASSERT(isJSJit())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isJSJit())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isJSJit()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isJSJit()", "/root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/js/ProfilingFrameIterator.h"
, 90); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isJSJit()" ")"
); do { MOZ_CrashSequence(__null, 90); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
91 return *static_cast<js::jit::JSJitProfilingFrameIterator*>(storage());
92 }
93
94 const js::jit::JSJitProfilingFrameIterator& jsJitIter() const {
95 MOZ_ASSERT(!done())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!done())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!done()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!done()", "/root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/js/ProfilingFrameIterator.h"
, 95); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!done()" ")")
; do { MOZ_CrashSequence(__null, 95); __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
96 MOZ_ASSERT(isJSJit())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isJSJit())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isJSJit()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isJSJit()", "/root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/js/ProfilingFrameIterator.h"
, 96); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isJSJit()" ")"
); do { MOZ_CrashSequence(__null, 96); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
97 return *static_cast<const js::jit::JSJitProfilingFrameIterator*>(storage());
98 }
99
100 void maybeSetEndStackAddress(void* addr) {
101 // If endStackAddress_ has already been set, don't change it because we
102 // want this to correspond to the most recent frame.
103 if (!endStackAddress_) {
104 endStackAddress_ = addr;
105 }
106 }
107
108 void settleFrames();
109 void settle();
110
111 public:
112 struct RegisterState {
113 RegisterState()
114 : pc(nullptr),
115 sp(nullptr),
116 fp(nullptr),
117 unused1(nullptr),
118 unused2(nullptr) {}
119 void* pc;
120 void* sp;
121 void* fp;
122 union {
123 // Value of the LR register on ARM platforms.
124 void* lr;
125 // The return address during a tail call operation.
126 // Note that for ARM is still the value of LR register.
127 void* tempRA;
128 // Undefined on non-ARM plaforms outside tail calls operations.
129 void* unused1;
130 };
131 union {
132 // The FP reference during a tail call operation.
133 void* tempFP;
134 // Undefined outside tail calls operations.
135 void* unused2;
136 };
137 };
138
139 ProfilingFrameIterator(
140 JSContext* cx, const RegisterState& state,
141 const mozilla::Maybe<uint64_t>& samplePositionInProfilerBuffer =
142 mozilla::Nothing());
143 ~ProfilingFrameIterator();
144 void operator++();
145 bool done() const { return !activation_; }
146
147 // Assuming the stack grows down (we do), the return value:
148 // - always points into the stack
149 // - is weakly monotonically increasing (may be equal for successive frames)
150 // - will compare greater than newer native and psuedo-stack frame addresses
151 // and less than older native and psuedo-stack frame addresses
152 // The exception is at the point of stack switching between the main stack
153 // and a suspendable one (see WebAssembly JS Promise Integration proposal).
154 void* stackAddress() const;
155
156 enum FrameKind {
157 Frame_BaselineInterpreter,
158 Frame_Baseline,
159 Frame_Ion,
160 Frame_WasmBaseline,
161 Frame_WasmIon,
162 Frame_WasmOther,
163 };
164
165 struct Frame {
Excessive padding in 'struct JS::ProfilingFrameIterator::Frame' (8 padding bytes, where 0 is optimal). Optimal fields order: stackAddress, , activation, endStackAddress, label, interpreterScript, realmID, kind, sourceId, line, column, consider reordering the fields or adding explicit padding members
166 FrameKind kind;
167 void* stackAddress;
168 union {
169 void* returnAddress_;
170 jsbytecode* interpreterPC_;
171 };
172 void* activation;
173 void* endStackAddress;
174 const char* label;
175 JSScript* interpreterScript;
176 uint64_t realmID;
177 uint32_t sourceId;
178 uint32_t line;
179 uint32_t column;
180
181 public:
182 void* returnAddress() const {
183 MOZ_ASSERT(kind != Frame_BaselineInterpreter)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(kind != Frame_BaselineInterpreter)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(kind != Frame_BaselineInterpreter
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"kind != Frame_BaselineInterpreter", "/root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/js/ProfilingFrameIterator.h"
, 183); AnnotateMozCrashReason("MOZ_ASSERT" "(" "kind != Frame_BaselineInterpreter"
")"); do { MOZ_CrashSequence(__null, 183); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
184 return returnAddress_;
185 }
186 jsbytecode* interpreterPC() const {
187 MOZ_ASSERT(kind == Frame_BaselineInterpreter)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(kind == Frame_BaselineInterpreter)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(kind == Frame_BaselineInterpreter
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"kind == Frame_BaselineInterpreter", "/root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/js/ProfilingFrameIterator.h"
, 187); AnnotateMozCrashReason("MOZ_ASSERT" "(" "kind == Frame_BaselineInterpreter"
")"); do { MOZ_CrashSequence(__null, 187); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
188 return interpreterPC_;
189 }
190 ProfilingCategoryPair profilingCategory() const {
191 switch (kind) {
192 case FrameKind::Frame_BaselineInterpreter:
193 return JS::ProfilingCategoryPair::JS_BaselineInterpret;
194 case FrameKind::Frame_Baseline:
195 return JS::ProfilingCategoryPair::JS_Baseline;
196 case FrameKind::Frame_Ion:
197 return JS::ProfilingCategoryPair::JS_IonMonkey;
198 case FrameKind::Frame_WasmBaseline:
199 return JS::ProfilingCategoryPair::JS_WasmBaseline;
200 case FrameKind::Frame_WasmIon:
201 return JS::ProfilingCategoryPair::JS_WasmIon;
202 case FrameKind::Frame_WasmOther:
203 return JS::ProfilingCategoryPair::JS_WasmOther;
204 }
205 MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/js/ProfilingFrameIterator.h"
, 205); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { MOZ_CrashSequence
(__null, 205); __attribute__((nomerge)) ::abort(); } while (false
); } while (false)
;
206 }
207 } JS_HAZ_GC_INVALIDATED;
208
209 bool isWasm() const;
210 bool isJSJit() const;
211
212 uint32_t extractStack(Frame* frames, uint32_t offset, uint32_t end) const;
213
214 mozilla::Maybe<Frame> getPhysicalFrameWithoutLabel() const;
215
216 // Return the registers from the native caller frame.
217 // Nothing{} if this iterator is NOT pointing at a native-to-JIT entry frame,
218 // or if the information is not accessible/implemented on this platform.
219 mozilla::Maybe<RegisterState> getCppEntryRegisters() const;
220
221 private:
222 mozilla::Maybe<Frame> getPhysicalFrameAndEntry(
223 const js::jit::JitcodeGlobalEntry** entry) const;
224
225 void iteratorConstruct(const RegisterState& state);
226 void iteratorConstruct();
227 void iteratorDestroy();
228 bool iteratorDone();
229} JS_HAZ_GC_INVALIDATED;
230
231JS_PUBLIC_API bool IsProfilingEnabledForContext(JSContext* cx);
232
233/**
234 * After each sample run, this method should be called with the current buffer
235 * position at which the buffer contents start. This will update the
236 * corresponding field on the JSRuntime.
237 *
238 * See the field |profilerSampleBufferRangeStart| on JSRuntime for documentation
239 * about what this value is used for.
240 */
241JS_PUBLIC_API void SetJSContextProfilerSampleBufferRangeStart(
242 JSContext* cx, uint64_t rangeStart);
243
244class ProfiledFrameRange;
245
246// A handle to the underlying JitcodeGlobalEntry, so as to avoid repeated
247// lookups on JitcodeGlobalTable.
248class MOZ_STACK_CLASS ProfiledFrameHandle {
249 friend class ProfiledFrameRange;
250
251 JSRuntime* rt_;
252 js::jit::JitcodeGlobalEntry& entry_;
253 void* addr_;
254 void* canonicalAddr_;
255 js::jit::CallStackFrameInfo frameInfo_;
256 uint32_t depth_;
257
258 ProfiledFrameHandle(JSRuntime* rt, js::jit::JitcodeGlobalEntry& entry,
259 void* addr, const js::jit::CallStackFrameInfo& frameInfo,
260 uint32_t depth);
261
262 public:
263 const char* label() const { return frameInfo_.label; }
264 uint32_t depth() const { return depth_; }
265 void* canonicalAddress() const { return canonicalAddr_; }
266
267 JS_PUBLIC_API ProfilingFrameIterator::FrameKind frameKind() const;
268
269 JS_PUBLIC_API uint64_t realmID() const;
270
271 JS_PUBLIC_API uint32_t sourceId() const { return frameInfo_.sourceId; }
272
273 JS_PUBLIC_API uint32_t line() const { return frameInfo_.line; }
274
275 JS_PUBLIC_API uint32_t column() const { return frameInfo_.column; }
276};
277
278class ProfiledFrameRange {
279 public:
280 class Iter final {
281 public:
282 Iter(const ProfiledFrameRange& range, uint32_t index)
283 : range_(range), index_(index) {}
284
285 JS_PUBLIC_API ProfiledFrameHandle operator*() const;
286
287 // Provide the bare minimum of iterator methods that are needed for
288 // C++ ranged for loops.
289 Iter& operator++() {
290 ++index_;
291 return *this;
292 }
293 bool operator==(const Iter& rhs) const { return index_ == rhs.index_; }
294 bool operator!=(const Iter& rhs) const { return !(*this == rhs); }
295
296 private:
297 const ProfiledFrameRange& range_;
298 uint32_t index_;
299 };
300
301 Iter begin() const { return Iter(*this, 0); }
302 Iter end() const { return Iter(*this, depth_); }
303
304 private:
305 friend JS_PUBLIC_API ProfiledFrameRange GetProfiledFrames(JSContext* cx,
306 void* addr);
307
308 ProfiledFrameRange(JSRuntime* rt, void* addr,
309 js::jit::JitcodeGlobalEntry* entry)
310 : rt_(rt), addr_(addr), entry_(entry), depth_(0) {}
311
312 JSRuntime* rt_;
313 void* addr_;
314 js::jit::JitcodeGlobalEntry* entry_;
315 // Maximum inlining depth. This must match InlineScriptTree::MaxDepth.
316 // We can't use InlineScriptTree::MaxDepth directly here because this is a
317 // public header and InlineScriptTree.h is private.
318 static constexpr uint32_t MaxInliningDepth = 8;
319 js::jit::CallStackFrameInfo frames_[MaxInliningDepth];
320 uint32_t depth_;
321};
322
323// Returns a range that can be iterated over using C++ ranged for loops.
324JS_PUBLIC_API ProfiledFrameRange GetProfiledFrames(JSContext* cx, void* addr);
325
326} // namespace JS
327
328#endif /* js_ProfilingFrameIterator_h */