| File: | root/firefox-clang/third_party/zucchini/moz_zucchini.cc |
| Warning: | line 75, column 3 Potential leak of memory pointed to by 'allocation' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | |||
| 2 | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ | |||
| 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 "mozilla/moz_zucchini.h" | |||
| 8 | ||||
| 9 | #include "absl/types/optional.h" | |||
| 10 | #include "base/logging.h" | |||
| 11 | #include "base/files/file.h" | |||
| 12 | #include "base/files/file_util.h" | |||
| 13 | #include "build/build_config.h" | |||
| 14 | #include "components/zucchini/crc32.h" | |||
| 15 | #include "components/zucchini/mapped_file.h" | |||
| 16 | #include "components/zucchini/patch_reader.h" | |||
| 17 | #include "components/zucchini/zucchini.h" | |||
| 18 | #include "components/zucchini/zucchini_apply.h" | |||
| 19 | ||||
| 20 | #include <cstdio> | |||
| 21 | #include <limits> | |||
| 22 | #include <memory> | |||
| 23 | #include <new> | |||
| 24 | #include <string> | |||
| 25 | ||||
| 26 | #if BUILDFLAG(IS_WIN)((0)) | |||
| 27 | // Get EXCEPTION_* constants defined with DWORD type | |||
| 28 | # include <ntstatus.h> | |||
| 29 | ||||
| 30 | # if defined(HAVE_SEH_EXCEPTIONS) | |||
| 31 | # include "components/zucchini/exception_filter_helper_win.h" | |||
| 32 | # endif // HAVE_SEH_EXCEPTIONS | |||
| 33 | ||||
| 34 | # include <io.h> | |||
| 35 | #endif // BUILDFLAG(IS_WIN) | |||
| 36 | ||||
| 37 | namespace zucchini::mozilla { | |||
| 38 | ||||
| 39 | #ifdef ENABLE_TESTS1 | |||
| 40 | // Helpers for crash test scenarios. | |||
| 41 | ||||
| 42 | static TestOptions gTestOptions; | |||
| 43 | ||||
| 44 | void SetTestOptions(const TestOptions& aTestOptions) { | |||
| 45 | gTestOptions = aTestOptions; | |||
| 46 | } | |||
| 47 | ||||
| 48 | // Test-only log to prove stack unwinding reaches local destructors when we | |||
| 49 | // recover from a fault originating from inside zucchini. | |||
| 50 | class ScopedDestructorMarker { | |||
| 51 | public: | |||
| 52 | ScopedDestructorMarker() = default; | |||
| 53 | ||||
| 54 | ~ScopedDestructorMarker() { | |||
| 55 | if (!gTestOptions.logDestructorMarker) { | |||
| 56 | return; | |||
| 57 | } | |||
| 58 | ||||
| 59 | LOG(ERROR)!((::logging::ShouldCreateLogMessage(::logging::LOGGING_ERROR ))) ? (void) 0 : ::logging::LogMessageVoidify() & (::logging ::LogMessage("/root/firefox-clang/third_party/zucchini/moz_zucchini.cc" , 59, ::logging::LOGGING_ERROR).stream()) << "MOZ_TEST_ZUCCHINI_DTOR_MARKER"; | |||
| 60 | } | |||
| 61 | }; | |||
| 62 | ||||
| 63 | // Test-only OOM injection used by updater tests to verify that a thrown | |||
| 64 | // bad_alloc is translated into kStatusOutOfMemory. | |||
| 65 | static void MaybeTriggerTestBadAlloc() { | |||
| 66 | if (!gTestOptions.triggerBadAlloc) { | |||
| 67 | return; | |||
| 68 | } | |||
| 69 | ||||
| 70 | // This allocation is expected to throw std::bad_alloc. volatile prevents | |||
| 71 | // the compiler from optimizing it away. If it somehow succeeded, CHECK(false) | |||
| 72 | // ensures the test fails visibly rather than silently passing. | |||
| 73 | void* volatile allocation = ::operator new(std::numeric_limits<size_t>::max()); | |||
| 74 | (void)allocation; | |||
| 75 | CHECK(false)switch (0) case 0: default: if (const bool probably_true = static_cast <bool>(false); __builtin_expect(!!(::AnalyzerAssumeTrue (!!(probably_true))), 1)) ; else (::logging::CheckError::Check ("false")); | |||
| ||||
| 76 | } | |||
| 77 | ||||
| 78 | // Test-only CHECK() injection used by updater tests to verify that deliberate | |||
| 79 | // crash paths are converted into kStatusFatal. | |||
| 80 | static void MaybeTriggerTestCheckFailure() { | |||
| 81 | if (!gTestOptions.triggerCheckFailure) { | |||
| 82 | return; | |||
| 83 | } | |||
| 84 | ||||
| 85 | CHECK(false)switch (0) case 0: default: if (const bool probably_true = static_cast <bool>(false); __builtin_expect(!!(::AnalyzerAssumeTrue (!!(probably_true))), 1)) ; else (::logging::CheckError::Check ("false")); | |||
| 86 | } | |||
| 87 | ||||
| 88 | // Test-only injection of the exception that Windows raises when accessing a | |||
| 89 | // mapped file fails, used by updater tests to verify that we recover from it | |||
| 90 | // and release the mapped files. Writes fail because the disk is full, reads | |||
| 91 | // because of a device error. | |||
| 92 | static void MaybeTriggerTestPageError(bool aTrigger, const uint8_t* aAddress, | |||
| 93 | bool aIsWrite) { | |||
| 94 | if (!aTrigger) { | |||
| 95 | return; | |||
| 96 | } | |||
| 97 | ||||
| 98 | # if BUILDFLAG(IS_WIN)((0)) && defined(HAVE_SEH_EXCEPTIONS) | |||
| 99 | const ULONG_PTR info[3] = { | |||
| 100 | aIsWrite, reinterpret_cast<ULONG_PTR>(aAddress), | |||
| 101 | static_cast<ULONG_PTR>(aIsWrite ? STATUS_DISK_FULL | |||
| 102 | : STATUS_DEVICE_DATA_ERROR)}; | |||
| 103 | ::RaiseException(EXCEPTION_IN_PAGE_ERROR, 0, 3, info); | |||
| 104 | # endif // BUILDFLAG(IS_WIN) && HAVE_SEH_EXCEPTIONS | |||
| 105 | } | |||
| 106 | #endif // ENABLE_TESTS | |||
| 107 | ||||
| 108 | static LogFunctionPtr gLogFunction = nullptr; | |||
| 109 | ||||
| 110 | static bool LogMessageHandler(int aSeverity, const char* aFile, int aLine, | |||
| 111 | size_t aMessageStart, const std::string& aStr) { | |||
| 112 | if (!gLogFunction) { | |||
| 113 | return false; | |||
| 114 | } | |||
| 115 | gLogFunction(aStr.c_str()); | |||
| 116 | return true; | |||
| 117 | } | |||
| 118 | ||||
| 119 | void SetLogFunction(LogFunctionPtr aLogFunction) { | |||
| 120 | gLogFunction = aLogFunction; | |||
| 121 | logging::SetLogMessageHandler(LogMessageHandler); | |||
| 122 | } | |||
| 123 | ||||
| 124 | #if !defined(__cpp_exceptions199711L) | |||
| 125 | # error The zucchini interface code requires compiler support for C++ exceptions. | |||
| 126 | #endif // !cpp_exceptions | |||
| 127 | ||||
| 128 | ||||
| 129 | // Catch C++ exceptions raised within zucchini code. This lets the updater | |||
| 130 | // recover from standard library allocation failures, so it can write an OOM | |||
| 131 | // update.status and run post-failure cleanup. We wrap the entire body of | |||
| 132 | // every entry point reachable from updater.cpp, making sure we cover all the | |||
| 133 | // zucchini code it uses. | |||
| 134 | // | |||
| 135 | // Every entry point into zucchini thus returns a status code. Running into a | |||
| 136 | // C++ std::bad_alloc exception returns kStatusOutOfMemory. Any other C++ | |||
| 137 | // exception results in kStatusFatal, although that should never happen. | |||
| 138 | ||||
| 139 | #define BEGIN_ENTRY_POINT()try { try { | |||
| 140 | #define END_ENTRY_POINT()} catch (const std::bad_alloc&) { !((::logging::ShouldCreateLogMessage (::logging::LOGGING_ERROR))) ? (void) 0 : ::logging::LogMessageVoidify () & (::logging::LogMessage("/root/firefox-clang/third_party/zucchini/moz_zucchini.cc" , 140, ::logging::LOGGING_ERROR).stream()) << "std::bad_alloc caught in zucchini." ; return status::kStatusOutOfMemory; } catch (...) { !((::logging ::ShouldCreateLogMessage(::logging::LOGGING_ERROR))) ? (void) 0 : ::logging::LogMessageVoidify() & (::logging::LogMessage ("/root/firefox-clang/third_party/zucchini/moz_zucchini.cc", 140 , ::logging::LOGGING_ERROR).stream()) << "unknown exception caught in zucchini; this is a bug." ; return status::kStatusFatal; } \ | |||
| 141 | } \ | |||
| 142 | catch (const std::bad_alloc&) { \ | |||
| 143 | LOG(ERROR)!((::logging::ShouldCreateLogMessage(::logging::LOGGING_ERROR ))) ? (void) 0 : ::logging::LogMessageVoidify() & (::logging ::LogMessage("/root/firefox-clang/third_party/zucchini/moz_zucchini.cc" , 143, ::logging::LOGGING_ERROR).stream()) << "std::bad_alloc caught in zucchini."; \ | |||
| 144 | return status::kStatusOutOfMemory; \ | |||
| 145 | } \ | |||
| 146 | catch (...) { \ | |||
| 147 | LOG(ERROR)!((::logging::ShouldCreateLogMessage(::logging::LOGGING_ERROR ))) ? (void) 0 : ::logging::LogMessageVoidify() & (::logging ::LogMessage("/root/firefox-clang/third_party/zucchini/moz_zucchini.cc" , 147, ::logging::LOGGING_ERROR).stream()) << "unknown exception caught in zucchini; this is a bug."; \ | |||
| 148 | return status::kStatusFatal; \ | |||
| 149 | } | |||
| 150 | ||||
| 151 | #if BUILDFLAG(IS_WIN)((0)) && defined(HAVE_SEH_EXCEPTIONS) | |||
| 152 | static status::Code PageErrorStatus(const ExceptionFilterHelper& aHelper) { | |||
| 153 | LOG(ERROR)!((::logging::ShouldCreateLogMessage(::logging::LOGGING_ERROR ))) ? (void) 0 : ::logging::LogMessageVoidify() & (::logging ::LogMessage("/root/firefox-clang/third_party/zucchini/moz_zucchini.cc" , 153, ::logging::LOGGING_ERROR).stream()) << "EXCEPTION_IN_PAGE_ERROR while " | |||
| 154 | << (aHelper.is_write() ? "writing to" : "reading from") | |||
| 155 | << " mapped files; NTSTATUS = " << aHelper.nt_status(); | |||
| 156 | return aHelper.nt_status() == STATUS_DISK_FULL ? status::kStatusDiskFull | |||
| 157 | : status::kStatusIoError; | |||
| 158 | } | |||
| 159 | ||||
| 160 | // Narrow handler that stays around the code touching the mapped file ranges, | |||
| 161 | // where EXCEPTION_IN_PAGE_ERROR can be raised. Usable only within member | |||
| 162 | // functions, as it relies on mImpl. This reflects the exception catching | |||
| 163 | // present in upstream zucchini::ApplyCommon (zucchini_integration.cc). | |||
| 164 | // Objects that need unwinding must live outside of aFunc: the unwinding that | |||
| 165 | // follows an EXCEPTION_IN_PAGE_ERROR doesn't run their destructors. | |||
| 166 | template <typename F> | |||
| 167 | static status::Code GuardPageErrors(ExceptionFilterHelper& aHelper, F& aFunc) { | |||
| 168 | __trytry { | |||
| 169 | return aFunc(); | |||
| 170 | } __except ( | |||
| 171 | aHelper.FilterPageError(GetExceptionInformation()->ExceptionRecord)) { | |||
| 172 | return PageErrorStatus(aHelper); | |||
| 173 | } | |||
| 174 | } | |||
| 175 | # define GUARD_PAGE_ERRORS(aFunc)aFunc() \ | |||
| 176 | GuardPageErrors(mImpl->mExceptionFilterHelper, aFunc) | |||
| 177 | #else | |||
| 178 | # define GUARD_PAGE_ERRORS(aFunc)aFunc() aFunc() | |||
| 179 | #endif // BUILDFLAG(IS_WIN) && HAVE_SEH_EXCEPTIONS | |||
| 180 | ||||
| 181 | status::Code ComputeCrc32(const uint8_t* aBuf, size_t aBufSize, | |||
| 182 | uint32_t& aOutCrc32) { | |||
| 183 | BEGIN_ENTRY_POINT()try { | |||
| 184 | aOutCrc32 = CalculateCrc32(aBuf, aBuf + aBufSize); | |||
| 185 | return status::kStatusSuccess; | |||
| 186 | END_ENTRY_POINT()} catch (const std::bad_alloc&) { !((::logging::ShouldCreateLogMessage (::logging::LOGGING_ERROR))) ? (void) 0 : ::logging::LogMessageVoidify () & (::logging::LogMessage("/root/firefox-clang/third_party/zucchini/moz_zucchini.cc" , 186, ::logging::LOGGING_ERROR).stream()) << "std::bad_alloc caught in zucchini." ; return status::kStatusOutOfMemory; } catch (...) { !((::logging ::ShouldCreateLogMessage(::logging::LOGGING_ERROR))) ? (void) 0 : ::logging::LogMessageVoidify() & (::logging::LogMessage ("/root/firefox-clang/third_party/zucchini/moz_zucchini.cc", 186 , ::logging::LOGGING_ERROR).stream()) << "unknown exception caught in zucchini; this is a bug." ; return status::kStatusFatal; } | |||
| 187 | } | |||
| 188 | ||||
| 189 | class MappedPatchImpl { | |||
| 190 | public: | |||
| 191 | MappedPatchImpl() = default; | |||
| 192 | ~MappedPatchImpl() = default; | |||
| 193 | std::optional<MappedFileReader> mFileReader; | |||
| 194 | EnsemblePatchReader mPatchReader; | |||
| 195 | #if BUILDFLAG(IS_WIN)((0)) && defined(HAVE_SEH_EXCEPTIONS) | |||
| 196 | ExceptionFilterHelper mExceptionFilterHelper; | |||
| 197 | #endif // BUILDFLAG(IS_WIN) && HAVE_SEH_EXCEPTIONS | |||
| 198 | }; | |||
| 199 | ||||
| 200 | status::Code MappedPatch::Initialize() { | |||
| 201 | BEGIN_ENTRY_POINT()try { | |||
| 202 | mImpl = new MappedPatchImpl(); | |||
| 203 | return status::kStatusSuccess; | |||
| 204 | END_ENTRY_POINT()} catch (const std::bad_alloc&) { !((::logging::ShouldCreateLogMessage (::logging::LOGGING_ERROR))) ? (void) 0 : ::logging::LogMessageVoidify () & (::logging::LogMessage("/root/firefox-clang/third_party/zucchini/moz_zucchini.cc" , 204, ::logging::LOGGING_ERROR).stream()) << "std::bad_alloc caught in zucchini." ; return status::kStatusOutOfMemory; } catch (...) { !((::logging ::ShouldCreateLogMessage(::logging::LOGGING_ERROR))) ? (void) 0 : ::logging::LogMessageVoidify() & (::logging::LogMessage ("/root/firefox-clang/third_party/zucchini/moz_zucchini.cc", 204 , ::logging::LOGGING_ERROR).stream()) << "unknown exception caught in zucchini; this is a bug." ; return status::kStatusFatal; } | |||
| 205 | } | |||
| 206 | ||||
| 207 | status::Code MappedPatch::Finalize() { | |||
| 208 | BEGIN_ENTRY_POINT()try { | |||
| 209 | auto* impl = mImpl; | |||
| 210 | mImpl = nullptr; | |||
| 211 | delete impl; | |||
| 212 | return status::kStatusSuccess; | |||
| 213 | END_ENTRY_POINT()} catch (const std::bad_alloc&) { !((::logging::ShouldCreateLogMessage (::logging::LOGGING_ERROR))) ? (void) 0 : ::logging::LogMessageVoidify () & (::logging::LogMessage("/root/firefox-clang/third_party/zucchini/moz_zucchini.cc" , 213, ::logging::LOGGING_ERROR).stream()) << "std::bad_alloc caught in zucchini." ; return status::kStatusOutOfMemory; } catch (...) { !((::logging ::ShouldCreateLogMessage(::logging::LOGGING_ERROR))) ? (void) 0 : ::logging::LogMessageVoidify() & (::logging::LogMessage ("/root/firefox-clang/third_party/zucchini/moz_zucchini.cc", 213 , ::logging::LOGGING_ERROR).stream()) << "unknown exception caught in zucchini; this is a bug." ; return status::kStatusFatal; } | |||
| 214 | } | |||
| 215 | ||||
| 216 | // This corresponds to the first half of zucchini::ApplyCommon. | |||
| 217 | status::Code MappedPatch::LoadImpl(FILE* aPatchFile, uint32_t* aSourceSize, | |||
| 218 | uint32_t* aDestinationSize, | |||
| 219 | uint32_t* aSourceCrc32) { | |||
| 220 | base::File patchFile = base::FILEToFile(aPatchFile); | |||
| 221 | if (!patchFile.IsValid()) { | |||
| 222 | LOG(ERROR)!((::logging::ShouldCreateLogMessage(::logging::LOGGING_ERROR ))) ? (void) 0 : ::logging::LogMessageVoidify() & (::logging ::LogMessage("/root/firefox-clang/third_party/zucchini/moz_zucchini.cc" , 222, ::logging::LOGGING_ERROR).stream()) << "Invalid patch file."; | |||
| 223 | return status::kStatusFileReadError; | |||
| 224 | } | |||
| 225 | mImpl->mFileReader.emplace(std::move(patchFile)); | |||
| 226 | auto& fileReader = *mImpl->mFileReader; | |||
| 227 | if (fileReader.HasError()) { | |||
| 228 | LOG(ERROR)!((::logging::ShouldCreateLogMessage(::logging::LOGGING_ERROR ))) ? (void) 0 : ::logging::LogMessageVoidify() & (::logging ::LogMessage("/root/firefox-clang/third_party/zucchini/moz_zucchini.cc" , 228, ::logging::LOGGING_ERROR).stream()) << "Error with patch file: " << fileReader.error(); | |||
| 229 | if (fileReader.error_is_oom()) { | |||
| 230 | return status::kStatusOutOfMemory; | |||
| 231 | } | |||
| 232 | return status::kStatusFileReadError; | |||
| 233 | } | |||
| 234 | #if BUILDFLAG(IS_WIN)((0)) && defined(HAVE_SEH_EXCEPTIONS) | |||
| 235 | mImpl->mExceptionFilterHelper.AddRange( | |||
| 236 | {fileReader.data(), fileReader.length()}); | |||
| 237 | #endif // BUILDFLAG(IS_WIN) && HAVE_SEH_EXCEPTIONS | |||
| 238 | auto readHeader = [&]() { | |||
| 239 | #ifdef ENABLE_TESTS1 | |||
| 240 | MaybeTriggerTestPageError(gTestOptions.triggerReadPageError, | |||
| 241 | fileReader.data(), /* aIsWrite */ false); | |||
| 242 | #endif // ENABLE_TESTS | |||
| 243 | BufferSource source(fileReader.region()); | |||
| 244 | auto& patchReader = mImpl->mPatchReader; | |||
| 245 | if (!patchReader.Initialize(&source)) { | |||
| 246 | LOG(ERROR)!((::logging::ShouldCreateLogMessage(::logging::LOGGING_ERROR ))) ? (void) 0 : ::logging::LogMessageVoidify() & (::logging ::LogMessage("/root/firefox-clang/third_party/zucchini/moz_zucchini.cc" , 246, ::logging::LOGGING_ERROR).stream()) << "Error reading patch header."; | |||
| 247 | return status::kStatusPatchReadError; | |||
| 248 | } | |||
| 249 | auto& header = patchReader.header(); | |||
| 250 | *aSourceSize = header.old_size; | |||
| 251 | *aDestinationSize = header.new_size; | |||
| 252 | *aSourceCrc32 = header.old_crc; | |||
| 253 | return status::kStatusSuccess; | |||
| 254 | }; | |||
| 255 | return GUARD_PAGE_ERRORS(readHeader)readHeader(); | |||
| 256 | } | |||
| 257 | ||||
| 258 | status::Code MappedPatch::Load(FILE* aPatchFile, uint32_t* aSourceSize, | |||
| 259 | uint32_t* aDestinationSize, | |||
| 260 | uint32_t* aSourceCrc32) { | |||
| 261 | if (!mImpl) { | |||
| 262 | return mInitStatus; | |||
| 263 | } | |||
| 264 | BEGIN_ENTRY_POINT()try { | |||
| 265 | return LoadImpl(aPatchFile, aSourceSize, aDestinationSize, aSourceCrc32); | |||
| 266 | END_ENTRY_POINT()} catch (const std::bad_alloc&) { !((::logging::ShouldCreateLogMessage (::logging::LOGGING_ERROR))) ? (void) 0 : ::logging::LogMessageVoidify () & (::logging::LogMessage("/root/firefox-clang/third_party/zucchini/moz_zucchini.cc" , 266, ::logging::LOGGING_ERROR).stream()) << "std::bad_alloc caught in zucchini." ; return status::kStatusOutOfMemory; } catch (...) { !((::logging ::ShouldCreateLogMessage(::logging::LOGGING_ERROR))) ? (void) 0 : ::logging::LogMessageVoidify() & (::logging::LogMessage ("/root/firefox-clang/third_party/zucchini/moz_zucchini.cc", 266 , ::logging::LOGGING_ERROR).stream()) << "unknown exception caught in zucchini; this is a bug." ; return status::kStatusFatal; } | |||
| 267 | } | |||
| 268 | ||||
| 269 | // This is zucchini::ApplyBuffer, except that we *assume* that aCheckedOldImage | |||
| 270 | // has the correct size and crc32 instead of checking it. | |||
| 271 | static status::Code ApplyBufferUnsafe(ConstBufferView aCheckedOldImage, | |||
| 272 | const EnsemblePatchReader& aPatchReader, | |||
| 273 | MutableBufferView aNewImage) { | |||
| 274 | #ifdef ENABLE_TESTS1 | |||
| 275 | // We want updater tests to simulate zucchini failures occurring in the worst | |||
| 276 | // possible location from the updater recovery's point of view. Failing here | |||
| 277 | // simulates a failure in the middle of patch application, with the new image | |||
| 278 | // still open and mapped, which makes recovery quite subtle. | |||
| 279 | ScopedDestructorMarker destructorTester; | |||
| 280 | MaybeTriggerTestBadAlloc(); | |||
| 281 | MaybeTriggerTestCheckFailure(); | |||
| 282 | MaybeTriggerTestPageError(gTestOptions.triggerWritePageError, | |||
| 283 | aNewImage.begin(), /* aIsWrite */ true); | |||
| 284 | #endif // ENABLE_TESTS | |||
| 285 | ||||
| 286 | for (const auto& elementPatch : aPatchReader.elements()) { | |||
| 287 | ElementMatch match = elementPatch.element_match(); | |||
| 288 | if (!ApplyElement(match.exe_type(), | |||
| 289 | aCheckedOldImage[match.old_element.region()], | |||
| 290 | elementPatch, aNewImage[match.new_element.region()])) | |||
| 291 | return status::kStatusFatal; | |||
| 292 | } | |||
| 293 | ||||
| 294 | if (!aPatchReader.CheckNewFile(ConstBufferView(aNewImage))) { | |||
| 295 | LOG(ERROR)!((::logging::ShouldCreateLogMessage(::logging::LOGGING_ERROR ))) ? (void) 0 : ::logging::LogMessageVoidify() & (::logging ::LogMessage("/root/firefox-clang/third_party/zucchini/moz_zucchini.cc" , 295, ::logging::LOGGING_ERROR).stream()) << "Invalid aNewImage."; | |||
| 296 | return status::kStatusInvalidNewImage; | |||
| 297 | } | |||
| 298 | ||||
| 299 | return status::kStatusSuccess; | |||
| 300 | } | |||
| 301 | ||||
| 302 | // This corresponds to the second half of zucchini::ApplyCommon. | |||
| 303 | status::Code MappedPatch::ApplyUnsafeImpl(const uint8_t* aCheckedOldImage, | |||
| 304 | size_t aCheckedOldImageSize, | |||
| 305 | FILE* aNewFile) { | |||
| 306 | ConstBufferView oldImageView(aCheckedOldImage, aCheckedOldImageSize); | |||
| 307 | ||||
| 308 | base::File newFile = base::FILEToFile(aNewFile); | |||
| 309 | if (!newFile.IsValid()) { | |||
| 310 | LOG(ERROR)!((::logging::ShouldCreateLogMessage(::logging::LOGGING_ERROR ))) ? (void) 0 : ::logging::LogMessageVoidify() & (::logging ::LogMessage("/root/firefox-clang/third_party/zucchini/moz_zucchini.cc" , 310, ::logging::LOGGING_ERROR).stream()) << "Invalid new file."; | |||
| 311 | return status::kStatusFileWriteError; | |||
| 312 | } | |||
| 313 | ||||
| 314 | PatchHeader header = mImpl->mPatchReader.header(); | |||
| 315 | base::FilePath name = base::FilePath().AppendASCII("old_name"); | |||
| 316 | MappedFileWriter mappedNew(name, std::move(newFile), header.new_size, | |||
| 317 | /*keep*/ true); | |||
| 318 | if (mappedNew.HasError()) { | |||
| 319 | LOG(ERROR)!((::logging::ShouldCreateLogMessage(::logging::LOGGING_ERROR ))) ? (void) 0 : ::logging::LogMessageVoidify() & (::logging ::LogMessage("/root/firefox-clang/third_party/zucchini/moz_zucchini.cc" , 319, ::logging::LOGGING_ERROR).stream()) << "Error with new file: " << mappedNew.error(); | |||
| 320 | if (mappedNew.error_is_oom()) { | |||
| 321 | return status::kStatusOutOfMemory; | |||
| 322 | } | |||
| 323 | return status::kStatusFileWriteError; | |||
| 324 | } | |||
| 325 | ||||
| 326 | #if BUILDFLAG(IS_WIN)((0)) && defined(HAVE_SEH_EXCEPTIONS) | |||
| 327 | mImpl->mExceptionFilterHelper.AddRange( | |||
| 328 | {mappedNew.data(), mappedNew.length()}); | |||
| 329 | #endif // BUILDFLAG(IS_WIN) && HAVE_SEH_EXCEPTIONS | |||
| 330 | ||||
| 331 | auto applyToNewFile = [&]() { | |||
| 332 | status::Code result = ApplyBufferUnsafe(oldImageView, mImpl->mPatchReader, | |||
| 333 | mappedNew.region()); | |||
| 334 | if (result != status::kStatusSuccess) { | |||
| 335 | LOG(ERROR)!((::logging::ShouldCreateLogMessage(::logging::LOGGING_ERROR ))) ? (void) 0 : ::logging::LogMessageVoidify() & (::logging ::LogMessage("/root/firefox-clang/third_party/zucchini/moz_zucchini.cc" , 335, ::logging::LOGGING_ERROR).stream()) << "Fatal error encountered while applying patch."; | |||
| 336 | return result; | |||
| 337 | } | |||
| 338 | ||||
| 339 | if (!mappedNew.Flush()) { | |||
| 340 | LOG(ERROR)!((::logging::ShouldCreateLogMessage(::logging::LOGGING_ERROR ))) ? (void) 0 : ::logging::LogMessageVoidify() & (::logging ::LogMessage("/root/firefox-clang/third_party/zucchini/moz_zucchini.cc" , 340, ::logging::LOGGING_ERROR).stream()) << "Error flushing changes to disk: " << mappedNew.error(); | |||
| 341 | return status::kStatusFileWriteError; | |||
| 342 | } | |||
| 343 | ||||
| 344 | return status::kStatusSuccess; | |||
| 345 | }; | |||
| 346 | return GUARD_PAGE_ERRORS(applyToNewFile)applyToNewFile(); | |||
| 347 | } | |||
| 348 | ||||
| 349 | status::Code MappedPatch::ApplyUnsafe(const uint8_t* aCheckedOldImage, | |||
| 350 | size_t aCheckedOldImageSize, | |||
| 351 | FILE* aNewFile) { | |||
| 352 | if (!mImpl) { | |||
| ||||
| 353 | return mInitStatus; | |||
| 354 | } | |||
| 355 | BEGIN_ENTRY_POINT()try { | |||
| 356 | return ApplyUnsafeImpl(aCheckedOldImage, aCheckedOldImageSize, aNewFile); | |||
| 357 | END_ENTRY_POINT()} catch (const std::bad_alloc&) { !((::logging::ShouldCreateLogMessage (::logging::LOGGING_ERROR))) ? (void) 0 : ::logging::LogMessageVoidify () & (::logging::LogMessage("/root/firefox-clang/third_party/zucchini/moz_zucchini.cc" , 357, ::logging::LOGGING_ERROR).stream()) << "std::bad_alloc caught in zucchini." ; return status::kStatusOutOfMemory; } catch (...) { !((::logging ::ShouldCreateLogMessage(::logging::LOGGING_ERROR))) ? (void) 0 : ::logging::LogMessageVoidify() & (::logging::LogMessage ("/root/firefox-clang/third_party/zucchini/moz_zucchini.cc", 357 , ::logging::LOGGING_ERROR).stream()) << "unknown exception caught in zucchini; this is a bug." ; return status::kStatusFatal; } | |||
| 358 | } | |||
| 359 | ||||
| 360 | } // namespace zucchini::mozilla |