Changeset 123856 in webkit
- Timestamp:
- Jul 27, 2012, 2:37:51 AM (13 years ago)
- Location:
- trunk/Source
- Files:
-
- 12 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r123853 r123856 1 2012-07-27 Adam Barth <abarth@webkit.org> 2 3 Add a Setting to expose quantized, rate-limited MemoryInfo values 4 https://bugs.webkit.org/show_bug.cgi?id=80444 5 6 Reviewed by Eric Seidel. 7 8 We do not currently expose real MemoryInfo objects to the web unless 9 the user opts in because we're worried that this memory information 10 could be used in side-channel attacks. 11 12 We've gotten feedback from a number of web app developers that this 13 information is very useful in tracking the performance of their 14 applications. These developers use the setting in their testing labs 15 and regression harnesses to catch memory leaks and regressiosn early in 16 their development cycle. 17 18 Some of these developers have experimented with enabling this feature 19 within their enterprise and have found the memory data from the field 20 extremely useful in tracking down memory issues that slip through their 21 testing. 22 23 Based on this experience, they've asked whether we can enable this 24 functionality on a wider scale so they catch even more problems 25 including problems that don't manifest within their enterprise. 26 Because we're still worried about side-channel attacks, we don't want 27 to expose the raw data, so we've talked with these folks in more detail 28 to understand what information they find most valuable. 29 30 This patch is the result of those discussions. In particular, this 31 patch adds an option to expose quantized and rate-limited memory 32 information to web pages. Web pages can only learn new data every 20 33 minutes, which helps mitigate attacks where the attacker compares two 34 or readings to extract side-channel information. The patch also only 35 reports 100 distinct memory values, which (combined with the rate 36 limts) makes it difficult for attackers to learn about small changes in 37 memory use. 38 39 * page/MemoryInfo.cpp: 40 (WebCore): 41 (HeapSizeCache): 42 (WebCore::HeapSizeCache::HeapSizeCache): 43 (WebCore::HeapSizeCache::getCachedHeapSize): 44 (WebCore::HeapSizeCache::maybeUpdate): 45 (WebCore::HeapSizeCache::update): 46 (WebCore::HeapSizeCache::quantize): 47 (WebCore::MemoryInfo::MemoryInfo): 48 * page/Settings.cpp: 49 (WebCore::Settings::Settings): 50 * page/Settings.h: 51 (WebCore::Settings::setQuantizedMemoryInfoEnabled): 52 (WebCore::Settings::quantizedMemoryInfoEnabled): 53 (Settings): 54 1 55 2012-07-27 Vsevolod Vlasov <vsevik@chromium.org> 2 56 -
trunk/Source/WebCore/bindings/js/ScriptGCEvent.cpp
r95901 r123856 44 44 using namespace JSC; 45 45 46 void ScriptGCEvent::getHeapSize( size_t& usedHeapSize, size_t& totalHeapSize, size_t& heapSizeLimit)46 void ScriptGCEvent::getHeapSize(HeapInfo& info) 47 47 { 48 48 JSGlobalData* globalData = JSDOMWindow::commonJSGlobalData(); 49 totalHeapSize = globalData->heap.capacity();50 usedHeapSize = globalData->heap.size();51 heapSizeLimit = 0;49 info.totalJSHeapSize = globalData->heap.capacity(); 50 info.usedJSHeapSize = globalData->heap.size(); 51 info.jsHeapSizeLimit = 0; 52 52 } 53 53 -
trunk/Source/WebCore/bindings/js/ScriptGCEvent.h
r95901 r123856 38 38 class ScriptGCEventListener; 39 39 40 struct HeapInfo { 41 HeapInfo() 42 : usedJSHeapSize(0) 43 , totalJSHeapSize(0) 44 , jsHeapSizeLimit(0) 45 { 46 } 47 48 size_t usedJSHeapSize; 49 size_t totalJSHeapSize; 50 size_t jsHeapSizeLimit; 51 }; 52 40 53 class ScriptGCEvent 41 54 { … … 43 56 static void addEventListener(ScriptGCEventListener*) { } 44 57 static void removeEventListener(ScriptGCEventListener*) { } 45 static void getHeapSize( size_t& usedHeapSize, size_t& totalHeapSize, size_t& heapSizeLimit);58 static void getHeapSize(HeapInfo&); 46 59 }; 47 60 -
trunk/Source/WebCore/bindings/v8/ScriptGCEvent.cpp
r116103 r123856 72 72 } 73 73 74 void ScriptGCEvent::getHeapSize( size_t& usedHeapSize, size_t& totalHeapSize, size_t& heapSizeLimit)74 void ScriptGCEvent::getHeapSize(HeapInfo& info) 75 75 { 76 76 v8::HeapStatistics heapStatistics; 77 77 v8::V8::GetHeapStatistics(&heapStatistics); 78 usedHeapSize = heapStatistics.used_heap_size();79 totalHeapSize = heapStatistics.total_heap_size();80 heapSizeLimit = heapStatistics.heap_size_limit();78 info.usedJSHeapSize = heapStatistics.used_heap_size(); 79 info.totalJSHeapSize = heapStatistics.total_heap_size(); 80 info.jsHeapSizeLimit = heapStatistics.heap_size_limit(); 81 81 } 82 82 -
trunk/Source/WebCore/bindings/v8/ScriptGCEvent.h
r116103 r123856 41 41 class ScriptGCEventListener; 42 42 43 struct HeapInfo { 44 HeapInfo() 45 : usedJSHeapSize(0) 46 , totalJSHeapSize(0) 47 , jsHeapSizeLimit(0) 48 { 49 } 50 51 size_t usedJSHeapSize; 52 size_t totalJSHeapSize; 53 size_t jsHeapSizeLimit; 54 }; 55 43 56 class ScriptGCEvent 44 57 { … … 46 59 static void addEventListener(ScriptGCEventListener*); 47 60 static void removeEventListener(ScriptGCEventListener*); 48 static void getHeapSize(size_t&, size_t&, size_t&); 61 static void getHeapSize(HeapInfo&); 62 49 63 private: 50 64 static void gcEpilogueCallback(v8::GCType type, v8::GCCallbackFlags flags); -
trunk/Source/WebCore/inspector/InspectorMemoryAgent.cpp
r123744 r123856 418 418 static PassRefPtr<InspectorMemoryBlock> jsHeapInfo() 419 419 { 420 size_t usedJSHeapSize; 421 size_t totalJSHeapSize; 422 size_t jsHeapSizeLimit; 423 ScriptGCEvent::getHeapSize(usedJSHeapSize, totalJSHeapSize, jsHeapSizeLimit); 420 HeapInfo info; 421 ScriptGCEvent::getHeapSize(info); 424 422 425 423 RefPtr<InspectorMemoryBlock> jsHeapAllocated = InspectorMemoryBlock::create().setName(MemoryBlockName::jsHeapAllocated); 426 jsHeapAllocated->setSize( totalJSHeapSize);424 jsHeapAllocated->setSize(static_cast<int>(info.totalJSHeapSize)); 427 425 428 426 RefPtr<TypeBuilder::Array<InspectorMemoryBlock> > children = TypeBuilder::Array<InspectorMemoryBlock>::create(); 429 427 RefPtr<InspectorMemoryBlock> jsHeapUsed = InspectorMemoryBlock::create().setName(MemoryBlockName::jsHeapUsed); 430 jsHeapUsed->setSize( usedJSHeapSize);428 jsHeapUsed->setSize(static_cast<int>(info.usedJSHeapSize)); 431 429 children->addItem(jsHeapUsed); 432 430 -
trunk/Source/WebCore/inspector/InspectorTimelineAgent.cpp
r122312 r123856 468 468 void InspectorTimelineAgent::setHeapSizeStatistics(InspectorObject* record) 469 469 { 470 size_t usedHeapSize = 0; 471 size_t totalHeapSize = 0; 472 size_t heapSizeLimit = 0; 473 ScriptGCEvent::getHeapSize(usedHeapSize, totalHeapSize, heapSizeLimit); 474 record->setNumber("usedHeapSize", usedHeapSize); 475 record->setNumber("totalHeapSize", totalHeapSize); 470 HeapInfo info; 471 ScriptGCEvent::getHeapSize(info); 472 record->setNumber("usedHeapSize", info.usedJSHeapSize); 473 record->setNumber("totalHeapSize", info.totalJSHeapSize); 476 474 477 475 if (m_state->getBoolean(TimelineAgentState::includeMemoryDetails)) { -
trunk/Source/WebCore/page/MemoryInfo.cpp
r95901 r123856 35 35 #include "ScriptGCEvent.h" 36 36 #include "Settings.h" 37 #include <limits> 38 #include <wtf/CurrentTime.h> 39 #include <wtf/MainThread.h> 37 40 38 41 namespace WebCore { 39 42 43 #if ENABLE(INSPECTOR) 44 45 class HeapSizeCache { 46 WTF_MAKE_NONCOPYABLE(HeapSizeCache); 47 public: 48 HeapSizeCache() 49 : m_lastUpdateTime(0) 50 { 51 } 52 53 void getCachedHeapSize(HeapInfo& info) 54 { 55 maybeUpdate(); 56 info = m_info; 57 } 58 59 private: 60 void maybeUpdate() 61 { 62 // We rate-limit queries to once every twenty minutes to make it more difficult 63 // for attackers to compare memory usage before and after some event. 64 const double TwentyMinutesInSeconds = 20 * 60; 65 66 double now = monotonicallyIncreasingTime(); 67 if (now - m_lastUpdateTime >= TwentyMinutesInSeconds) { 68 update(); 69 m_lastUpdateTime = now; 70 } 71 } 72 73 void update() 74 { 75 ScriptGCEvent::getHeapSize(m_info); 76 m_info.usedJSHeapSize = quantizeMemorySize(m_info.usedJSHeapSize); 77 m_info.totalJSHeapSize = quantizeMemorySize(m_info.totalJSHeapSize); 78 m_info.jsHeapSizeLimit = quantizeMemorySize(m_info.jsHeapSizeLimit); 79 } 80 81 double m_lastUpdateTime; 82 83 HeapInfo m_info; 84 }; 85 86 // We quantize the sizes to make it more difficult for an attacker to see precise 87 // impact of operations on memory. The values are used for performance tuning, 88 // and hence don't need to be as refined when the value is large, so we threshold 89 // at a list of exponentially separated buckets. 90 size_t quantizeMemorySize(size_t size) 91 { 92 const int numberOfBuckets = 100; 93 DEFINE_STATIC_LOCAL(Vector<size_t>, bucketSizeList, ()); 94 95 ASSERT(isMainThread()); 96 if (bucketSizeList.isEmpty()) { 97 bucketSizeList.resize(numberOfBuckets); 98 99 float sizeOfNextBucket = 10000000.0; // First bucket size is roughly 10M. 100 const float largestBucketSize = 4000000000.0; // Roughly 4GB. 101 // We scale with the Nth root of the ratio, so that we use all the bucktes. 102 const float scalingFactor = exp(log(largestBucketSize / sizeOfNextBucket) / numberOfBuckets); 103 104 size_t nextPowerOfTen = static_cast<size_t>(pow(10, floor(log10(sizeOfNextBucket)) + 1) + 0.5); 105 size_t granularity = nextPowerOfTen / 1000; // We want 3 signficant digits. 106 107 for (int i = 0; i < numberOfBuckets; ++i) { 108 size_t currentBucketSize = static_cast<size_t>(sizeOfNextBucket); 109 bucketSizeList[i] = currentBucketSize - (currentBucketSize % granularity); 110 111 sizeOfNextBucket *= scalingFactor; 112 if (sizeOfNextBucket >= nextPowerOfTen) { 113 if (std::numeric_limits<size_t>::max() / 10 <= nextPowerOfTen) 114 nextPowerOfTen = std::numeric_limits<size_t>::max(); 115 else { 116 nextPowerOfTen *= 10; 117 granularity *= 10; 118 } 119 } 120 121 // Watch out for overflow, if the range is too large for size_t. 122 if (i > 0 && bucketSizeList[i] < bucketSizeList[i - 1]) 123 bucketSizeList[i] = std::numeric_limits<size_t>::max(); 124 } 125 } 126 127 for (int i = 0; i < numberOfBuckets; ++i) { 128 if (size <= bucketSizeList[i]) 129 return bucketSizeList[i]; 130 } 131 132 return bucketSizeList[numberOfBuckets - 1]; 133 } 134 135 #endif 136 40 137 MemoryInfo::MemoryInfo(Frame* frame) 41 : m_totalJSHeapSize(0),42 m_usedJSHeapSize(0),43 m_jsHeapSizeLimit(0)44 138 { 45 if (frame && frame->settings() && frame->settings()->memoryInfoEnabled()) { 139 if (!frame || !frame->settings()) 140 return; 141 46 142 #if ENABLE(INSPECTOR) 47 ScriptGCEvent::getHeapSize(m_usedJSHeapSize, m_totalJSHeapSize, m_jsHeapSizeLimit); 143 if (frame->settings()->memoryInfoEnabled()) 144 ScriptGCEvent::getHeapSize(m_info); 145 else if (true || frame->settings()->quantizedMemoryInfoEnabled()) { 146 DEFINE_STATIC_LOCAL(HeapSizeCache, heapSizeCache, ()); 147 heapSizeCache.getCachedHeapSize(m_info); 148 } 48 149 #endif 49 }50 150 } 51 151 -
trunk/Source/WebCore/page/MemoryInfo.h
r123451 r123856 32 32 #define MemoryInfo_h 33 33 34 #include "ScriptGCEvent.h" 34 35 #include <wtf/PassRefPtr.h> 35 36 #include <wtf/RefCounted.h> … … 43 44 static PassRefPtr<MemoryInfo> create(Frame* frame) { return adoptRef(new MemoryInfo(frame)); } 44 45 45 size_t totalJSHeapSize() const { return m_ totalJSHeapSize; }46 size_t usedJSHeapSize() const { return m_ usedJSHeapSize; }47 size_t jsHeapSizeLimit() const { return m_ jsHeapSizeLimit; }46 size_t totalJSHeapSize() const { return m_info.totalJSHeapSize; } 47 size_t usedJSHeapSize() const { return m_info.usedJSHeapSize; } 48 size_t jsHeapSizeLimit() const { return m_info.jsHeapSizeLimit; } 48 49 49 50 private: 50 51 explicit MemoryInfo(Frame*); 51 52 52 size_t m_totalJSHeapSize; 53 size_t m_usedJSHeapSize; 54 size_t m_jsHeapSizeLimit; 53 HeapInfo m_info; 55 54 }; 55 56 size_t quantizeMemorySize(size_t); 56 57 57 58 } // namespace WebCore -
trunk/Source/WebCore/page/Settings.cpp
r123775 r123856 243 243 #endif 244 244 , m_memoryInfoEnabled(false) 245 , m_quantizedMemoryInfoEnabled(false) 245 246 , m_interactiveFormValidation(false) 246 247 , m_usePreHTML5ParserQuirks(false) -
trunk/Source/WebCore/page/Settings.h
r123775 r123856 453 453 void setMemoryInfoEnabled(bool flag) { m_memoryInfoEnabled = flag; } 454 454 bool memoryInfoEnabled() const { return m_memoryInfoEnabled; } 455 456 void setQuantizedMemoryInfoEnabled(bool flag) { m_quantizedMemoryInfoEnabled = flag; } 457 bool quantizedMemoryInfoEnabled() const { return m_quantizedMemoryInfoEnabled; } 455 458 456 459 // This setting will be removed when an HTML5 compatibility issue is … … 732 735 bool m_fullScreenAPIEnabled : 1; 733 736 #endif 734 bool m_asynchronousSpellCheckingEnabled: 1; 735 bool m_unifiedTextCheckerEnabled: 1; 736 bool m_memoryInfoEnabled: 1; 737 bool m_interactiveFormValidation: 1; 738 bool m_usePreHTML5ParserQuirks: 1; 737 bool m_asynchronousSpellCheckingEnabled : 1; 738 bool m_unifiedTextCheckerEnabled : 1; 739 bool m_memoryInfoEnabled : 1; 740 bool m_quantizedMemoryInfoEnabled : 1; 741 bool m_interactiveFormValidation : 1; 742 bool m_usePreHTML5ParserQuirks : 1; 739 743 bool m_hyperlinkAuditingEnabled : 1; 740 744 bool m_crossOriginCheckInGetMatchedCSSRulesDisabled : 1; -
trunk/Source/WebKit/chromium/WebKit.gypi
r123065 r123856 126 126 'tests/LocalizedDateICUTest.cpp', 127 127 'tests/LocalizedNumberICUTest.cpp', 128 'tests/MemoryInfo.cpp', 128 129 'tests/MockCCQuadCuller.h', 129 130 'tests/OpaqueRectTrackingContentLayerDelegateTest.cpp', -
trunk/Source/WebKit/chromium/tests/MemoryInfo.cpp
r123854 r123856 1 1 /* 2 * Copyright (C) 201 0Google Inc. All rights reserved.2 * Copyright (C) 2012 Google Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 30 30 31 31 #include "config.h" 32 32 33 #include "MemoryInfo.h" 33 34 34 #include "Frame.h" 35 #include "ScriptGCEvent.h" 36 #include "Settings.h" 35 #include <gtest/gtest.h> 37 36 38 namespace WebCore { 37 using namespace WebCore; 39 38 40 MemoryInfo::MemoryInfo(Frame* frame) 41 : m_totalJSHeapSize(0), 42 m_usedJSHeapSize(0), 43 m_jsHeapSizeLimit(0) 39 namespace { 40 41 TEST(MemoryInfo, quantizeMemorySize) 44 42 { 45 if (frame && frame->settings() && frame->settings()->memoryInfoEnabled()) { 46 #if ENABLE(INSPECTOR) 47 ScriptGCEvent::getHeapSize(m_usedJSHeapSize, m_totalJSHeapSize, m_jsHeapSizeLimit); 48 #endif 49 } 43 EXPECT_EQ(10000000u, quantizeMemorySize(1024)); 44 EXPECT_EQ(10000000u, quantizeMemorySize(1024 * 1024)); 45 EXPECT_EQ(410000000u, quantizeMemorySize(389472983)); 46 EXPECT_EQ(39600000u, quantizeMemorySize(38947298)); 47 EXPECT_EQ(29400000u, quantizeMemorySize(28947298)); 48 EXPECT_EQ(19300000u, quantizeMemorySize(18947298)); 49 EXPECT_EQ(14300000u, quantizeMemorySize(13947298)); 50 EXPECT_EQ(10000000u, quantizeMemorySize(3894729)); 51 EXPECT_EQ(10000000u, quantizeMemorySize(389472)); 52 EXPECT_EQ(10000000u, quantizeMemorySize(38947)); 53 EXPECT_EQ(10000000u, quantizeMemorySize(3894)); 54 EXPECT_EQ(10000000u, quantizeMemorySize(389)); 55 EXPECT_EQ(10000000u, quantizeMemorySize(38)); 56 EXPECT_EQ(10000000u, quantizeMemorySize(3)); 57 EXPECT_EQ(10000000u, quantizeMemorySize(1)); 58 EXPECT_EQ(10000000u, quantizeMemorySize(0)); 50 59 } 51 60 52 } // namespace WebCore61 } // namespace
Note:
See TracChangeset
for help on using the changeset viewer.