Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/dom/media/webaudio/blink/ReverbConvolver.cpp
Warning:line 230, column 13
Although the value stored to 'readIndex' is used in the enclosing expression, the value is never actually read from 'readIndex'

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 Unified_cpp_webaudio_blink0.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=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/media/webaudio/blink -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/media/webaudio/blink -resource-dir /usr/lib/llvm-18/lib/clang/18 -include /var/lib/jenkins/workspace/firefox-scan-build/config/gcc_hidden.h -include /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D USE_SSE2 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /var/lib/jenkins/workspace/firefox-scan-build/dom/media/webaudio/blink -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/media/webaudio/blink -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /var/lib/jenkins/workspace/firefox-scan-build/ipc/chromium/src -I /var/lib/jenkins/workspace/firefox-scan-build/dom/media/webaudio -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /var/lib/jenkins/workspace/firefox-scan-build/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-18/lib/clang/18/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=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 -fdeprecated-macro -ferror-limit 19 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -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-2024-07-21-021012-413605-1 -x c++ Unified_cpp_webaudio_blink0.cpp
1/*
2 * Copyright (C) 2010 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include "ReverbConvolver.h"
30#include "ReverbConvolverStage.h"
31
32using namespace mozilla;
33
34namespace WebCore {
35
36const int InputBufferSize = 8 * 16384;
37
38// We only process the leading portion of the impulse response in the real-time
39// thread. We don't exceed this length. It turns out then, that the background
40// thread has about 278msec of scheduling slop. Empirically, this has been found
41// to be a good compromise between giving enough time for scheduling slop, while
42// still minimizing the amount of processing done in the primary (high-priority)
43// thread. This was found to be a good value on Mac OS X, and may work well on
44// other platforms as well, assuming the very rough scheduling latencies are
45// similar on these time-scales. Of course, this code may need to be tuned for
46// individual platforms if this assumption is found to be incorrect.
47const size_t RealtimeFrameLimit = 8192 + 4096 // ~278msec @ 44.1KHz
48 - WEBAUDIO_BLOCK_SIZE;
49// First stage will have size MinFFTSize - successive stages will double in
50// size each time until we hit the maximum size.
51const size_t MinFFTSize = 256;
52// If we are using background threads then don't exceed this FFT size for the
53// stages which run in the real-time thread. This avoids having only one or
54// two large stages (size 16384 or so) at the end which take a lot of time
55// every several processing slices. This way we amortize the cost over more
56// processing slices.
57const size_t MaxRealtimeFFTSize = 4096;
58
59ReverbConvolver::ReverbConvolver(const float* impulseResponseData,
60 size_t impulseResponseLength,
61 size_t maxFFTSize, size_t convolverRenderPhase,
62 bool useBackgroundThreads,
63 bool* aAllocationFailure)
64 : m_impulseResponseLength(impulseResponseLength),
65 m_inputBuffer(InputBufferSize),
66 m_backgroundThread("ConvolverWorker"),
67 m_backgroundThreadMonitor("ConvolverMonitor"),
68 m_useBackgroundThreads(useBackgroundThreads),
69 m_wantsToExit(false),
70 m_moreInputBuffered(false) {
71 *aAllocationFailure = !m_accumulationBuffer.allocate(impulseResponseLength +
72 WEBAUDIO_BLOCK_SIZE);
73 if (*aAllocationFailure) {
74 return;
75 }
76 // For the moment, a good way to know if we have real-time constraint is to
77 // check if we're using background threads. Otherwise, assume we're being run
78 // from a command-line tool.
79 bool hasRealtimeConstraint = useBackgroundThreads;
80
81 const float* response = impulseResponseData;
82 size_t totalResponseLength = impulseResponseLength;
83
84 // The total latency is zero because the first FFT stage is small enough
85 // to return output in the first block.
86 size_t reverbTotalLatency = 0;
87
88 size_t stageOffset = 0;
89 size_t stagePhase = 0;
90 size_t fftSize = MinFFTSize;
91 while (stageOffset < totalResponseLength) {
92 size_t stageSize = fftSize / 2;
93
94 // For the last stage, it's possible that stageOffset is such that we're
95 // straddling the end of the impulse response buffer (if we use stageSize),
96 // so reduce the last stage's length...
97 if (stageSize + stageOffset > totalResponseLength) {
98 stageSize = totalResponseLength - stageOffset;
99 // Use smallest FFT that is large enough to cover the last stage.
100 fftSize = MinFFTSize;
101 while (stageSize * 2 > fftSize) {
102 fftSize *= 2;
103 }
104 }
105
106 // This "staggers" the time when each FFT happens so they don't all happen
107 // at the same time
108 int renderPhase = convolverRenderPhase + stagePhase;
109
110 UniquePtr<ReverbConvolverStage> stage(new ReverbConvolverStage(
111 response, totalResponseLength, reverbTotalLatency, stageOffset,
112 stageSize, fftSize, renderPhase, &m_accumulationBuffer));
113
114 bool isBackgroundStage = false;
115
116 if (this->useBackgroundThreads() && stageOffset > RealtimeFrameLimit) {
117 m_backgroundStages.AppendElement(std::move(stage));
118 isBackgroundStage = true;
119 } else
120 m_stages.AppendElement(std::move(stage));
121
122 // Figure out next FFT size
123 fftSize *= 2;
124
125 stageOffset += stageSize;
126
127 if (hasRealtimeConstraint && !isBackgroundStage &&
128 fftSize > MaxRealtimeFFTSize) {
129 fftSize = MaxRealtimeFFTSize;
130 // Custom phase positions for all but the first of the realtime
131 // stages of largest size. These spread out the work of the
132 // larger realtime stages. None of the FFTs of size 1024, 2048 or
133 // 4096 are performed when processing the same block. The first
134 // MaxRealtimeFFTSize = 4096 stage, at the end of the doubling,
135 // performs its FFT at block 7. The FFTs of size 2048 are
136 // performed in blocks 3 + 8 * n and size 1024 at 1 + 4 * n.
137 const uint32_t phaseLookup[] = {14, 0, 10, 4};
138 stagePhase = WEBAUDIO_BLOCK_SIZE *
139 phaseLookup[m_stages.Length() % ArrayLength(phaseLookup)];
140 } else if (fftSize > maxFFTSize) {
141 fftSize = maxFFTSize;
142 // A prime offset spreads out FFTs in a way that all
143 // available phase positions will be used if there are sufficient
144 // stages.
145 stagePhase += 5 * WEBAUDIO_BLOCK_SIZE;
146 } else if (stageSize > WEBAUDIO_BLOCK_SIZE) {
147 // As the stages are doubling in size, the next FFT will occur
148 // mid-way between FFTs for this stage.
149 stagePhase = stageSize - WEBAUDIO_BLOCK_SIZE;
150 }
151 }
152
153 // Start up background thread
154 // FIXME: would be better to up the thread priority here. It doesn't need to
155 // be real-time, but higher than the default...
156 if (this->useBackgroundThreads() && m_backgroundStages.Length() > 0) {
157 if (!m_backgroundThread.Start()) {
158 NS_WARNING("Cannot start convolver thread.")NS_DebugBreak(NS_DEBUG_WARNING, "Cannot start convolver thread."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/webaudio/blink/ReverbConvolver.cpp"
, 158)
;
159 return;
160 }
161 m_backgroundThread.message_loop()->PostTask(NewNonOwningRunnableMethod(
162 "WebCore::ReverbConvolver::backgroundThreadEntry", this,
163 &ReverbConvolver::backgroundThreadEntry));
164 }
165}
166
167ReverbConvolver::~ReverbConvolver() {
168 // Wait for background thread to stop
169 if (useBackgroundThreads() && m_backgroundThread.IsRunning()) {
170 m_wantsToExit = true;
171
172 // Wake up thread so it can return
173 {
174 MonitorAutoLock locker(m_backgroundThreadMonitor);
175 m_moreInputBuffered = true;
176 m_backgroundThreadMonitor.Notify();
177 }
178
179 m_backgroundThread.Stop();
180 }
181}
182
183size_t ReverbConvolver::sizeOfIncludingThis(
184 mozilla::MallocSizeOf aMallocSizeOf) const {
185 size_t amount = aMallocSizeOf(this);
186 amount += m_stages.ShallowSizeOfExcludingThis(aMallocSizeOf);
187 for (size_t i = 0; i < m_stages.Length(); i++) {
188 if (m_stages[i]) {
189 amount += m_stages[i]->sizeOfIncludingThis(aMallocSizeOf);
190 }
191 }
192
193 amount += m_backgroundStages.ShallowSizeOfExcludingThis(aMallocSizeOf);
194 for (size_t i = 0; i < m_backgroundStages.Length(); i++) {
195 if (m_backgroundStages[i]) {
196 amount += m_backgroundStages[i]->sizeOfIncludingThis(aMallocSizeOf);
197 }
198 }
199
200 // NB: The buffer sizes are static, so even though they might be accessed
201 // in another thread it's safe to measure them.
202 amount += m_accumulationBuffer.sizeOfExcludingThis(aMallocSizeOf);
203 amount += m_inputBuffer.sizeOfExcludingThis(aMallocSizeOf);
204
205 // Possible future measurements:
206 // - m_backgroundThread
207 // - m_backgroundThreadMonitor
208 return amount;
209}
210
211void ReverbConvolver::backgroundThreadEntry() {
212 while (!m_wantsToExit) {
213 // Wait for realtime thread to give us more input
214 m_moreInputBuffered = false;
215 {
216 MonitorAutoLock locker(m_backgroundThreadMonitor);
217 while (!m_moreInputBuffered && !m_wantsToExit)
218 m_backgroundThreadMonitor.Wait();
219 }
220
221 // Process all of the stages until their read indices reach the input
222 // buffer's write index
223 int writeIndex = m_inputBuffer.writeIndex();
224
225 // Even though it doesn't seem like every stage needs to maintain its own
226 // version of readIndex we do this in case we want to run in more than one
227 // background thread.
228 int readIndex;
229
230 while ((readIndex = m_backgroundStages[0]->inputReadIndex()) !=
Although the value stored to 'readIndex' is used in the enclosing expression, the value is never actually read from 'readIndex'
231 writeIndex) { // FIXME: do better to detect buffer overrun...
232 // Accumulate contributions from each stage
233 for (size_t i = 0; i < m_backgroundStages.Length(); ++i)
234 m_backgroundStages[i]->processInBackground(this);
235 }
236 }
237}
238
239void ReverbConvolver::process(const float* sourceChannelData,
240 float* destinationChannelData) {
241 const float* source = sourceChannelData;
242 float* destination = destinationChannelData;
243 bool isDataSafe = source && destination;
244 MOZ_ASSERT(isDataSafe)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isDataSafe)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isDataSafe))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("isDataSafe", "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/webaudio/blink/ReverbConvolver.cpp"
, 244); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isDataSafe" ")"
); do { *((volatile int*)__null) = 244; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
245 if (!isDataSafe) return;
246
247 // Feed input buffer (read by all threads)
248 m_inputBuffer.write(source, WEBAUDIO_BLOCK_SIZE);
249
250 // Accumulate contributions from each stage
251 for (size_t i = 0; i < m_stages.Length(); ++i) m_stages[i]->process(source);
252
253 // Finally read from accumulation buffer
254 m_accumulationBuffer.readAndClear(destination, WEBAUDIO_BLOCK_SIZE);
255
256 // Now that we've buffered more input, wake up our background thread.
257
258 // Not using a MonitorAutoLock looks strange, but we use a TryLock() instead
259 // because this is run on the real-time thread where it is a disaster for the
260 // lock to be contended (causes audio glitching). It's OK if we fail to
261 // signal from time to time, since we'll get to it the next time we're called.
262 // We're called repeatedly and frequently (around every 3ms). The background
263 // thread is processing well into the future and has a considerable amount of
264 // leeway here...
265 if (m_backgroundThreadMonitor.TryLock()) {
266 m_moreInputBuffered = true;
267 m_backgroundThreadMonitor.Notify();
268 m_backgroundThreadMonitor.Unlock();
269 }
270}
271
272} // namespace WebCore