Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/toolkit/crashreporter/breakpad-client/linux/./../../../../../toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_server.cc
Warning:line 324, column 5
Value stored to 'res' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_linux0.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/toolkit/crashreporter/breakpad-client/linux -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/toolkit/crashreporter/breakpad-client/linux -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 COMMON_LINUX_GUID_CREATOR_H__=1 -D NO_STABS_SUPPORT -D MOZ_PHC -D MOZ_HAS_MOZGLUE -I /root/firefox-clang/toolkit/crashreporter/breakpad-client/linux -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/toolkit/crashreporter/breakpad-client/linux -I /root/firefox-clang/toolkit/crashreporter/breakpad-client -I /root/firefox-clang/toolkit/crashreporter/google-breakpad/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 -Wno-unused-local-typedefs -Wno-deprecated-declarations -Wno-bool-compare -Wno-unused-but-set-variable -Wno-c++11-narrowing -Wno-implicit-fallthrough -Wno-error=stack-protector -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_linux0.cpp
1// Copyright (c) 2010 Google Inc.
2// 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 are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30#include <assert.h>
31#include <dirent.h>
32#include <fcntl.h>
33#include <limits.h>
34#include <poll.h>
35#include <stdio.h>
36#include <string.h>
37#include <sys/socket.h>
38#include <sys/stat.h>
39#include <sys/types.h>
40#include <unistd.h>
41
42#include <vector>
43
44#include "linux/crash_generation/crash_generation_server.h"
45#include "linux/crash_generation/client_info.h"
46#include "linux/handler/exception_handler.h"
47#include "linux/handler/guid_generator.h"
48#include "linux/minidump_writer/minidump_writer.h"
49#include "common/linux/eintr_wrapper.h"
50#include "common/linux/safe_readlink.h"
51
52#if defined(MOZ_OXIDIZED_BREAKPAD1)
53# include "mozilla/toolkit/crashreporter/rust_minidump_writer_linux_ffi_generated.h"
54#endif // defined(MOZ_OXIDIZED_BREAKPAD)
55
56static const char kCommandQuit = 'x';
57
58namespace google_breakpad {
59
60CrashGenerationServer::CrashGenerationServer(
61 const int listen_fd,
62#if defined(MOZ_OXIDIZED_BREAKPAD1)
63 std::function<GetAuxvInfoCallback> get_auxv_info,
64#endif // defined(MOZ_OXIDIZED_BREAKPAD)
65 std::function<OnClientDumpRequestCallback> dump_callback,
66 void* dump_context,
67 const string* dump_path) :
68 server_fd_(listen_fd),
69#if defined(MOZ_OXIDIZED_BREAKPAD1)
70 get_auxv_info_(std::move(get_auxv_info)),
71#endif // defined(MOZ_OXIDIZED_BREAKPAD)
72 dump_callback_(std::move(dump_callback)),
73 dump_context_(dump_context),
74 dump_dir_mutex_(PTHREAD_MUTEX_INITIALIZER{ { 0, 0, 0, 0, PTHREAD_MUTEX_TIMED_NP, 0, 0, { __null, __null
} } }
),
75 started_(false)
76{
77 if (dump_path)
78 dump_dir_ = *dump_path;
79 else
80 dump_dir_ = "/tmp";
81}
82
83CrashGenerationServer::~CrashGenerationServer()
84{
85 if (started_)
86 Stop();
87}
88
89bool
90CrashGenerationServer::Start()
91{
92 if (started_ || 0 > server_fd_)
93 return false;
94
95 int control_pipe[2];
96 if (pipe(control_pipe))
97 return false;
98
99 if (fcntl(control_pipe[0], F_SETFD2, FD_CLOEXEC1))
100 return false;
101 if (fcntl(control_pipe[1], F_SETFD2, FD_CLOEXEC1))
102 return false;
103
104 if (fcntl(control_pipe[0], F_SETFL4, O_NONBLOCK04000))
105 return false;
106
107 control_pipe_in_ = control_pipe[0];
108 control_pipe_out_ = control_pipe[1];
109
110 if (pthread_create(&thread_, nullptr,
111 [](void* context) -> void* {
112 reinterpret_cast<CrashGenerationServer*>(context)->Run();
113 return nullptr;
114 }, this))
115 return false;
116
117 started_ = true;
118 return true;
119}
120
121void
122CrashGenerationServer::Stop()
123{
124 assert(pthread_self() != thread_)(static_cast <bool> (pthread_self() != thread_) ? void (
0) : __assert_fail ("pthread_self() != thread_", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
125
126 if (!started_)
127 return;
128
129 HANDLE_EINTR(write(control_pipe_out_, &kCommandQuit, 1))({ __typeof__(write(control_pipe_out_, &kCommandQuit, 1))
eintr_wrapper_result; do { eintr_wrapper_result = (write(control_pipe_out_
, &kCommandQuit, 1)); } while (eintr_wrapper_result == -1
&& (*__errno_location ()) == 4); eintr_wrapper_result
; })
;
130
131 void* dummy;
132 pthread_join(thread_, &dummy);
133
134 close(control_pipe_in_);
135 close(control_pipe_out_);
136
137 started_ = false;
138}
139
140void
141CrashGenerationServer::SetPath(const char* dump_path)
142{
143 pthread_mutex_lock(&dump_dir_mutex_);
144 this->dump_dir_ = string(dump_path);
145 pthread_mutex_unlock(&dump_dir_mutex_);
146}
147
148//static
149bool
150CrashGenerationServer::CreateReportChannel(int* server_fd, int* client_fd)
151{
152 int fds[2];
153
154 if (socketpair(AF_UNIX1, SOCK_SEQPACKETSOCK_SEQPACKET, 0, fds))
155 return false;
156
157 static const int on = 1;
158 // Enable passcred on the server end of the socket
159 if (setsockopt(fds[1], SOL_SOCKET1, SO_PASSCRED16, &on, sizeof(on)))
160 return false;
161
162 if (fcntl(fds[1], F_SETFL4, O_NONBLOCK04000))
163 return false;
164
165 *client_fd = fds[0];
166 *server_fd = fds[1];
167 return true;
168}
169
170// The following methods/functions execute on the server thread
171
172void
173CrashGenerationServer::Run()
174{
175 struct pollfd pollfds[2];
176 memset(&pollfds, 0, sizeof(pollfds));
177
178 pollfds[0].fd = server_fd_;
179 pollfds[0].events = POLLIN0x001;
180
181 pollfds[1].fd = control_pipe_in_;
182 pollfds[1].events = POLLIN0x001;
183
184 while (true) {
185 // infinite timeout
186 int nevents = poll(pollfds, sizeof(pollfds)/sizeof(pollfds[0]), -1);
187 if (-1 == nevents) {
188 if (EINTR4 == errno(*__errno_location ())) {
189 continue;
190 } else {
191 return;
192 }
193 }
194
195 if (pollfds[0].revents && !ClientEvent(pollfds[0].revents))
196 return;
197
198 if (pollfds[1].revents && !ControlEvent(pollfds[1].revents))
199 return;
200 }
201}
202
203bool
204CrashGenerationServer::ClientEvent(short revents)
205{
206 if (POLLHUP0x010 & revents)
207 return false;
208 assert(POLLIN & revents)(static_cast <bool> (0x001 & revents) ? void (0) : __assert_fail
("POLLIN & revents", __builtin_FILE (), __builtin_LINE (
), __extension__ __PRETTY_FUNCTION__))
;
209
210 // A process has crashed and has signaled us by writing a datagram
211 // to the death signal socket. The datagram contains the crash context needed
212 // for writing the minidump as well as a file descriptor and a credentials
213 // block so that they can't lie about their pid.
214
215 // The length of the control message:
216 static const unsigned kControlMsgSize =
217 CMSG_SPACE(sizeof(int))((((sizeof(int)) + sizeof (size_t) - 1) & (size_t) ~(sizeof
(size_t) - 1)) + (((sizeof (struct cmsghdr)) + sizeof (size_t
) - 1) & (size_t) ~(sizeof (size_t) - 1)))
+ CMSG_SPACE(sizeof(struct ucred))((((sizeof(struct ucred)) + sizeof (size_t) - 1) & (size_t
) ~(sizeof (size_t) - 1)) + (((sizeof (struct cmsghdr)) + sizeof
(size_t) - 1) & (size_t) ~(sizeof (size_t) - 1)))
;
218 // The length of the regular payload:
219 static const unsigned kCrashContextSize =
220 sizeof(google_breakpad::ExceptionHandler::CrashContext);
221
222 struct msghdr msg = {0};
223 struct iovec iov[1];
224 alignas(16) char crash_context[kCrashContextSize];
225 char control[kControlMsgSize];
226 const ssize_t expected_msg_size = sizeof(crash_context);
227
228 iov[0].iov_base = crash_context;
229 iov[0].iov_len = sizeof(crash_context);
230 msg.msg_iov = iov;
231 msg.msg_iovlen = sizeof(iov)/sizeof(iov[0]);
232 msg.msg_control = control;
233 msg.msg_controllen = kControlMsgSize;
234
235 const ssize_t msg_size = HANDLE_EINTR(recvmsg(server_fd_, &msg, 0))({ __typeof__(recvmsg(server_fd_, &msg, 0)) eintr_wrapper_result
; do { eintr_wrapper_result = (recvmsg(server_fd_, &msg, 0
)); } while (eintr_wrapper_result == -1 && (*__errno_location
()) == 4); eintr_wrapper_result; })
;
236 if (msg_size != expected_msg_size)
237 return true;
238
239 if (msg.msg_controllen != kControlMsgSize ||
240 msg.msg_flags & ~MSG_TRUNCMSG_TRUNC)
241 return true;
242
243 // Walk the control payload and extract the file descriptor and validated pid.
244 pid_t crashing_pid = -1;
245 int signal_fd = -1;
246 for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg)((size_t) (&msg)->msg_controllen >= sizeof (struct cmsghdr
) ? (struct cmsghdr *) (&msg)->msg_control : (struct cmsghdr
*) 0)
; hdr;
247 hdr = CMSG_NXTHDR(&msg, hdr)__cmsg_nxthdr (&msg, hdr)) {
248 if (hdr->cmsg_level != SOL_SOCKET1)
249 continue;
250 if (hdr->cmsg_type == SCM_RIGHTSSCM_RIGHTS) {
251 const unsigned len = hdr->cmsg_len -
252 (((uint8_t*)CMSG_DATA(hdr)((hdr)->__cmsg_data)) - (uint8_t*)hdr);
253 assert(len % sizeof(int) == 0u)(static_cast <bool> (len % sizeof(int) == 0u) ? void (0
) : __assert_fail ("len % sizeof(int) == 0u", __builtin_FILE (
), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
254 const unsigned num_fds = len / sizeof(int);
255 if (num_fds > 1 || num_fds == 0) {
256 // A nasty process could try and send us too many descriptors and
257 // force a leak.
258 for (unsigned i = 0; i < num_fds; ++i)
259 close(reinterpret_cast<int*>(CMSG_DATA(hdr)((hdr)->__cmsg_data))[i]);
260 return true;
261 } else {
262 signal_fd = reinterpret_cast<int*>(CMSG_DATA(hdr)((hdr)->__cmsg_data))[0];
263 }
264 } else if (hdr->cmsg_type == SCM_CREDENTIALSSCM_CREDENTIALS) {
265 const struct ucred *cred =
266 reinterpret_cast<struct ucred*>(CMSG_DATA(hdr)((hdr)->__cmsg_data));
267 crashing_pid = cred->pid;
268 }
269 }
270
271 if (crashing_pid == -1 || signal_fd == -1) {
272 if (signal_fd != -1)
273 close(signal_fd);
274 return true;
275 }
276
277 string minidump_filename;
278 if (!MakeMinidumpFilename(minidump_filename))
279 return true;
280
281#if defined(MOZ_OXIDIZED_BREAKPAD1)
282 ExceptionHandler::CrashContext* breakpad_cc =
283 reinterpret_cast<ExceptionHandler::CrashContext*>(crash_context);
284 ExtraCrashData* extra_data = nullptr;
285 siginfo_t& si = breakpad_cc->siginfo;
286 signalfd_siginfo signalfd_si = {};
287 signalfd_si.ssi_signo = si.si_signo;
288 signalfd_si.ssi_errno = si.si_errno;
289 signalfd_si.ssi_code = si.si_code;
290 signalfd_si.ssi_pid = si.si_pid_sifields._kill.si_pid;
291 signalfd_si.ssi_uid = si.si_uid_sifields._kill.si_uid;
292
293 switch (si.si_signo) {
294 case SIGILL4:
295 case SIGFPE8:
296 case SIGSEGV11:
297 case SIGBUS7:
298 case SIGSYS31:
299 signalfd_si.ssi_addr = reinterpret_cast<size_t>(si.si_addr_sifields._sigfault.si_addr);
300 break;
301 }
302
303 bool res = false;
304
305 MinidumpWriterContext* writer = minidump_writer_create(
306 minidump_filename.c_str(),
307 crashing_pid,
308 breakpad_cc->tid,
309 &extra_data
310 );
311 DirectAuxvDumpInfo auxvInfo = {};
312 if (writer && get_auxv_info_ && get_auxv_info_(crashing_pid, &auxvInfo)) {
313 minidump_writer_set_direct_auxv_dump_info(writer, &auxvInfo);
314 }
315 if (writer) {
316 const fpregset_t *float_state = nullptr;
317
318# ifndef __arm__
319 float_state = reinterpret_cast<const fpregset_t *>(&breakpad_cc->float_state);
320# endif
321
322 minidump_writer_set_crash_context(writer, &breakpad_cc->context, float_state, &signalfd_si);
323
324 res = minidump_writer_dump(writer, extra_data);
Value stored to 'res' is never read
325 }
326#else
327 if (!google_breakpad::WriteMinidump(minidump_filename.c_str(),
328 crashing_pid, crash_context,
329 kCrashContextSize)) {
330 close(signal_fd);
331 return true;
332 }
333#endif
334
335 ClientInfo info(crashing_pid, this, extra_data);
336 extra_data = nullptr; // ownership transferred to the info object.
337
338 if (dump_callback_) {
339 dump_callback_(dump_context_, info, minidump_filename);
340 }
341
342 // Send the done signal to the process: it can exit now.
343 // (Closing this will make the child's sys_read unblock and return 0.)
344 close(signal_fd);
345
346 return true;
347}
348
349bool
350CrashGenerationServer::ControlEvent(short revents)
351{
352 if (POLLHUP0x010 & revents)
353 return false;
354 assert(POLLIN & revents)(static_cast <bool> (0x001 & revents) ? void (0) : __assert_fail
("POLLIN & revents", __builtin_FILE (), __builtin_LINE (
), __extension__ __PRETTY_FUNCTION__))
;
355
356 char command;
357 if (read(control_pipe_in_, &command, 1))
358 return false;
359
360 switch (command) {
361 case kCommandQuit:
362 return false;
363 default:
364 assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
365 }
366
367 return true;
368}
369
370bool
371CrashGenerationServer::MakeMinidumpFilename(string& outFilename)
372{
373 GUID guid;
374 char guidString[kGUIDStringLength+1];
375
376 if (!(CreateGUID(&guid)
377 && GUIDToString(&guid, guidString, sizeof(guidString))))
378 return false;
379
380 char path[PATH_MAX4096];
381 pthread_mutex_lock(&dump_dir_mutex_);
382 snprintf(path, sizeof(path), "%s/%s.dmp", dump_dir_.c_str(), guidString);
383 pthread_mutex_unlock(&dump_dir_mutex_);
384
385 outFilename = path;
386 return true;
387}
388
389} // namespace google_breakpad