Bug Summary

File:Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp
Warning:line 627, column 19
Local variable 'resource' is uncounted and unsafe

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple arm64-apple-ios26.2.0-simulator -O3 -Wundef-prefix=TARGET_OS_ -Werror=undef-prefix -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -Werror=implicit-function-declaration -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name UnifiedSource290.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=osx -analyzer-checker=security.insecureAPI.decodeValueOfObjCType -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 -mframe-pointer=non-leaf -ffp-contract=on -fno-rounding-math -target-sdk-version=26.2 -fdepfile-entry=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/SDKSettings.json -fcompatibility-qualified-id-block-type-checking -fvisibility-inlines-hidden-static-local-var -fno-modulemap-allow-subdirectory-search -fdefine-target-os-macros -enable-tlsdesc -target-cpu apple-m1 -target-feature +v8.4a -target-feature +aes -target-feature +altnzcv -target-feature +ccdp -target-feature +ccpp -target-feature +complxnum -target-feature +crc -target-feature +dotprod -target-feature +flagm -target-feature +fp-armv8 -target-feature +fp16fml -target-feature +fptoint -target-feature +fullfp16 -target-feature +jsconv -target-feature +lse -target-feature +neon -target-feature +pauth -target-feature +perfmon -target-feature +predres -target-feature +ras -target-feature +rcpc -target-feature +rdm -target-feature +sb -target-feature +sha2 -target-feature +sha3 -target-feature +specrestrict -target-feature +ssbs -target-abi darwinpcs -dwarf-ext-refs -fmodule-format=obj -debug-info-kind=standalone -dwarf-version=5 -debugger-tuning=lldb -fdebug-compilation-dir=/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore -target-linker-version 1230.1 -fcoverage-compilation-dir=/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore -resource-dir /Users/buildbot/Library/Developer/Toolchains/swift-webkit.xctoolchain/usr/lib/clang/21 -dependency-file /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebCore/WebCore/normal/arm64/UnifiedSource290.d -skip-unused-modulemap-deps -MT dependencies -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk -iquote /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/WebCore-generated-files.hmap -iquote /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/WebCore-project-headers.hmap -isystem /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/PAL/ThirdParty/dav1d/include -isystem /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/SDKAdditions/usr/include -iframework /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/SDKAdditions/System/Library/Frameworks -iframework /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitLibraries/SDKs/iphonesimulator26.0-additions.sdk/System/Library/PrivateFrameworks -iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/System/Library/Frameworks -include-pch /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/PrecompiledHeaders/SharedPrecompiledHeaders/11721353671419897710/WebCorePrefix.h.gch -D _LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE -D NDEBUG -D BUILDING_WEBKIT -D GL_SILENCE_DEPRECATION=1 -D GLES_SILENCE_DEPRECATION=1 -D __clang_analyzer__ -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/WebCore-own-target-headers.hmap -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/WebCore-all-target-headers.hmap -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/include -I PAL -I ForwardingHeaders -I /usr/include/libxslt -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/include/libxml2 -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/DerivedSources/WebCore -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include/WebKitAdditions -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include/WebKitAdditions -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitLibraries/SDKs/iphonesimulator26.0-additions.sdk/usr/local/include -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include/webrtc -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include/webrtc -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include/webm -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include/webm -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/PAL.build/PAL.build/DerivedSources -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/PAL.build/Release-iphonesimulator/PAL.build/DerivedSources -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/DerivedSources-normal/arm64 -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/DerivedSources/arm64 -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/DerivedSources -F/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator -F/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator -I/usr/local/include -stdlib=libc++ -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/include/c++/v1 -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include -internal-isystem /Users/buildbot/Library/Developer/Toolchains/swift-webkit.xctoolchain/usr/lib/clang/21/include -internal-externc-isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/include -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/System/Library/Frameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/System/Library/SubFrameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/Library/Frameworks -Wno-trigraphs -Werror -Wno-missing-field-initializers -Wmissing-prototypes -Wunreachable-code -Wnon-virtual-dtor -Wno-overloaded-virtual -Wno-exit-time-destructors -Wno-missing-braces -Wparentheses -Wswitch -Wunused-function -Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value -Wempty-body -Wuninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wconstant-conversion -Wint-conversion -Wbool-conversion -Wenum-conversion -Wno-float-conversion -Wnon-literal-null-conversion -Wobjc-literal-conversion -Wsign-compare -Wno-shorten-64-to-32 -Wnewline-eof -Wno-c++11-extensions -Wno-implicit-fallthrough -Wdeprecated-declarations -Winvalid-offsetof -Wno-sign-conversion -Winfinite-recursion -Wmove -Wcomma -Wblock-capture-autoreleasing -Wstrict-prototypes -Wrange-loop-analysis -Wno-semicolon-before-method-body -Wall -Wc99-designator -Wconditional-uninitialized -Wextra -Wdeprecated-enum-enum-conversion -Wdeprecated-enum-float-conversion -Wenum-float-conversion -Wfinal-dtor-non-final-class -Wformat=2 -Wmisleading-indentation -Wpointer-to-int-cast -Wreorder-init-list -Wundef -Wunused-but-set-variable -Wvla -Werror=unguarded-availability -Wno-elaborated-enum-base -Wcast-qual -Wchar-subscripts -Wextra-tokens -Winit-self -Wmissing-noreturn -Wpacked -Wpointer-arith -Wredundant-decls -Wwrite-strings -Wexit-time-destructors -Wglobal-constructors -Wtautological-compare -Wimplicit-fallthrough -Wvla -Wno-unknown-warning-option -Wliteral-conversion -Wthread-safety -Wno-profile-instr-out-of-date -Wno-profile-instr-unprofiled -Wno-backend-plugin -Wunsafe-buffer-usage -std=c++2b -fdeprecated-macro -ferror-limit 19 -fmacro-backtrace-limit=0 -fvisibility=hidden -fvisibility-inlines-hidden -stack-protector 1 -fblocks -fencode-extended-block-signature -fno-rtti -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fno-cxx-modules -fno-implicit-modules -fskip-odr-check-in-gmf -fpascal-strings -fmax-type-align=16 -fdiagnostics-show-note-include-stack -vectorize-loops -vectorize-slp -fsafe-buffer-usage-suggestions -analyzer-output=html -analyzer-config report-in-main-source-file=true -analyzer-config nullability:NoDiagnoseCallsToSystemHeaders=true -analyzer-checker optin.osx.cocoa.localizability.NonLocalizedStringChecker -analyzer-checker security.insecureAPI.UncheckedReturn -analyzer-checker security.insecureAPI.getpw -analyzer-checker security.insecureAPI.gets -analyzer-checker security.insecureAPI.mkstemp -analyzer-checker security.insecureAPI.mktemp -analyzer-disable-checker security.insecureAPI.rand -analyzer-disable-checker security.insecureAPI.strcpy -analyzer-checker security.insecureAPI.vfork -analyzer-disable-checker alpha,apiModeling,core,cplusplus,deadcode,debug,fuchsia,nullability,optin,osx,security,unix,webkit -analyzer-checker alpha.webkit.ForwardDeclChecker,alpha.webkit.MemoryUnsafeCastChecker,alpha.webkit.NoDeleteChecker,alpha.webkit.NoUncheckedPtrMemberChecker,alpha.webkit.NoUnretainedMemberChecker,alpha.webkit.RetainPtrCtorAdoptChecker,alpha.webkit.UncheckedCallArgsChecker,alpha.webkit.UncheckedLocalVarsChecker,alpha.webkit.UncountedCallArgsChecker,alpha.webkit.UncountedLocalVarsChecker,alpha.webkit.UnretainedCallArgsChecker,alpha.webkit.UnretainedLambdaCapturesChecker,alpha.webkit.UnretainedLocalVarsChecker,webkit.NoUncountedMemberChecker,webkit.RefCntblBaseVirtualDtor,webkit.UncountedLambdaCapturesChecker -analyzer-config max-nodes=10000000 -analyzer-config verbose-report-filename=true -fdwarf2-cfi-asm -o /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebCore/WebCore/normal/arm64/UnifiedSource290.plist -x c++ /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/DerivedSources/WebCore/unified-sources/UnifiedSource290.cpp
1/*
2 Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
3 Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
4 Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
5 Copyright (C) 2004-2025 Apple Inc. All rights reserved.
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
21*/
22
23#include "config.h"
24#include "MemoryCache.h"
25
26#include "BitmapImage.h"
27#include "CachedImage.h"
28#include "CachedImageClient.h"
29#include "CachedResource.h"
30#include "CachedResourceHandle.h"
31#include "ClientOrigin.h"
32#include "Document.h"
33#include "FrameLoader.h"
34#include "FrameLoaderTypes.h"
35#include "Image.h"
36#include "LocalFrameView.h"
37#include "Logging.h"
38#include "PublicSuffixStore.h"
39#include "SharedBuffer.h"
40#include "WorkerGlobalScope.h"
41#include "WorkerLoaderProxy.h"
42#include "WorkerThread.h"
43#include <pal/Logging.h>
44#include <stdio.h>
45#include <wtf/MathExtras.h>
46#include <wtf/NeverDestroyed.h>
47#include <wtf/SetForScope.h>
48#include <wtf/text/CString.h>
49
50namespace WebCore {
51
52static const int cDefaultCacheCapacity = 8192 * 1024;
53static const Seconds cMinDelayBeforeLiveDecodedPrune { 1_s };
54static const float cTargetPrunePercentage = .95f; // Percentage of capacity toward which we prune, to avoid immediately pruning again.
55
56MemoryCache& MemoryCache::singleton()
57{
58 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(58, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
59 static NeverDestroyed<MemoryCache> memoryCache;
60 return memoryCache;
61}
62
63MemoryCache::MemoryCache()
64 : m_capacity(cDefaultCacheCapacity)
65 , m_maxDeadCapacity(cDefaultCacheCapacity)
66 , m_pruneTimer(*this, &MemoryCache::prune)
67{
68 static_assert(sizeof(long long) > sizeof(unsigned), "Numerical overflow can happen when adjusting the size of the cached memory.");
69
70 static std::once_flag onceFlag;
71 std::call_once(onceFlag, [] {
72 PAL::registerNotifyCallback("com.apple.WebKit.showMemoryCache"_s, [] {
73 MemoryCache::singleton().dumpStats();
74 MemoryCache::singleton().dumpLRULists(true);
75 });
76 });
77}
78
79auto MemoryCache::sessionResourceMap(PAL::SessionID sessionID) const -> CachedResourceMap*
80{
81 RELEASE_ASSERT(sessionID.isValid())do { if (__builtin_expect(!!(!(sessionID.isValid())), 0)) do {
WTF::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(81, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
82 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(82, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
83 RELEASE_ASSERT(m_sessionResources.isValidKey(sessionID))do { if (__builtin_expect(!!(!(m_sessionResources.isValidKey(
sessionID))), 0)) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(83, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
84 return m_sessionResources.get(sessionID);
85}
86
87auto MemoryCache::ensureSessionResourceMap(PAL::SessionID sessionID) -> CachedResourceMap&
88{
89 RELEASE_ASSERT(sessionID.isValid())do { if (__builtin_expect(!!(!(sessionID.isValid())), 0)) do {
WTF::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(89, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
90 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(90, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
91 RELEASE_ASSERT(m_sessionResources.isValidKey(sessionID))do { if (__builtin_expect(!!(!(m_sessionResources.isValidKey(
sessionID))), 0)) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(91, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
92 auto& map = m_sessionResources.add(sessionID, nullptr).iterator->value;
93 if (!map)
94 map = makeUnique<CachedResourceMap>();
95 return *map;
96}
97
98bool MemoryCache::shouldRemoveFragmentIdentifier(const URL& originalURL)
99{
100 if (!originalURL.hasFragmentIdentifier())
101 return false;
102 // Strip away fragment identifier from HTTP URLs.
103 // Data URLs must be unmodified. For file and custom URLs clients may expect resources
104 // to be unique even when they differ by the fragment identifier only.
105 return originalURL.protocolIsInHTTPFamily();
106}
107
108URL MemoryCache::removeFragmentIdentifierIfNeeded(const URL& originalURL)
109{
110 if (!shouldRemoveFragmentIdentifier(originalURL))
111 return originalURL;
112 URL url = originalURL;
113 url.removeFragmentIdentifier();
114 return url;
115}
116
117bool MemoryCache::add(CachedResource& resource)
118{
119 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(119, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
120
121 if (disabled())
122 return false;
123
124 if (resource.resourceRequest().httpMethod() != "GET"_s)
125 return false;
126
127 ASSERT(isMainThread())((void)0);
128
129 auto key = std::make_pair(resource.url(), resource.cachePartition());
130
131 auto& resources = ensureSessionResourceMap(resource.sessionID());
132
133 RELEASE_ASSERT(!resources.get(key))do { if (__builtin_expect(!!(!(!resources.get(key))), 0)) do {
WTF::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(133, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
134 resources.set(key, &resource);
135 resource.setInCache(true);
136
137 resourceAccessed(resource);
138
139 LOG(ResourceLoading, "MemoryCache::add Added '%.255s', resource %p\n", resource.url().string().latin1().data(), &resource)((void)0);
140 return true;
141}
142
143void MemoryCache::revalidationSucceeded(CachedResource& revalidatingResource, const ResourceResponse& response)
144{
145 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(145, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
146 ASSERT(response.source() == ResourceResponse::Source::MemoryCacheAfterValidation)((void)0);
147 ASSERT(revalidatingResource.resourceToRevalidate())((void)0);
148 RefPtr protectedRevalidatingResource { revalidatingResource };
149 RefPtr resource = *revalidatingResource.resourceToRevalidate();
150 ASSERT(!resource->inCache())((void)0);
151 ASSERT(resource->isLoaded())((void)0);
152
153 remove(revalidatingResource);
154
155 // A resource with the same URL may have been added back in the cache during revalidation.
156 // In this case, we remove the cached resource and replace it with our freshly revalidated
157 // one.
158 std::pair key { resource->url(), resource->cachePartition() };
159 if (auto* existingResources = sessionResourceMap(resource->sessionID())) {
160 if (RefPtr existingResource = existingResources->get(key))
161 remove(*existingResource);
162 }
163
164 // Don't move the call to ensureSessionResourceMap() in this function as the calls to
165 // remove() above could invalidate the reference returned by ensureSessionResourceMap().
166 auto& resources = ensureSessionResourceMap(resource->sessionID());
167 ASSERT(!resources.contains(key))((void)0);
168 resources.add(key, resource.get());
169 resource->setInCache(true);
170 resource->updateResponseAfterRevalidation(response);
171 insertInLRUList(*resource);
172 long long delta = resource->size();
173 if (resource->decodedSize() && resource->hasClients())
174 insertInLiveDecodedResourcesList(*resource);
175 if (delta)
176 adjustSize(resource->hasClients(), delta);
177
178 revalidatingResource.switchClientsToRevalidatedResource();
179 // This deletes the revalidating resource.
180 revalidatingResource.clearResourceToRevalidate();
181}
182
183void MemoryCache::revalidationFailed(CachedResource& revalidatingResource)
184{
185 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(185, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
186 LOG(ResourceLoading, "Revalidation failed for %p", &revalidatingResource)((void)0);
187 ASSERT(revalidatingResource.resourceToRevalidate())((void)0);
188 revalidatingResource.clearResourceToRevalidate();
189}
190
191CachedResource* MemoryCache::resourceForRequest(const ResourceRequest& request, PAL::SessionID sessionID)
192{
193 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(193, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
194 // FIXME: Change all clients to make sure HTTP(s) URLs have no fragment identifiers before calling here.
195 // CachedResourceLoader is now doing this. Add an assertion once all other clients are doing it too.
196 auto* resources = sessionResourceMap(sessionID);
197 return resources ? resourceForRequestImpl(request, *resources) : nullptr;
198}
199
200CachedResource* MemoryCache::resourceForRequestImpl(const ResourceRequest& request, CachedResourceMap& resources)
201{
202 ASSERT(isMainThread())((void)0);
203 URL url = removeFragmentIdentifierIfNeeded(request.url());
204
205 auto key = std::make_pair(WTF::move(url), request.cachePartition());
206 return resources.get(key);
207}
208
209unsigned MemoryCache::deadCapacity() const
210{
211 // Dead resource capacity is whatever space is not occupied by live resources, bounded by an independent minimum and maximum.
212 unsigned capacity = m_capacity - std::min(m_liveSize, m_capacity); // Start with available capacity.
213 capacity = std::max(capacity, m_minDeadCapacity); // Make sure it's above the minimum.
214 capacity = std::min(capacity, m_maxDeadCapacity); // Make sure it's below the maximum.
215 return capacity;
216}
217
218unsigned MemoryCache::liveCapacity() const
219{
220 // Live resource capacity is whatever is left over after calculating dead resource capacity.
221 return m_capacity - deadCapacity();
222}
223
224void MemoryCache::pruneLiveResources(bool shouldDestroyDecodedDataForAllLiveResources)
225{
226 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(226, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
227 unsigned capacity = shouldDestroyDecodedDataForAllLiveResources ? 0 : liveCapacity();
228 if (capacity && m_liveSize <= capacity)
229 return;
230
231 unsigned targetSize = static_cast<unsigned>(capacity * cTargetPrunePercentage); // Cut by a percentage to avoid immediately pruning again.
232
233 pruneLiveResourcesToSize(targetSize, shouldDestroyDecodedDataForAllLiveResources);
234}
235
236void MemoryCache::forEachResource(NOESCAPE[[clang::noescape]] const Function<void(CachedResource&)>& function)
237{
238 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(238, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
239 Vector<CachedResourceHandle<CachedResource>> allResources;
240 for (auto& lruList : m_allResources) {
241 allResources.reserveCapacity(allResources.size() + lruList->computeSize());
242 allResources.appendRange(lruList->begin(), lruList->end());
243 }
244 for (auto& resource : allResources) {
245 if (RefPtr resourceHandle = resource.get())
246 function(*resourceHandle);
247 }
248}
249
250void MemoryCache::forEachSessionResource(PAL::SessionID sessionID, NOESCAPE[[clang::noescape]] const Function<void(CachedResource&)>& function)
251{
252 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(252, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
253 RELEASE_ASSERT(m_sessionResources.isValidKey(sessionID))do { if (__builtin_expect(!!(!(m_sessionResources.isValidKey(
sessionID))), 0)) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(253, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
254 auto it = m_sessionResources.find(sessionID);
255 if (it == m_sessionResources.end())
256 return;
257
258 for (auto& weakResource : copyToVector(it->value->values())) {
259 if (RefPtr resource = weakResource.get())
260 function(*resource);
261 }
262}
263
264void MemoryCache::destroyDecodedDataForAllImages()
265{
266 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(266, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
267 forEachResource([](CachedResource& resource) {
268 if (auto cachedImage = dynamicDowncast<CachedImage>(resource)) {
269 if (RefPtr image = cachedImage->image())
270 image->destroyDecodedData();
271 }
272 });
273}
274
275void MemoryCache::pruneLiveResourcesToSize(unsigned targetSize, bool shouldDestroyDecodedDataForAllLiveResources)
276{
277 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(277, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
278 if (m_inPruneResources)
279 return;
280
281 LOG(ResourceLoading, "MemoryCache::pruneLiveResourcesToSize(%d, shouldDestroyDecodedDataForAllLiveResources = %d)", targetSize, shouldDestroyDecodedDataForAllLiveResources)((void)0);
282
283 SetForScope reentrancyProtector(m_inPruneResources, true);
284
285 MonotonicTime currentTime = LocalFrameView::currentPaintTimeStamp();
286 if (!currentTime) // In case prune is called directly, outside of a Frame paint.
287 currentTime = MonotonicTime::now();
288
289 // Destroy any decoded data in live objects that we can.
290 // Start from the head, since this is the least recently accessed of the objects.
291
292 // The list might not be sorted by the m_lastDecodedAccessTime. The impact
293 // of this weaker invariant is minor as the below if statement to check the
294 // elapsedTime will evaluate to false as the currentTime will be a lot
295 // greater than the current->m_lastDecodedAccessTime.
296 // For more details see: https://bugs.webkit.org/show_bug.cgi?id=30209
297 auto it = m_liveDecodedResources.begin();
298 while (it != m_liveDecodedResources.end()) {
299 RefPtr current = *it;
300
301 LOG(ResourceLoading, " live resource %p %.255s - loaded %d, decodedSize %u", current.get(), current->url().string().utf8().data(), current->isLoaded(), current->decodedSize())((void)0);
302
303 // Increment the iterator now because the call to destroyDecodedData() below
304 // may cause a call to ListHashSet::remove() and invalidate the current
305 // iterator. Note that this is safe because unlike iteration of most
306 // WTF Hash data structures, iteration is guaranteed safe against mutation
307 // of the ListHashSet, except for removal of the item currently pointed to
308 // by a given iterator.
309 ++it;
310
311 ASSERT(current->hasClients())((void)0);
312 if (current->isLoaded() && current->decodedSize()) {
313 // Check to see if the remaining resources are too new to prune.
314 Seconds elapsedTime = currentTime - current->m_lastDecodedAccessTime;
315 if (!shouldDestroyDecodedDataForAllLiveResources && elapsedTime < cMinDelayBeforeLiveDecodedPrune) {
316 LOG(ResourceLoading, " current time is less than min delay before pruning (%.3fms)", elapsedTime.milliseconds())((void)0);
317 return;
318 }
319
320 // Destroy our decoded data. This will remove us from m_liveDecodedResources, and possibly move us
321 // to a different LRU list in m_allResources.
322 current->destroyDecodedData();
323
324 if (targetSize && m_liveSize <= targetSize)
325 return;
326 }
327 }
328}
329
330void MemoryCache::pruneDeadResources()
331{
332 LOG(ResourceLoading, "MemoryCache::pruneDeadResources")((void)0);
333 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(333, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
334
335 unsigned capacity = deadCapacity();
336 if (capacity && m_deadSize <= capacity)
337 return;
338
339 unsigned targetSize = static_cast<unsigned>(capacity * cTargetPrunePercentage); // Cut by a percentage to avoid immediately pruning again.
340 pruneDeadResourcesToSize(targetSize);
341}
342
343void MemoryCache::pruneDeadResourcesToSize(unsigned targetSize)
344{
345 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(345, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
346 if (m_inPruneResources)
347 return;
348
349 LOG(ResourceLoading, "MemoryCache::pruneDeadResourcesToSize(%d)", targetSize)((void)0);
350
351 SetForScope reentrancyProtector(m_inPruneResources, true);
352
353 if (targetSize && m_deadSize <= targetSize)
354 return;
355
356 bool canShrinkLRULists = true;
357 for (int i = m_allResources.size() - 1; i >= 0; i--) {
358 // Make a copy of the LRUList first (and ref the resources) as calling
359 // destroyDecodedData() can alter the LRUList.
360 auto lruList = copyToVector(*m_allResources[i]);
361
362 LOG(ResourceLoading, " lru list (size %zu) - flushing stage", lruList.size())((void)0);
363
364 // First flush all the decoded data in this queue.
365 // Remove from the head, since this is the least frequently accessed of the objects.
366 for (auto& weakResource : lruList) {
367 RefPtr resource = weakResource.get();
368 if (!resource)
369 continue;
370
371 LOG(ResourceLoading, " lru resource %p - in cache %d, has clients %d, preloaded %d, loaded %d", resource.get(), resource->inCache(), resource->hasClients(), resource->isPreloaded(), resource->isLoaded())((void)0);
372 if (!resource->inCache())
373 continue;
374
375 if (!resource->hasClients() && !resource->isPreloaded() && resource->isLoaded()) {
376 // Destroy our decoded data. This will remove us from
377 // m_liveDecodedResources, and possibly move us to a different
378 // LRU list in m_allResources.
379
380 LOG(ResourceLoading, " lru resource %p destroyDecodedData", resource.get())((void)0);
381
382 resource->destroyDecodedData();
383
384 if (targetSize && m_deadSize <= targetSize)
385 return;
386 }
387 }
388
389 LOG(ResourceLoading, " lru list (size %zu) - eviction stage", lruList.size())((void)0);
390
391 // Now evict objects from this list.
392 // Remove from the head, since this is the least frequently accessed of the objects.
393 for (auto& weakResource : lruList) {
394 RefPtr resource = weakResource.get();
395 if (!resource)
396 continue;
397
398 LOG(ResourceLoading, " lru resource %p - in cache %d, has clients %d, preloaded %d, loaded %d", resource.get(), resource->inCache(), resource->hasClients(), resource->isPreloaded(), resource->isLoaded())((void)0);
399 if (!resource->inCache())
400 continue;
401
402 if (!resource->hasClients() && !resource->isPreloaded() && !resource->isCacheValidator()) {
403 remove(*resource);
404 if (targetSize && m_deadSize <= targetSize)
405 return;
406 }
407 }
408
409 // Shrink the vector back down so we don't waste time inspecting
410 // empty LRU lists on future prunes.
411 if (!m_allResources[i]->isEmptyIgnoringNullReferences())
412 canShrinkLRULists = false;
413 else if (canShrinkLRULists)
414 m_allResources.shrink(i);
415 }
416}
417
418void MemoryCache::setCapacities(unsigned minDeadBytes, unsigned maxDeadBytes, unsigned totalBytes)
419{
420 ASSERT(minDeadBytes <= maxDeadBytes)((void)0);
421 ASSERT(maxDeadBytes <= totalBytes)((void)0);
422 m_minDeadCapacity = minDeadBytes;
423 m_maxDeadCapacity = maxDeadBytes;
424 m_capacity = totalBytes;
425 prune();
426}
427
428void MemoryCache::remove(CachedResource& resource)
429{
430 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(430, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
431 RefPtr protectedResource { resource };
432
433 LOG(ResourceLoading, "Evicting resource %p for '%.255s' from cache", &resource, resource.url().string().latin1().data())((void)0);
434 // The resource may have already been removed by someone other than our caller,
435 // who needed a fresh copy for a reload. See <http://bugs.webkit.org/show_bug.cgi?id=12479#c6>.
436 if (auto* resources = sessionResourceMap(resource.sessionID())) {
437 auto key = std::make_pair(resource.url(), resource.cachePartition());
438
439 if (resource.inCache()) {
440 ASSERT_WITH_MESSAGE(resource.response().source() != ResourceResponse::Source::InspectorOverride, "InspectorOverride responses should not get into the MemoryCache")((void)0);
441
442 // Remove resource from the resource map.
443 resources->remove(key);
444 resource.setInCache(false);
445
446 // If the resource map is now empty, remove it from m_sessionResources.
447 if (resources->isEmpty()) {
448 RELEASE_ASSERT(m_sessionResources.isValidKey(resource.sessionID()))do { if (__builtin_expect(!!(!(m_sessionResources.isValidKey(
resource.sessionID()))), 0)) do { WTF::isIntegralOrPointerType
(); compilerFenceForCrash(); WTFCrashWithInfo(448, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
449 m_sessionResources.remove(resource.sessionID());
450 }
451
452 // Remove from the appropriate LRU list.
453 removeFromLRUList(resource);
454 removeFromLiveDecodedResourcesList(resource);
455 adjustSize(resource.hasClients(), -static_cast<long long>(resource.size()));
456 } else {
457 RELEASE_ASSERT(resources->get(key) != &resource)do { if (__builtin_expect(!!(!(resources->get(key) != &
resource)), 0)) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(457, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
458 LOG(ResourceLoading, " resource %p is not in cache", &resource)((void)0);
459 }
460 }
461 RELEASE_ASSERT(!resource.inCache())do { if (__builtin_expect(!!(!(!resource.inCache())), 0)) do {
WTF::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(461, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
462}
463
464auto MemoryCache::lruListFor(CachedResource& resource) -> LRUList&
465{
466 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(466, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
467 unsigned accessCount = std::max(resource.accessCount(), 1U);
468 unsigned queueIndex = WTF::fastLog2(resource.size() / accessCount);
469#if ASSERT_ENABLED0
470 resource.m_lruIndex = queueIndex;
471#endif
472
473 m_allResources.reserveCapacity(queueIndex + 1);
474 while (m_allResources.size() <= queueIndex)
475 m_allResources.append(makeUnique<LRUList>());
476 return *m_allResources[queueIndex];
477}
478
479void MemoryCache::removeFromLRUList(CachedResource& resource)
480{
481 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(481, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
482 // If we've never been accessed, then we're brand new and not in any list.
483 if (!resource.accessCount())
484 return;
485
486#if ASSERT_ENABLED0
487 unsigned oldListIndex = resource.m_lruIndex;
488#endif
489
490 LRUList& list = lruListFor(resource);
491
492 // Verify that the list we got is the list we want.
493 ASSERT(resource.m_lruIndex == oldListIndex)((void)0);
494
495 bool removed = list.remove(resource);
496 ASSERT_UNUSED(removed, removed)((void)removed);
497}
498
499void MemoryCache::insertInLRUList(CachedResource& resource)
500{
501 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(501, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
502 ASSERT(resource.inCache())((void)0);
503 ASSERT(resource.accessCount() > 0)((void)0);
504
505 auto addResult = lruListFor(resource).add(resource);
506 ASSERT_UNUSED(addResult, addResult.isNewEntry)((void)addResult);
507}
508
509void MemoryCache::resourceAccessed(CachedResource& resource)
510{
511 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(511, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
512 ASSERT(resource.inCache())((void)0);
513
514 // Need to make sure to remove before we increase the access count, since
515 // the queue will possibly change.
516 removeFromLRUList(resource);
517
518 // If this is the first time the resource has been accessed, adjust the size of the cache to account for its initial size.
519 if (!resource.accessCount())
520 adjustSize(resource.hasClients(), resource.size());
521
522 // Add to our access count.
523 resource.increaseAccessCount();
524
525 // Now insert into the new queue.
526 insertInLRUList(resource);
527}
528
529bool MemoryCache::inLiveDecodedResourcesList(CachedResource& resource) const
530{
531 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(531, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
532 return m_liveDecodedResources.contains(resource);
533}
534
535void MemoryCache::removeResourcesWithOrigin(const SecurityOrigin& origin, const String& cachePartition)
536{
537 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(537, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
538 Vector<WeakPtr<CachedResource>> resourcesWithOrigin;
539 for (auto& resources : m_sessionResources.values()) {
540 for (auto& keyValue : *resources) {
541 auto& resource = *keyValue.value;
542 auto& partitionName = keyValue.key.second;
543 if (partitionName == cachePartition) {
544 resourcesWithOrigin.append(resource);
545 continue;
546 }
547 auto resourceOrigin = SecurityOrigin::create(resource.url());
548 if (resourceOrigin->equal(origin))
549 resourcesWithOrigin.append(resource);
550 }
551 }
552
553 for (auto& weakResource : resourcesWithOrigin) {
554 if (RefPtr resource = weakResource.get())
555 remove(*resource);
556 }
557}
558
559void MemoryCache::removeResourcesWithOrigin(const SecurityOrigin& origin)
560{
561 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(561, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
562 String originPartition = ResourceRequest::partitionName(origin.host());
563 removeResourcesWithOrigin(origin, originPartition);
564}
565
566void MemoryCache::removeResourcesWithOrigin(const ClientOrigin& origin)
567{
568 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(568, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
569 auto cachePartition = origin.topOrigin == origin.clientOrigin ? emptyString() : ResourceRequest::partitionName(origin.topOrigin.host());
570 removeResourcesWithOrigin(origin.clientOrigin.securityOrigin(), cachePartition);
571}
572
573void MemoryCache::removeResourcesWithOrigins(PAL::SessionID sessionID, const HashSet<Ref<SecurityOrigin>>& origins)
574{
575 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(575, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
576 auto* resourceMap = sessionResourceMap(sessionID);
577 if (!resourceMap)
578 return;
579
580 HashSet<String> originPartitions;
581
582 for (auto& origin : origins)
583 originPartitions.add(ResourceRequest::partitionName(origin->host()));
584
585 Vector<WeakPtr<CachedResource>> resourcesToRemove;
586 for (auto& keyValuePair : *resourceMap) {
587 auto& resource = *keyValuePair.value;
588 auto& partitionName = keyValuePair.key.second;
589 if (originPartitions.contains(partitionName)) {
590 resourcesToRemove.append(resource);
591 continue;
592 }
593 if (origins.contains(SecurityOrigin::create(resource.url()).ptr()))
594 resourcesToRemove.append(resource);
595 }
596
597 for (auto& weakResource : resourcesToRemove) {
598 if (RefPtr resource = weakResource.get())
599 remove(*resource);
600 }
601}
602
603void MemoryCache::getOriginsWithCache(SecurityOriginSet& origins)
604{
605 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(605, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
606 for (auto& resources : m_sessionResources.values()) {
607 for (auto& keyValue : *resources) {
608 auto& resource = *keyValue.value;
609 auto& partitionName = keyValue.key.second;
610 if (!partitionName.isEmpty())
611 origins.add(SecurityOrigin::create("http"_s, partitionName, 0));
612 else
613 origins.add(SecurityOrigin::create(resource.url()));
614 }
615 }
616}
617
618HashSet<Ref<SecurityOrigin>> MemoryCache::originsWithCache(PAL::SessionID sessionID) const
619{
620 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(620, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
621
622 HashSet<Ref<SecurityOrigin>> origins;
623
624 auto it = m_sessionResources.find(sessionID);
625 if (it != m_sessionResources.end()) {
626 for (auto& keyValue : *it->value) {
627 auto& resource = *keyValue.value;
Local variable 'resource' is uncounted and unsafe
628 auto& partitionName = keyValue.key.second;
629 if (!partitionName.isEmpty())
630 origins.add(SecurityOrigin::create("http"_s, partitionName, 0));
631 else
632 origins.add(SecurityOrigin::create(resource.url()));
633 }
634 }
635
636 return origins;
637}
638
639void MemoryCache::removeFromLiveDecodedResourcesList(CachedResource& resource)
640{
641 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(641, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
642 m_liveDecodedResources.remove(resource);
643}
644
645void MemoryCache::moveToEndOfLiveDecodedResourcesListIfPresent(CachedResource& resource)
646{
647 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(647, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
648 m_liveDecodedResources.moveToLastIfPresent(resource);
649}
650
651void MemoryCache::insertInLiveDecodedResourcesList(CachedResource& resource)
652{
653 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(653, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
654 // Make sure we aren't in the list already.
655 ASSERT(!m_liveDecodedResources.contains(resource))((void)0);
656 m_liveDecodedResources.add(resource);
657}
658
659void MemoryCache::addToLiveResourcesSize(CachedResource& resource)
660{
661 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(661, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
662 m_liveSize += resource.size();
663 m_deadSize -= resource.size();
664}
665
666void MemoryCache::removeFromLiveResourcesSize(CachedResource& resource)
667{
668 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(668, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
669 m_liveSize -= resource.size();
670 m_deadSize += resource.size();
671}
672
673void MemoryCache::adjustSize(bool live, long long delta)
674{
675 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(675, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
676 if (live) {
677 ASSERT(delta >= 0 || (static_cast<long long>(m_liveSize) + delta >= 0))((void)0);
678 m_liveSize += delta;
679 } else {
680 ASSERT(delta >= 0 || (static_cast<long long>(m_deadSize) + delta >= 0))((void)0);
681 m_deadSize += delta;
682 }
683}
684
685void MemoryCache::removeRequestFromSessionCaches(ScriptExecutionContext& context, const ResourceRequest& request)
686{
687 if (auto* globalScope = dynamicDowncast<WorkerGlobalScope>(context)) {
688 CheckedPtr workerLoaderProxy = globalScope->thread()->workerLoaderProxy();
689 if (!workerLoaderProxy)
690 return;
691 workerLoaderProxy->postTaskToLoader([request = request.isolatedCopy()] (ScriptExecutionContext& context) {
692 MemoryCache::removeRequestFromSessionCaches(context, request);
693 });
694 return;
695 }
696
697 Ref memoryCache = MemoryCache::singleton();
698 for (auto& resources : memoryCache->m_sessionResources) {
699 if (RefPtr resource = memoryCache->resourceForRequestImpl(request, *resources.value))
700 memoryCache->remove(*resource);
701 }
702}
703
704void MemoryCache::TypeStatistic::addResource(CachedResource& resource)
705{
706 count++;
707 size += resource.size();
708 liveSize += resource.hasClients() ? resource.size() : 0;
709 decodedSize += resource.decodedSize();
710}
711
712MemoryCache::Statistics MemoryCache::getStatistics()
713{
714 Statistics stats;
715
716 for (auto& resources : m_sessionResources.values()) {
717 for (auto& resource : resources->values()) {
718 switch (resource->type()) {
719 case CachedResource::Type::ImageResource:
720 stats.images.addResource(*resource);
721 break;
722 case CachedResource::Type::CSSStyleSheet:
723 stats.cssStyleSheets.addResource(*resource);
724 break;
725 case CachedResource::Type::JSON:
726 case CachedResource::Type::Script:
727 stats.scripts.addResource(*resource);
728 break;
729#if ENABLE(XSLT)(defined 1 && 1)
730 case CachedResource::Type::XSLStyleSheet:
731 stats.xslStyleSheets.addResource(*resource);
732 break;
733#endif
734 case CachedResource::Type::SVGFontResource:
735 case CachedResource::Type::FontResource:
736 stats.fonts.addResource(*resource);
737 break;
738 default:
739 break;
740 }
741 }
742 }
743 return stats;
744}
745
746void MemoryCache::setDisabled(bool disabled)
747{
748 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(748, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
749 m_disabled = disabled;
750 if (!m_disabled)
751 return;
752
753 while (!m_sessionResources.isEmpty()) {
754 auto& resources = *m_sessionResources.begin()->value;
755 ASSERT(!resources.isEmpty())((void)0);
756 RefPtr resource = *resources.begin()->value;
757 remove(*resource);
758 }
759}
760
761void MemoryCache::evictResources()
762{
763 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(763, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
764 if (disabled())
765 return;
766
767 setDisabled(true);
768 setDisabled(false);
769}
770
771void MemoryCache::evictResources(PAL::SessionID sessionID)
772{
773 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(773, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
774 if (disabled())
775 return;
776
777 forEachSessionResource(sessionID, [this] (CachedResource& resource) { remove(resource); });
778
779 ASSERT(!m_sessionResources.contains(sessionID))((void)0);
780}
781
782bool MemoryCache::needsPruning() const
783{
784 return m_liveSize + m_deadSize > m_capacity || m_deadSize > m_maxDeadCapacity;
785}
786
787void MemoryCache::prune()
788{
789 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(789, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
790 if (!needsPruning())
791 return;
792
793 pruneDeadResources(); // Prune dead first, in case it was "borrowing" capacity from live.
794 pruneLiveResources();
795}
796
797void MemoryCache::pruneSoon()
798{
799 RELEASE_ASSERT(isMainThread())do { if (__builtin_expect(!!(!(isMainThread())), 0)) do { WTF
::isIntegralOrPointerType(); compilerFenceForCrash(); WTFCrashWithInfo
(799, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/cache/MemoryCache.cpp"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
800 if (!needsPruning())
801 return;
802 if (m_pruneTimer.isActive())
803 return;
804 m_pruneTimer.startOneShot(0_s);
805}
806
807void MemoryCache::dumpStats()
808{
809 Statistics s = getStatistics();
810 WTFLogAlways("\nMemory Cache");
811 WTFLogAlways("%-13s %-13s %-13s %-13s %-13s\n", "", "Count", "Size", "LiveSize", "DecodedSize");
812 WTFLogAlways("%-13s %-13s %-13s %-13s %-13s\n", "-------------", "-------------", "-------------", "-------------", "-------------");
813 WTFLogAlways("%-13s %13d %13d %13d %13d\n", "Images", s.images.count, s.images.size, s.images.liveSize, s.images.decodedSize);
814 WTFLogAlways("%-13s %13d %13d %13d %13d\n", "CSS", s.cssStyleSheets.count, s.cssStyleSheets.size, s.cssStyleSheets.liveSize, s.cssStyleSheets.decodedSize);
815#if ENABLE(XSLT)(defined 1 && 1)
816 WTFLogAlways("%-13s %13d %13d %13d %13d\n", "XSL", s.xslStyleSheets.count, s.xslStyleSheets.size, s.xslStyleSheets.liveSize, s.xslStyleSheets.decodedSize);
817#endif
818 WTFLogAlways("%-13s %13d %13d %13d %13d\n", "JavaScript", s.scripts.count, s.scripts.size, s.scripts.liveSize, s.scripts.decodedSize);
819 WTFLogAlways("%-13s %13d %13d %13d %13d\n", "Fonts", s.fonts.count, s.fonts.size, s.fonts.liveSize, s.fonts.decodedSize);
820 WTFLogAlways("%-13s %-13s %-13s %-13s %-13s\n\n", "-------------", "-------------", "-------------", "-------------", "-------------");
821
822 unsigned countTotal = s.images.count + s.cssStyleSheets.count + s.scripts.count + s.fonts.count;
823 unsigned sizeTotal = s.images.size + s.cssStyleSheets.size + s.scripts.size + s.fonts.size;
824 unsigned liveSizeTotal = s.images.liveSize + s.cssStyleSheets.liveSize + s.scripts.liveSize + s.fonts.liveSize;
825 unsigned decodedSizeTotal = s.images.decodedSize + s.cssStyleSheets.decodedSize + s.scripts.decodedSize + s.fonts.decodedSize;
826#if ENABLE(XSLT)(defined 1 && 1)
827 countTotal += s.xslStyleSheets.count;
828 sizeTotal += s.xslStyleSheets.size;
829 liveSizeTotal += s.xslStyleSheets.liveSize;
830 decodedSizeTotal += s.xslStyleSheets.decodedSize;
831#endif
832
833 WTFLogAlways("%-13s %13d %11.2fKB %11.2fKB %11.2fKB\n", "Total", countTotal, sizeTotal / 1024., liveSizeTotal / 1024., decodedSizeTotal / 1024.);
834}
835
836void MemoryCache::dumpLRULists(bool includeLive) const
837{
838 WTFLogAlways("LRU-SP lists in eviction order (Kilobytes decoded, Kilobytes encoded, Access count, Referenced):\n");
839
840 int size = m_allResources.size();
841 for (int i = size - 1; i >= 0; i--) {
842 WTFLogAlways("\nList %d:\n", i);
843 for (auto& resource : *m_allResources[i]) {
844 if (includeLive || !resource.hasClients())
845 WTFLogAlways(" %p %.255s %.1fK, %.1fK, accesses: %u, clients: %d\n", &resource, resource.url().string().utf8().data(), resource.decodedSize() / 1024.0f, (resource.encodedSize() + resource.overheadSize()) / 1024.0f, resource.accessCount(), resource.numberOfClients());
846 }
847 }
848}
849
850} // namespace WebCore