Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp
Warning:line 282, column 3
Value stored to 'rv' is never read

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_toolkit_xre0.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/toolkit/xre -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/toolkit/xre -resource-dir /usr/lib/llvm-20/lib/clang/20 -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 _GLIBCXX_ASSERTIONS -D DEBUG=1 -D TELEMETRY_PING_FORMAT_VERSION=4 -D PROXY_PRINTING=1 -D USE_GLX_TEST -D MOZ_APP_NAME="firefox" -D MOZ_APP_BASENAME="Firefox" -D MOZ_APP_DISPLAYNAME="Nightly" -D MOZ_APP_VENDOR="Mozilla" -D MOZ_APP_VERSION="136.0a1" -D OS_TARGET="Linux" -D MOZ_WIDGET_TOOLKIT="gtk" -D MOZ_UPDATER -D MOZ_DISTRIBUTION_ID="org.mozilla" -D TARGET_OS_ABI="Linux_x86_64-gcc3" -D GRE_MILESTONE=136.0a1 -D MOZ_APP_VERSION_DISPLAY=136.0a1 -D APP_VERSION=136.0a1 -D APP_ID={ec8030f7-c20a-464f-9b0e-13a3a9e97384} -D MOZ_BUILD_APP_IS_BROWSER -D MAR_NSS -D TOPOBJDIR=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu -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/toolkit/xre -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/toolkit/xre -I /var/lib/jenkins/workspace/firefox-scan-build/toolkit/components/remote -I /var/lib/jenkins/workspace/firefox-scan-build/widget -I /var/lib/jenkins/workspace/firefox-scan-build/widget/gtk -I /var/lib/jenkins/workspace/firefox-scan-build/toolkit/components/printingui -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/other-licenses/nsis/Contrib/CityHash/cityhash -I /var/lib/jenkins/workspace/firefox-scan-build/toolkit/components/find -I /var/lib/jenkins/workspace/firefox-scan-build/toolkit/components/printingui/ipc -I /var/lib/jenkins/workspace/firefox-scan-build/toolkit/components/windowwatcher -I /var/lib/jenkins/workspace/firefox-scan-build/toolkit/mozapps/update/common -I /var/lib/jenkins/workspace/firefox-scan-build/toolkit/profile -I /var/lib/jenkins/workspace/firefox-scan-build/config -I /var/lib/jenkins/workspace/firefox-scan-build/dom/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/commandhandler -I /var/lib/jenkins/workspace/firefox-scan-build/dom/ipc -I /var/lib/jenkins/workspace/firefox-scan-build/dom/webbrowserpersist -I /var/lib/jenkins/workspace/firefox-scan-build/js/xpconnect/loader -I /var/lib/jenkins/workspace/firefox-scan-build/testing/gtest/mozilla -I /var/lib/jenkins/workspace/firefox-scan-build/third_party/sqlite3/ext -I /var/lib/jenkins/workspace/firefox-scan-build/toolkit/crashreporter -I /var/lib/jenkins/workspace/firefox-scan-build/xpcom/build -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 -I /usr/include/uuid -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/gtk-3.0/unix-print -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -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-20/lib/clang/20/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 -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-01-20-090804-167946-1 -x c++ Unified_cpp_toolkit_xre0.cpp
1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim:set ts=2 sw=2 sts=2 et cindent: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7#include <stdlib.h>
8#include <stdio.h>
9#include "nsUpdateDriver.h"
10
11#include "nsDebug.h"
12#include "nsXULAppAPI.h"
13#include "nsAppRunner.h"
14#include "nsIFile.h"
15#include "nsVariant.h"
16#include "nsCOMPtr.h"
17#include "nsString.h"
18#include "prproces.h"
19#include "mozilla/Logging.h"
20#include "prenv.h"
21#include "nsVersionComparator.h"
22#include "nsDirectoryServiceDefs.h"
23#include "nsThreadUtils.h"
24#include "nsIXULAppInfo.h"
25#include "mozilla/Preferences.h"
26#include "nsPrintfCString.h"
27#include "mozilla/DebugOnly.h"
28#include "mozilla/ErrorNames.h"
29#include "mozilla/Printf.h"
30#include "mozilla/UniquePtr.h"
31#include "nsIObserverService.h"
32#include "nsNetCID.h"
33#include "mozilla/ScopeExit.h"
34#include "mozilla/Services.h"
35#include "mozilla/dom/Promise.h"
36#include "mozilla/CmdLineAndEnvUtils.h"
37
38#ifdef XP_MACOSX
39# include "nsILocalFileMac.h"
40# include "nsCommandLineServiceMac.h"
41# include "MacLaunchHelper.h"
42# include "updaterfileutils_osx.h"
43# include "mozilla/Monitor.h"
44# include "gfxPlatformMac.h"
45#endif
46
47#if defined(XP_WIN)
48# include <direct.h>
49# include <process.h>
50# include <windows.h>
51# include <shlwapi.h>
52# include <strsafe.h>
53# include <shellapi.h>
54# include "commonupdatedir.h"
55# include "nsWindowsHelpers.h"
56# include "pathhash.h"
57# include "WinUtils.h"
58# define getcwd(path, size) _getcwd(path, size)
59# define getpid() GetCurrentProcessId()
60#elif defined(XP_UNIX1)
61# include <unistd.h>
62# include <sys/wait.h>
63#endif
64
65using namespace mozilla;
66
67static LazyLogModule sUpdateLog("updatedriver");
68// Some other file in our unified batch might have defined LOG already.
69#ifdef LOG
70# undef LOG
71#endif
72#define LOG(args)do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, MOZ_LOG_EXPAND_ARGS
args); } } while (0)
MOZ_LOG(sUpdateLog, mozilla::LogLevel::Debug, args)do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, MOZ_LOG_EXPAND_ARGS
args); } } while (0)
73
74static nsresult GetCurrentWorkingDir(nsACString& aOutPath) {
75 // Cannot use NS_GetSpecialDirectory because XPCOM is not yet initialized.
76 // This code is duplicated from xpcom/io/SpecialSystemDirectory.cpp:
77
78 aOutPath.Truncate();
79
80#if defined(XP_WIN)
81 wchar_t wpath[MAX_PATH];
82 if (!_wgetcwd(wpath, std::size(wpath))) {
83 return NS_ERROR_FAILURE;
84 }
85 CopyUTF16toUTF8(nsDependentString(wpath), aOutPath);
86#else
87 char path[MAXPATHLEN4096];
88 if (!getcwd(path, std::size(path))) {
89 return NS_ERROR_FAILURE;
90 }
91 aOutPath = path;
92#endif
93
94 return NS_OK;
95}
96
97/**
98 * Get the path to the installation directory. For Mac OS X this will be the
99 * bundle directory.
100 *
101 * @param appDir the application directory file object
102 * @param installDirPath the path to the installation directory
103 */
104static nsresult GetInstallDirPath(nsIFile* appDir, nsACString& installDirPath) {
105 nsresult rv;
106#ifdef XP_MACOSX
107 nsCOMPtr<nsIFile> parentDir1, parentDir2;
108 rv = appDir->GetParent(getter_AddRefs(parentDir1));
109 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 109); return rv; } } while (false)
;
110 rv = parentDir1->GetParent(getter_AddRefs(parentDir2));
111 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 111); return rv; } } while (false)
;
112 rv = parentDir2->GetNativePath(installDirPath);
113 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 113); return rv; } } while (false)
;
114#elif XP_WIN
115 nsAutoString installDirPathW;
116 rv = appDir->GetPath(installDirPathW);
117 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 117); return rv; } } while (false)
;
118 CopyUTF16toUTF8(installDirPathW, installDirPath);
119#else
120 rv = appDir->GetNativePath(installDirPath);
121 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 121); return rv; } } while (false)
;
122#endif
123 return NS_OK;
124}
125
126static bool GetFile(nsIFile* dir, const nsACString& name,
127 nsCOMPtr<nsIFile>& result) {
128 nsresult rv;
129
130 nsCOMPtr<nsIFile> file;
131 rv = dir->Clone(getter_AddRefs(file));
132 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
133 return false;
134 }
135
136 rv = file->AppendNative(name);
137 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
138 return false;
139 }
140
141 result = file;
142 return true;
143}
144
145static bool GetStatusFile(nsIFile* dir, nsCOMPtr<nsIFile>& result) {
146 return GetFile(dir, "update.status"_ns, result);
147}
148
149static void GetPidString(nsACString& output) {
150 output.Truncate(0);
151 output.AppendInt((int32_t)getpid());
152}
153
154/**
155 * Get the contents of the file when it can be opened with read and write
156 * access. The reason it is opened for both read and write is to prevent trying
157 * to update when the user doesn't have write access to the update directory.
158 * Otherwise we will loop infinitely and try to install it over and over.
159 *
160 * @param file
161 * The file object.
162 * @param buf
163 * The buffer holding the file contents.
164 *
165 * @return The result of `PR_Read`: number of characters read or -1 on error.
166 */
167template <size_t Size>
168static int32_t ReadWritableFile(nsIFile* file, char (&buf)[Size]) {
169 PRFileDesc* fd = nullptr;
170 nsresult rv = file->OpenNSPRFileDesc(PR_RDWR0x04, 0660, &fd);
171 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
172 return 0;
173 }
174
175 const int32_t n = PR_Read(fd, buf, Size);
176 PR_Close(fd);
177
178 return n;
179}
180
181static nsresult WriteFile(nsIFile* file, nsACString& toWrite) {
182 PRFileDesc* fd = nullptr;
183 nsresult rv = file->OpenNSPRFileDesc(PR_WRONLY0x02 | PR_CREATE_FILE0x08 | PR_TRUNCATE0x20,
184 0660, &fd);
185 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 185); return rv; } } while (false)
;
186
187 const int32_t n =
188 PR_Write(fd, PromiseFlatCStringTPromiseFlatString<char>(toWrite).get(), toWrite.Length());
189 PR_Close(fd);
190
191 return (unsigned long)n == toWrite.Length() ? NS_OK : NS_ERROR_FAILURE;
192}
193
194enum UpdateStatus {
195 eNoUpdateAction,
196 ePendingUpdate,
197 ePendingService,
198 ePendingElevate,
199 eAppliedUpdate,
200 eAppliedService,
201};
202
203/**
204 * Returns a value indicating what needs to be done in order to handle an
205 * update.
206 *
207 * @param dir the directory in which we should look for an update.status file.
208 * @param statusFile the update.status file found in the directory.
209 *
210 * @return the update action to be performed.
211 */
212static UpdateStatus GetUpdateStatus(nsIFile* dir,
213 nsCOMPtr<nsIFile>& statusFile) {
214 if (GetStatusFile(dir, statusFile)) {
215 // This buffer must be big enough to hold all valid status codes
216 char buf[32];
217 if (ReadWritableFile(statusFile, buf) >= 0) {
218 const char kPending[] = "pending";
219 const char kPendingService[] = "pending-service";
220 const char kPendingElevate[] = "pending-elevate";
221 const char kApplied[] = "applied";
222 const char kAppliedService[] = "applied-service";
223 if (!strncmp(buf, kPendingElevate, sizeof(kPendingElevate) - 1)) {
224 return ePendingElevate;
225 }
226 if (!strncmp(buf, kPendingService, sizeof(kPendingService) - 1)) {
227 return ePendingService;
228 }
229 if (!strncmp(buf, kPending, sizeof(kPending) - 1)) {
230 return ePendingUpdate;
231 }
232 if (!strncmp(buf, kAppliedService, sizeof(kAppliedService) - 1)) {
233 return eAppliedService;
234 }
235 if (!strncmp(buf, kApplied, sizeof(kApplied) - 1)) {
236 return eAppliedUpdate;
237 }
238 }
239 }
240 return eNoUpdateAction;
241}
242
243static bool GetVersionFile(nsIFile* dir, nsCOMPtr<nsIFile>& result) {
244 return GetFile(dir, "update.version"_ns, result);
245}
246
247// Compares the current application version with the update's application
248// version.
249static bool IsOlderVersion(nsIFile* versionFile, const char* appVersion) {
250 PRFileDesc* fd = nullptr;
251 nsresult rv = versionFile->OpenNSPRFileDesc(PR_RDONLY0x01, 0660, &fd);
252 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
253 return true;
254 }
255
256 char buf[32];
257 const int32_t n = PR_Read(fd, buf, sizeof(buf));
258 PR_Close(fd);
259
260 if (n < 0) {
261 return false;
262 }
263
264 // Trim off the trailing newline
265 if (buf[n - 1] == '\n') {
266 buf[n - 1] = '\0';
267 }
268
269 // If the update xml doesn't provide the application version the file will
270 // contain the string "null" and it is assumed that the update is not older.
271 const char kNull[] = "null";
272 if (strncmp(buf, kNull, sizeof(kNull) - 1) == 0) {
273 return false;
274 }
275
276 return mozilla::Version(appVersion) > buf;
277}
278
279nsresult GetUpdatePatchDir(nsIFile* updRootDir, nsIFile** updatesDirOut) {
280 nsresult rv;
281 nsCOMPtr<nsIFile> updatesDir;
282 rv = updRootDir->Clone(getter_AddRefs(updatesDir));
Value stored to 'rv' is never read
283 rv = updatesDir->AppendNative("updates"_ns);
284 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 284); return rv; } } while (false)
;
285 rv = updatesDir->AppendNative("0"_ns);
286 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 286); return rv; } } while (false)
;
287
288 updatesDir.forget(updatesDirOut);
289 return NS_OK;
290}
291
292nsresult IsMultiSessionInstallLockoutActive(nsIFile* updRootDir,
293 bool& isActive) {
294 nsresult rv;
295
296 nsCOMPtr<nsIFile> timestampFile;
297 rv = GetUpdatePatchDir(updRootDir, getter_AddRefs(timestampFile));
298 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 298); return rv; } } while (false)
;
299 rv = timestampFile->AppendNative("update.timestamp"_ns);
300 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 300); return rv; } } while (false)
;
301
302 // Let's make sure we can hold any valid, unsigned 64 bit integer plus a null.
303 // Maximum 64 bit integer: 18446744073709551615 (20 characters)
304 const size_t bufferSize = 21;
305 char buffer[bufferSize];
306 int32_t readLen = ReadWritableFile(timestampFile, buffer);
307 NS_ENSURE_TRUE(readLen >= 0 && readLen < static_cast<int32_t>(bufferSize),do { if ((__builtin_expect(!!(!(readLen >= 0 && readLen
< static_cast<int32_t>(bufferSize))), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "readLen >= 0 && readLen < static_cast<int32_t>(bufferSize)"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 308); return NS_ERROR_FAILURE; } } while (false)
308 NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(readLen >= 0 && readLen
< static_cast<int32_t>(bufferSize))), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "readLen >= 0 && readLen < static_cast<int32_t>(bufferSize)"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 308); return NS_ERROR_FAILURE; } } while (false)
;
309 buffer[readLen] = '\0';
310
311 // If we couldn't read anything from the file, the lockout is not active.
312 if (readLen == 0) {
313 isActive = false;
314 return NS_OK;
315 }
316
317 nsDependentCString timestampString(buffer);
318 // This timestamp represents the end of the Multi Session Install Lockout.
319 uint64_t msilEnd = timestampString.ToInteger64(&rv);
320 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 320); return rv; } } while (false)
;
321
322 uint64_t now = PR_Now() / PR_USEC_PER_MSEC1000L;
323
324 isActive = now < msilEnd;
325
326#ifdef DEBUG1
327 printf_stderr("Multi Session Install Lockout %s active\n",
328 isActive ? "is" : "is not");
329#endif
330
331 return NS_OK;
332}
333
334nsresult WriteUpdateCompleteTestFile(nsIFile* updRootDir) {
335 nsCOMPtr<nsIFile> outputFile;
336 nsresult rv = updRootDir->Clone(getter_AddRefs(outputFile));
337 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 337); return rv; } } while (false)
;
338 outputFile->AppendNative("test_process_updates.txt"_ns);
339
340 nsAutoCString pid;
341 GetPidString(pid);
342
343 return WriteFile(outputFile, pid);
344}
345
346/**
347 * Applies, switches, or stages an update.
348 *
349 * @param greDir the GRE directory
350 * @param updateDir the update root directory
351 * @param appDir the application directory
352 * @param appArgc the number of args passed to the application
353 * @param appArgv the args passed to the application
354 * (used for restarting the application when necessary)
355 * @param restart true when a restart is necessary.
356 * @param isStaged true when the update has already been staged
357 * @param outpid (out) parameter holding the handle to the updater application
358 * when staging updates
359 */
360static void ApplyUpdate(nsIFile* greDir, nsIFile* updateDir, nsIFile* appDir,
361 int appArgc, char** appArgv, bool restart,
362 bool isStaged, ProcessType* outpid) {
363 MOZ_DIAGNOSTIC_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!restart || NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!restart || NS_IsMainThread(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!restart || NS_IsMainThread()" " (" "restart may only be set when called on the main thread"
")", "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 365); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!restart || NS_IsMainThread()"
") (" "restart may only be set when called on the main thread"
")"); do { *((volatile int*)__null) = 365; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
364 !restart || NS_IsMainThread(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!restart || NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!restart || NS_IsMainThread(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!restart || NS_IsMainThread()" " (" "restart may only be set when called on the main thread"
")", "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 365); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!restart || NS_IsMainThread()"
") (" "restart may only be set when called on the main thread"
")"); do { *((volatile int*)__null) = 365; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
365 "restart may only be set when called on the main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!restart || NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!restart || NS_IsMainThread(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!restart || NS_IsMainThread()" " (" "restart may only be set when called on the main thread"
")", "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 365); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!restart || NS_IsMainThread()"
") (" "restart may only be set when called on the main thread"
")"); do { *((volatile int*)__null) = 365; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
366 // The following determines the update operation to perform.
367 // 1. When restart is false the update will be staged.
368 // 2. When restart is true and isStaged is false the update will apply the mar
369 // file to the installation directory.
370 // 3. When restart is true and isStaged is true the update will switch the
371 // staged update with the installation directory.
372
373 nsresult rv;
374
375 nsCOMPtr<nsIFile> updater;
376 nsAutoCString updaterPath;
377 nsAutoCString updateDirPath;
378#if defined(XP_WIN)
379 // Get an nsIFile reference for the updater in the installation dir.
380 if (!GetFile(greDir, nsLiteralCString(UPDATER_BIN"updater"), updater)) {
381 return;
382 }
383
384 // Get the path to the updater.
385 nsAutoString updaterPathW;
386 rv = updater->GetPath(updaterPathW);
387 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
388 return;
389 }
390 CopyUTF16toUTF8(updaterPathW, updaterPath);
391
392 // Get the path to the update dir.
393 nsAutoString updateDirPathW;
394 rv = updateDir->GetPath(updateDirPathW);
395 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
396 return;
397 }
398 CopyUTF16toUTF8(updateDirPathW, updateDirPath);
399#elif defined(XP_MACOSX)
400 // Get an nsIFile reference for the updater in the installation dir.
401 if (!GetFile(appDir, nsLiteralCString(UPDATER_APP), updater)) {
402 return;
403 }
404 rv = updater->AppendNative("Contents"_ns);
405 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
406 return;
407 }
408 rv = updater->AppendNative("MacOS"_ns);
409 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
410 return;
411 }
412 rv = updater->AppendNative(nsLiteralCString(UPDATER_BIN"updater"));
413 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
414 return;
415 }
416
417 // Get the path to the updater.
418 rv = updater->GetNativePath(updaterPath);
419 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
420 return;
421 }
422
423 // Get the path to the update dir.
424 rv = updateDir->GetNativePath(updateDirPath);
425 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
426 return;
427 }
428#else
429 // Get an nsIFile reference for the updater in the installation dir.
430 if (!GetFile(greDir, nsLiteralCString(UPDATER_BIN"updater"), updater)) {
431 return;
432 }
433
434 // Get the path to the updater.
435 rv = updater->GetNativePath(updaterPath);
436 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
437 return;
438 }
439
440 // Get the path to the update dir.
441 rv = updateDir->GetNativePath(updateDirPath);
442 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
443 return;
444 }
445#endif
446
447 // appFilePath and workingDirPath are only used when the application will be
448 // restarted.
449#ifndef XP_MACOSX
450 nsAutoCString appFilePath;
451#endif
452 nsAutoCString workingDirPath;
453 if (restart) {
454 // Get the path to the current working directory.
455 rv = GetCurrentWorkingDir(workingDirPath);
456 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
457 return;
458 }
459
460 // Get the application file path used by the updater to restart the
461 // application after the update has finished. Note that macOS uses the
462 // path to the application bundle, i.e. installDirPath, to relaunch the
463 // application.
464 nsCOMPtr<nsIFile> appFile;
465 XRE_GetBinaryPath(getter_AddRefs(appFile));
466 if (!appFile) {
467 return;
468 }
469
470#if defined(XP_WIN)
471 nsAutoString appFilePathW;
472 rv = appFile->GetPath(appFilePathW);
473 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
474 return;
475 }
476 CopyUTF16toUTF8(appFilePathW, appFilePath);
477#elif !defined(XP_MACOSX)
478 rv = appFile->GetNativePath(appFilePath);
479 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
480 return;
481 }
482#endif
483 }
484
485 // Get the installation directory path.
486 nsAutoCString installDirPath;
487 rv = GetInstallDirPath(appDir, installDirPath);
488 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
489 return;
490 }
491
492#if defined(XP_MACOSX)
493 // If we're going to do a restart, we need to make sure the font registration
494 // thread has finished before this process exits (bug 1777332).
495 if (restart) {
496 gfxPlatformMac::WaitForFontRegistration();
497 }
498
499 // We need to detect whether elevation is required for this update. This can
500 // occur when an admin user installs the application, but another admin
501 // user attempts to update (see bug 394984).
502 // We only check if we need elevation if we are restarting. We don't attempt
503 // to stage if elevation is required. Staging happens without the user knowing
504 // about it, and we don't want to ask for elevation for seemingly no reason.
505 bool needElevation = false;
506 if (restart) {
507 needElevation = !IsRecursivelyWritable(installDirPath.get());
508 if (needElevation) {
509 // Normally we would check this via nsIAppStartup::wasSilentlyStarted,
510 // but nsIAppStartup isn't available yet.
511 char* mozAppSilentStart = PR_GetEnv("MOZ_APP_SILENT_START");
512 bool wasSilentlyStarted =
513 mozAppSilentStart && (strcmp(mozAppSilentStart, "") != 0);
514 if (wasSilentlyStarted) {
515 // Elevation always requires prompting for credentials on macOS. If we
516 // are trying to restart silently, we must not display UI such as this
517 // prompt.
518 // We make this check here rather than in the updater, because it is
519 // actually Firefox that shows the elevation prompt (via
520 // InstallPrivilegedHelper), not the updater.
521 return;
522 }
523 }
524 }
525#endif
526
527 nsAutoCString applyToDirPath;
528 nsCOMPtr<nsIFile> updatedDir;
529 if (restart && !isStaged) {
530 // The install directory is the same as the apply to directory.
531 applyToDirPath.Assign(installDirPath);
532 } else {
533 // Get the directory where the update is staged or will be staged. This is
534 // `updateDir` for macOS and `appDir` for all other platforms. macOS cannot
535 // stage updates inside the .app bundle (`appDir`) without breaking the code
536 // signature on the bundle, so we use `updateDir` instead.
537#if defined(XP_MACOSX)
538 if (!GetFile(updateDir, "Updated.app"_ns, updatedDir)) {
539#else
540 if (!GetFile(appDir, "updated"_ns, updatedDir)) {
541#endif
542 return;
543 }
544#if defined(XP_WIN)
545 nsAutoString applyToDirPathW;
546 rv = updatedDir->GetPath(applyToDirPathW);
547 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
548 return;
549 }
550 CopyUTF16toUTF8(applyToDirPathW, applyToDirPath);
551#else
552 rv = updatedDir->GetNativePath(applyToDirPath);
553#endif
554 }
555 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
556 return;
557 }
558
559 if (restart && isStaged) {
560 // When the update should already be staged make sure that the updated
561 // directory exists.
562 bool updatedDirExists = false;
563 if (NS_FAILED(updatedDir->Exists(&updatedDirExists))((bool)(__builtin_expect(!!(NS_FAILED_impl(updatedDir->Exists
(&updatedDirExists))), 0)))
|| !updatedDirExists) {
564 return;
565 }
566 }
567
568 // On platforms where we are not calling execv, we may need to make the
569 // updater executable wait for the calling process to exit. Otherwise, the
570 // updater may have trouble modifying our executable image (because it might
571 // still be in use). This is accomplished by passing our PID to the updater
572 // so that it can wait for us to exit. This is not perfect as there is a race
573 // condition that could bite us. It's possible that the calling process could
574 // exit before the updater waits on the specified PID, and in the meantime a
575 // new process with the same PID could be created. This situation is
576 // unlikely, however, given the way most operating systems recycle PIDs. We'll
577 // take our chances ;-) Construct the PID argument for this process to pass to
578 // the updater.
579 nsAutoCString pid;
580 if (restart) {
581#if defined(XP_UNIX1) & !defined(XP_MACOSX)
582 // When execv is used for an update that requires a restart 0 is passed
583 // which is ignored by the updater.
584 pid.AssignLiteral("0");
585#else
586 GetPidString(pid);
587#endif
588 if (isStaged) {
589 // Append a special token to the PID in order to inform the updater that
590 // it should replace install with the updated directory.
591 pid.AppendLiteral("/replace");
592 }
593 } else {
594 // Signal the updater application that it should stage the update.
595 pid.AssignLiteral("-1");
596 }
597
598 int argc = 7;
599 if (restart) {
600 argc += 1; // callback working directory
601 argc += appArgc;
602 if (gRestartedByOS) {
603 argc += 1;
604 }
605 }
606 char** argv = static_cast<char**>(malloc((argc + 1) * sizeof(char*)));
607 if (!argv) {
608 return;
609 }
610 argv[0] = (char*)updaterPath.get();
611 argv[1] = const_cast<char*>("3");
612 argv[2] = (char*)updateDirPath.get();
613 argv[3] = (char*)installDirPath.get();
614 argv[4] = (char*)applyToDirPath.get();
615 argv[5] = const_cast<char*>("first");
616 argv[6] = (char*)pid.get();
617 if (restart && appArgc) {
618 argv[7] = (char*)workingDirPath.get();
619#if defined(XP_MACOSX)
620 argv[8] = (char*)installDirPath.get();
621#else
622 argv[8] = (char*)appFilePath.get();
623#endif
624 for (int i = 1; i < appArgc; ++i) {
625 argv[8 + i] = appArgv[i];
626 }
627 if (gRestartedByOS) {
628 // We haven't truly started up, restore this argument so that we will have
629 // it upon restart.
630 argv[8 + appArgc] = const_cast<char*>("-os-restarted");
631 }
632 }
633 argv[argc] = nullptr;
634
635 if (restart && gSafeMode) {
636 PR_SetEnv("MOZ_SAFE_MODE_RESTART=1");
637 }
638
639 LOG(("spawning updater process [%s]\n", updaterPath.get()))do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "spawning updater process [%s]\n"
, updaterPath.get()); } } while (0)
;
640
641#if defined(XP_UNIX1) && !defined(XP_MACOSX)
642 // We use execv to spawn the updater process on all UNIX systems except Mac
643 // OSX since it is known to cause problems on the Mac. Windows has execv, but
644 // it is a faked implementation that doesn't really replace the current
645 // process. Instead it spawns a new process, so we gain nothing from using
646 // execv on Windows.
647 if (restart) {
648 int execResult = execv(updaterPath.get(), argv);
649 free(argv);
650 exit(execResult);
651 }
652 *outpid = fork();
653 if (*outpid == -1) {
654 free(argv);
655 return;
656 }
657 if (*outpid == 0) {
658 int execResult = execv(updaterPath.get(), argv);
659 free(argv);
660 exit(execResult);
661 }
662#elif defined(XP_WIN)
663 if (isStaged) {
664 // Launch the updater to replace the installation with the staged updated.
665 if (!WinLaunchChild(updaterPathW.get(), argc, argv)) {
666 free(argv);
667 return;
668 }
669 } else {
670 // Launch the updater to either stage or apply an update.
671 if (!WinLaunchChild(updaterPathW.get(), argc, argv, nullptr, outpid)) {
672 free(argv);
673 return;
674 }
675 }
676#elif defined(XP_MACOSX)
677if (restart) {
678 // Ensure we've added URLs to load into the app command line if we're
679 // restarting.
680 CommandLineServiceMac::SetupMacCommandLine(argc, argv, restart);
681
682 if (needElevation) {
683 bool hasLaunched = LaunchElevatedUpdate(argc, argv, outpid);
684 free(argv);
685 if (!hasLaunched) {
686 LOG(("Failed to launch elevated update!"))do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to launch elevated update!"
); } } while (0)
;
687 exit(1);
688 }
689 exit(0);
690 }
691}
692
693if (isStaged) {
694 // Launch the updater to replace the installation with the staged updated.
695 LaunchChildMac(argc, argv);
696} else {
697 // Launch the updater to either stage or apply an update.
698 LaunchChildMac(argc, argv, outpid);
699}
700#else
701if (isStaged) {
702 // Launch the updater to replace the installation with the staged updated.
703 PR_CreateProcessDetached(updaterPath.get(), argv, nullptr, nullptr);
704} else {
705 // Launch the updater to either stage or apply an update.
706 *outpid = PR_CreateProcess(updaterPath.get(), argv, nullptr, nullptr);
707}
708#endif
709 free(argv);
710 if (restart) {
711 exit(0);
712 }
713}
714
715#if !defined(XP_WIN)
716/**
717 * Wait briefly to see if a process terminates, then return true if it has.
718 *
719 * (Not implemented on Windows, where HandleWatcher is used instead.)
720 */
721static bool ProcessHasTerminated(ProcessType pt) {
722# if defined(XP_MACOSX)
723 // We're waiting for the process to terminate in LaunchChildMac.
724 return true;
725# elif defined(XP_UNIX1)
726 int exitStatus;
727 pid_t exited = waitpid(pt, &exitStatus, WNOHANG1);
728 if (exited == 0) {
729 // Process is still running.
730 sleep(1);
731 return false;
732 }
733 if (exited == -1) {
734 LOG(("Error while checking if the updater process is finished"))do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Error while checking if the updater process is finished"
); } } while (0)
;
735 // This shouldn't happen, but if it does, the updater process is lost to us,
736 // so the best we can do is pretend that it's exited.
737 return true;
738 }
739 // If we get here, the process has exited; make sure it exited normally.
740 if (WIFEXITED(exitStatus)(((exitStatus) & 0x7f) == 0) && (WEXITSTATUS(exitStatus)(((exitStatus) & 0xff00) >> 8) != 0)) {
741 LOG(("Error while running the updater process, check update.log"))do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Error while running the updater process, check update.log"
); } } while (0)
;
742 }
743 return true;
744# else
745 // No way to have a non-blocking implementation on these platforms,
746 // because we're using NSPR and it only provides a blocking wait.
747 int32_t exitCode;
748 PR_WaitProcess(pt, &exitCode);
749 if (exitCode != 0) {
750 LOG(("Error while running the updater process, check update.log"))do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Error while running the updater process, check update.log"
); } } while (0)
;
751 }
752 return true;
753# endif
754}
755#endif
756
757nsresult ProcessUpdates(nsIFile* greDir, nsIFile* appDir, nsIFile* updRootDir,
758 int argc, char** argv, const char* appVersion,
759 bool restart, ProcessType* pid) {
760 nsresult rv;
761
762#ifdef XP_WIN
763 // If we're in a package, we know any updates that we find are not for us.
764 if (mozilla::widget::WinUtils::HasPackageIdentity()) {
765 return NS_OK;
766 }
767#endif
768
769 nsCOMPtr<nsIFile> updatesDir;
770 rv = GetUpdatePatchDir(updRootDir, getter_AddRefs(updatesDir));
771 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 771); return rv; } } while (false)
;
772
773 // Return early since there isn't a valid update when the update application
774 // version file doesn't exist or if the update's application version is less
775 // than the current application version. The cleanup of the update will happen
776 // during post update processing in nsUpdateService.js.
777 nsCOMPtr<nsIFile> versionFile;
778 if (!GetVersionFile(updatesDir, versionFile) ||
779 IsOlderVersion(versionFile, appVersion)) {
780 return NS_OK;
781 }
782
783 nsCOMPtr<nsIFile> statusFile;
784 UpdateStatus status = GetUpdateStatus(updatesDir, statusFile);
785 switch (status) {
786 case ePendingUpdate:
787 case ePendingService: {
788 ApplyUpdate(greDir, updatesDir, appDir, argc, argv, restart, false, pid);
789 break;
790 }
791 case eAppliedUpdate:
792 case eAppliedService:
793 // An update was staged and needs to be switched so the updated
794 // application is used.
795 ApplyUpdate(greDir, updatesDir, appDir, argc, argv, restart, true, pid);
796 break;
797 case ePendingElevate:
798 // No action should be performed since the user hasn't opted into
799 // elevating for the update so continue application startup.
800 case eNoUpdateAction:
801 // We don't need to do any special processing here, we'll just continue to
802 // startup the application.
803 break;
804 }
805
806 return NS_OK;
807}
808
809NS_IMPL_ISUPPORTS(nsUpdateProcessor, nsIUpdateProcessor)MozExternalRefCountType nsUpdateProcessor::AddRef(void) { static_assert
(!std::is_destructible_v<nsUpdateProcessor>, "Reference-counted class "
"nsUpdateProcessor" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 809); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
809; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsUpdateProcessor" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("nsUpdateProcessor" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"nsUpdateProcessor\" != nullptr" " (" "Must specify a name"
")", "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 809); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsUpdateProcessor\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 809; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("nsUpdateProcessor" " not thread-safe"); nsrefcnt
count = ++mRefCnt; NS_LogAddRef((this), (count), ("nsUpdateProcessor"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
nsUpdateProcessor::Release(void) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(int32_t(mRefCnt)
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 809); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 809
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsUpdateProcessor" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("nsUpdateProcessor" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"nsUpdateProcessor\" != nullptr" " (" "Must specify a name"
")", "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 809); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsUpdateProcessor\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 809; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("nsUpdateProcessor" " not thread-safe"); const
char* const nametmp = "nsUpdateProcessor"; nsrefcnt count = --
mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (count
== 0) { mRefCnt = 1; delete (this); return 0; } return count
; } nsresult nsUpdateProcessor::QueryInterface(const nsIID&
aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 809); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<nsUpdateProcessor, nsIUpdateProcessor>
, int32_t( reinterpret_cast<char*>(static_cast<nsIUpdateProcessor
*>((nsUpdateProcessor*)0x1000)) - reinterpret_cast<char
*>((nsUpdateProcessor*)0x1000))}, {&mozilla::detail::kImplementedIID
<nsUpdateProcessor, nsISupports>, int32_t(reinterpret_cast
<char*>(static_cast<nsISupports*>( static_cast<
nsIUpdateProcessor*>((nsUpdateProcessor*)0x1000))) - reinterpret_cast
<char*>((nsUpdateProcessor*)0x1000))}, { nullptr, 0 } }
; static_assert(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
810
811nsUpdateProcessor::nsUpdateProcessor() : mUpdaterPID(0) {}
812
813#ifdef XP_WIN
814nsUpdateProcessor::~nsUpdateProcessor() { mProcessWatcher.Stop(); }
815#else
816nsUpdateProcessor::~nsUpdateProcessor() = default;
817#endif
818
819NS_IMETHODIMPnsresult
820nsUpdateProcessor::ProcessUpdate() {
821 nsresult rv;
822
823 nsCOMPtr<nsIProperties> ds =
824 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID"@mozilla.org/file/directory_service;1", &rv);
825 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 825); return rv; } } while (false)
;
826
827 nsCOMPtr<nsIFile> exeFile;
828 rv = ds->Get(XRE_EXECUTABLE_FILE"XREExeF", NS_GET_IID(nsIFile)(nsIFile::COMTypeInfo<nsIFile, void>::kIID),
829 getter_AddRefs(exeFile));
830 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 830); return rv; } } while (false)
;
831
832 nsCOMPtr<nsIFile> appDir;
833 rv = exeFile->GetParent(getter_AddRefs(appDir));
834 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 834); return rv; } } while (false)
;
835
836 nsCOMPtr<nsIFile> greDir;
837 rv = ds->Get(NS_GRE_DIR"GreD", NS_GET_IID(nsIFile)(nsIFile::COMTypeInfo<nsIFile, void>::kIID), getter_AddRefs(greDir));
838 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 838); return rv; } } while (false)
;
839
840 nsCOMPtr<nsIFile> updRoot;
841 rv = ds->Get(XRE_UPDATE_ROOT_DIR"UpdRootD", NS_GET_IID(nsIFile)(nsIFile::COMTypeInfo<nsIFile, void>::kIID),
842 getter_AddRefs(updRoot));
843 NS_ASSERTION(NS_SUCCEEDED(rv), "Can't get the UpdRootD dir")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Can't get the UpdRootD dir"
, "NS_SUCCEEDED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 843); MOZ_PretendNoReturn(); } } while (0)
;
844
845 // XRE_UPDATE_ROOT_DIR should not fail but if it does fallback to the
846 // application directory just to be safe.
847 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
848 rv = appDir->Clone(getter_AddRefs(updRoot));
849 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 849); return rv; } } while (false)
;
850 }
851
852 nsCOMPtr<nsIXULAppInfo> appInfo =
853 do_GetService("@mozilla.org/xre/app-info;1", &rv);
854 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 854); return rv; } } while (false)
;
855
856 nsAutoCString appVersion;
857 rv = appInfo->GetVersion(appVersion);
858 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 858); return rv; } } while (false)
;
859
860 // Copy the parameters to the StagedUpdateInfo structure shared with the
861 // worker thread.
862 mInfo.mGREDir = greDir;
863 mInfo.mAppDir = appDir;
864 mInfo.mUpdateRoot = updRoot;
865 mInfo.mArgc = 0;
866 mInfo.mArgv = nullptr;
867 mInfo.mAppVersion = appVersion;
868
869 MOZ_ASSERT(NS_IsMainThread(), "not main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "not main thread" ")", "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 869); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { *((volatile int*)__null) =
869; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false)
;
870 nsCOMPtr<nsIRunnable> r =
871 NewRunnableMethod("nsUpdateProcessor::StartStagedUpdate", this,
872 &nsUpdateProcessor::StartStagedUpdate);
873 return NS_NewNamedThread("UpdateProcessor", getter_AddRefs(mWorkerThread), r);
874}
875
876void nsUpdateProcessor::StartStagedUpdate() {
877 MOZ_ASSERT(!NS_IsMainThread(), "main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!NS_IsMainThread()"
" (" "main thread" ")", "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!NS_IsMainThread()"
") (" "main thread" ")"); do { *((volatile int*)__null) = 877
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
878
879 // If we fail to launch the updater process or its monitor for some reason, we
880 // need to shut down the worker thread, as there isn't anything more for us to
881 // do.
882 auto onExitStopThread = mozilla::MakeScopeExit([&] {
883 nsresult rv = NS_DispatchToMainThread(
884 NewRunnableMethod("nsUpdateProcessor::ShutdownWorkerThread", this,
885 &nsUpdateProcessor::ShutdownWorkerThread));
886 NS_ENSURE_SUCCESS_VOID(rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS_VOID(%s) failed with "
"result 0x%" "X" "%s%s%s", "rv", static_cast<uint32_t>
(__rv), name ? " (" : "", name ? name : "", name ? ")" : "");
NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 886); return; } } while (false)
;
887 });
888
889 // Launch updater. (We do this on a worker thread to avoid blocking the main
890 // thread with file I/O.)
891 nsresult rv = ProcessUpdates(mInfo.mGREDir, mInfo.mAppDir, mInfo.mUpdateRoot,
892 mInfo.mArgc, mInfo.mArgv,
893 mInfo.mAppVersion.get(), false, &mUpdaterPID);
894 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
895 MOZ_LOG(sUpdateLog, mozilla::LogLevel::Error,do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Error)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Error, "could not start updater process: %s"
, GetStaticErrorName(rv)); } } while (0)
896 ("could not start updater process: %s", GetStaticErrorName(rv)))do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Error)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Error, "could not start updater process: %s"
, GetStaticErrorName(rv)); } } while (0)
;
897 return;
898 }
899
900 if (!mUpdaterPID) {
901 // not an error
902 MOZ_LOG(sUpdateLog, mozilla::LogLevel::Verbose,do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Verbose)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Verbose, "ProcessUpdates() indicated nothing to do"
); } } while (0)
903 ("ProcessUpdates() indicated nothing to do"))do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Verbose)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Verbose, "ProcessUpdates() indicated nothing to do"
); } } while (0)
;
904 return;
905 }
906
907#ifdef WIN32
908 // Set up a HandleWatcher to report to the main thread when we're done.
909 RefPtr<nsIThread> mainThread;
910 NS_GetMainThread(getter_AddRefs(mainThread));
911 mProcessWatcher.Watch(mUpdaterPID, mainThread,
912 NewRunnableMethod("nsUpdateProcessor::UpdateDone", this,
913 &nsUpdateProcessor::UpdateDone));
914
915// On Windows, that's all we need the worker thread for. Let
916// `onExitStopThread` shut us down.
917#else
918 // Monitor the state of the updater process while it is staging an update.
919 rv = NS_DispatchToCurrentThread(
920 NewRunnableMethod("nsUpdateProcessor::WaitForProcess", this,
921 &nsUpdateProcessor::WaitForProcess));
922 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
923 MOZ_LOG(sUpdateLog, mozilla::LogLevel::Error,do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Error)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Error, "could not start updater process poll: error %s"
, GetStaticErrorName(rv)); } } while (0)
924 ("could not start updater process poll: error %s",do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Error)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Error, "could not start updater process poll: error %s"
, GetStaticErrorName(rv)); } } while (0)
925 GetStaticErrorName(rv)))do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Error)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Error, "could not start updater process poll: error %s"
, GetStaticErrorName(rv)); } } while (0)
;
926 return;
927 }
928
929 // Leave the worker thread alive to run WaitForProcess. Either it or its
930 // successors will be responsible for shutting down the worker thread.
931 onExitStopThread.release();
932#endif
933}
934
935void nsUpdateProcessor::ShutdownWorkerThread() {
936 MOZ_ASSERT(NS_IsMainThread(), "not main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "not main thread" ")", "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 936); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { *((volatile int*)__null) =
936; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false)
;
937 mWorkerThread->Shutdown();
938 mWorkerThread = nullptr;
939}
940
941#ifndef WIN32
942void nsUpdateProcessor::WaitForProcess() {
943 MOZ_ASSERT(!NS_IsMainThread(), "main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!NS_IsMainThread()"
" (" "main thread" ")", "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 943); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!NS_IsMainThread()"
") (" "main thread" ")"); do { *((volatile int*)__null) = 943
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
944 if (ProcessHasTerminated(mUpdaterPID)) {
945 NS_DispatchToMainThread(NewRunnableMethod(
946 "nsUpdateProcessor::UpdateDone", this, &nsUpdateProcessor::UpdateDone));
947 } else {
948 NS_DispatchToCurrentThread(
949 NewRunnableMethod("nsUpdateProcessor::WaitForProcess", this,
950 &nsUpdateProcessor::WaitForProcess));
951 }
952}
953#endif
954
955void nsUpdateProcessor::UpdateDone() {
956 MOZ_ASSERT(NS_IsMainThread(), "not main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "not main thread" ")", "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 956); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { *((volatile int*)__null) =
956; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false)
;
957
958 nsCOMPtr<nsIUpdateManager> um =
959 do_GetService("@mozilla.org/updates/update-manager;1");
960 if (um) {
961 // This completes asynchronously, but nothing else that we are doing in this
962 // function requires waiting for this to complete.
963 RefPtr<mozilla::dom::Promise> outPromise;
964 um->RefreshUpdateStatus(getter_AddRefs(outPromise));
965 }
966
967// On Windows, shutting down the worker thread is taken care of by another task.
968// (Which may not have run yet, so we can't assert.)
969#ifndef XP_WIN
970 ShutdownWorkerThread();
971#endif
972}
973
974NS_IMETHODIMPnsresult
975nsUpdateProcessor::GetServiceRegKeyExists(bool* aResult) {
976#ifndef XP_WIN
977 return NS_ERROR_NOT_IMPLEMENTED;
978#else // #ifdef XP_WIN
979 nsCOMPtr<nsIProperties> dirSvc(
980 do_GetService("@mozilla.org/file/directory_service;1"));
981 NS_ENSURE_TRUE(dirSvc, NS_ERROR_SERVICE_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(dirSvc)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "dirSvc" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 981); return NS_ERROR_SERVICE_NOT_AVAILABLE; } } while (false
)
;
982
983 nsCOMPtr<nsIFile> installBin;
984 nsresult rv = dirSvc->Get(XRE_EXECUTABLE_FILE"XREExeF", NS_GET_IID(nsIFile)(nsIFile::COMTypeInfo<nsIFile, void>::kIID),
985 getter_AddRefs(installBin));
986 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 986); return rv; } } while (false)
;
987
988 nsCOMPtr<nsIFile> installDir;
989 rv = installBin->GetParent(getter_AddRefs(installDir));
990 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 990); return rv; } } while (false)
;
991
992 nsAutoString installPath;
993 rv = installDir->GetPath(installPath);
994 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 994); return rv; } } while (false)
;
995
996 wchar_t maintenanceServiceKey[MAX_PATH + 1];
997 BOOL success = CalculateRegistryPathFromFilePath(
998 PromiseFlatStringTPromiseFlatString<char16_t>(installPath).get(), maintenanceServiceKey);
999 NS_ENSURE_TRUE(success, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(success)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "success" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre/nsUpdateDriver.cpp"
, 999); return NS_ERROR_FAILURE; } } while (false)
;
1000
1001 HKEY regHandle;
1002 LSTATUS ls = RegOpenKeyExW(HKEY_LOCAL_MACHINE, maintenanceServiceKey, 0,
1003 KEY_QUERY_VALUE | KEY_WOW64_64KEY, &regHandle);
1004 if (ls == ERROR_SUCCESS) {
1005 RegCloseKey(regHandle);
1006 *aResult = true;
1007 return NS_OK;
1008 }
1009 if (ls == ERROR_FILE_NOT_FOUND) {
1010 *aResult = false;
1011 return NS_OK;
1012 }
1013 // We got an error we weren't expecting reading the registry.
1014 return NS_ERROR_NOT_AVAILABLE;
1015#endif // #ifdef XP_WIN
1016}
1017
1018NS_IMETHODIMPnsresult
1019nsUpdateProcessor::AttemptAutomaticApplicationRestartWithLaunchArgs(
1020 const nsTArray<nsString>& argvExtra, int32_t* pidRet) {
1021#ifndef XP_WIN
1022 return NS_ERROR_NOT_IMPLEMENTED;
1023#else
1024 // Retrieve current command line arguments for restart
1025 // GetCommandLineW() returns a read only pointer to
1026 // the arguments the process was launched with.
1027 LPWSTR currentCommandLine = GetCommandLineW();
1028
1029 // Spawn a new process for the application based on the current
1030 // command line with the -restart-pid <pid> flag. This flag
1031 // can be used with MaybeWaitForProcessExit() to have
1032 // the process wait until the parent process has exited.
1033 if (currentCommandLine) {
1034 // Append additional command line arguments to current command line for
1035 // restart.
1036 int currentArgc = 0;
1037 UniquePtr<LPWSTR, LocalFreeDeleter> currentArgv(
1038 CommandLineToArgvW(currentCommandLine, &currentArgc));
1039 nsTArray<wchar_t*> restartCommandLineArgv(currentArgc + argvExtra.Length() +
1040 2);
1041 for (int i = 0; i < currentArgc; i++) {
1042 restartCommandLineArgv.AppendElement(currentArgv.get()[i]);
1043 }
1044 for (const nsString& arg : argvExtra) {
1045 restartCommandLineArgv.AppendElement(static_cast<wchar_t*>(arg.get()));
1046 }
1047 // Append -restart-pid flag and pid to restart command line.
1048 DWORD pidCurrent = GetCurrentProcessId();
1049 nsString pid;
1050 pid.AppendInt(static_cast<uint32_t>(pidCurrent));
1051 nsString pidFlag = u"-restart-pid"_ns;
1052 restartCommandLineArgv.AppendElement(pidFlag.get());
1053 restartCommandLineArgv.AppendElement(pid.get());
1054
1055 // Create new process that interacts with MaybeWaitForProcessExit()
1056 // and sleeps until the original process is killed.
1057 wchar_t exeName[MAX_PATH];
1058 GetModuleFileNameW(NULL__null, exeName, MAX_PATH);
1059 HANDLE childHandle;
1060 WinLaunchChild(exeName, restartCommandLineArgv.Length(),
1061 restartCommandLineArgv.Elements(), nullptr, &childHandle);
1062 *pidRet = GetProcessId(childHandle);
1063 CloseHandle(childHandle);
1064 if (!*pidRet) {
1065 printf_stderr("*** ApplyUpdate: !pidRet ***\n");
1066 return NS_ERROR_ABORT;
1067 }
1068 printf_stderr("*** ApplyUpdate: launched pidRet = %d ***\n", *pidRet);
1069
1070 MOZ_LOG(sUpdateLog, mozilla::LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "register application restart succeeded"
); } } while (0)
1071 ("register application restart succeeded"))do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "register application restart succeeded"
); } } while (0)
;
1072 } else {
1073 MOZ_LOG(sUpdateLog, mozilla::LogLevel::Error,do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Error)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Error, "could not register application restart"
); } } while (0)
1074 ("could not register application restart"))do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Error)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Error, "could not register application restart"
); } } while (0)
;
1075 return NS_ERROR_NOT_AVAILABLE;
1076 }
1077 return NS_OK;
1078#endif // #ifndef XP_WIN
1079}
1080
1081NS_IMETHODIMPnsresult
1082nsUpdateProcessor::WaitForProcessExit(uint32_t pid, uint32_t timeoutMS) {
1083#ifndef XP_WIN
1084 return NS_ERROR_NOT_IMPLEMENTED;
1085#else
1086
1087 nsAutoHandle hProcess(OpenProcess(SYNCHRONIZE, FALSE(0), pid));
1088 if (!hProcess) {
1089 // It's possible the pid is incorrect, or the process has exited.
1090 // This isn't necessarily a failure state as if the process has
1091 // already exited then that is the desired behavior.
1092 MOZ_LOG(sUpdateLog, mozilla::LogLevel::Warning,do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Warning)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Warning, "WaitForProcessExit(%d): failed to OpenProcess"
, pid); } } while (0)
1093 ("WaitForProcessExit(%d): failed to OpenProcess", pid))do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Warning)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Warning, "WaitForProcessExit(%d): failed to OpenProcess"
, pid); } } while (0)
;
1094 return NS_OK;
1095 }
1096
1097 // Wait up to timeoutMS milliseconds for termination.
1098 DWORD waitRv = WaitForSingleObjectEx(hProcess, timeoutMS, FALSE(0));
1099 if (waitRv != WAIT_OBJECT_0) {
1100 if (waitRv == WAIT_TIMEOUT) {
1101 MOZ_LOG(do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "WaitForProcessExit(%d): timed out after %d MS"
, pid, timeoutMS); } } while (0)
1102 sUpdateLog, mozilla::LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "WaitForProcessExit(%d): timed out after %d MS"
, pid, timeoutMS); } } while (0)
1103 ("WaitForProcessExit(%d): timed out after %d MS", pid, timeoutMS))do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "WaitForProcessExit(%d): timed out after %d MS"
, pid, timeoutMS); } } while (0)
;
1104 return NS_ERROR_ABORT;
1105 }
1106
1107 MOZ_LOG(sUpdateLog, mozilla::LogLevel::Warning,do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Warning)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Warning, "WaitForProcessExit(%d): unexpected error %lx"
, pid, waitRv); } } while (0)
1108 ("WaitForProcessExit(%d): unexpected error %lx", pid, waitRv))do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Warning)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Warning, "WaitForProcessExit(%d): unexpected error %lx"
, pid, waitRv); } } while (0)
;
1109 return NS_ERROR_FAILURE;
1110 }
1111
1112 MOZ_LOG(sUpdateLog, mozilla::LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "WaitForProcessExit(%d): success"
, pid); } } while (0)
1113 ("WaitForProcessExit(%d): success", pid))do { const ::mozilla::LogModule* moz_real_module = sUpdateLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "WaitForProcessExit(%d): success"
, pid); } } while (0)
;
1114 return NS_OK;
1115#endif // XP_WIN
1116}