1 : // Copyright 2015 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/refinery/analyzers/heap_analyzer.h"
16 :
17 : #include "gtest/gtest.h"
18 : #include "syzygy/common/unittest_util.h"
19 : #include "syzygy/refinery/unittest_util.h"
20 : #include "syzygy/refinery/analyzers/analysis_runner.h"
21 : #include "syzygy/refinery/analyzers/memory_analyzer.h"
22 : #include "syzygy/refinery/analyzers/module_analyzer.h"
23 : #include "syzygy/refinery/process_state/process_state.h"
24 : #include "syzygy/refinery/process_state/process_state_util.h"
25 : #include "syzygy/refinery/symbols/symbol_provider.h"
26 :
27 : namespace refinery {
28 :
29 : namespace {
30 :
31 : bool AnalyzeMinidump(const base::FilePath& minidump_path,
32 E : ProcessState* process_state) {
33 E : minidump::Minidump minidump;
34 E : if (!minidump.Open(minidump_path))
35 i : return false;
36 :
37 E : scoped_refptr<SymbolProvider> symbol_provider(new SymbolProvider());
38 :
39 E : AnalysisRunner runner;
40 : runner.AddAnalyzer(
41 E : scoped_ptr<Analyzer>(new refinery::MemoryAnalyzer()).Pass());
42 : runner.AddAnalyzer(
43 E : scoped_ptr<Analyzer>(new refinery::ModuleAnalyzer()).Pass());
44 : runner.AddAnalyzer(
45 E : scoped_ptr<Analyzer>(new refinery::HeapAnalyzer(symbol_provider)).Pass());
46 :
47 E : return runner.Analyze(minidump, process_state) == Analyzer::ANALYSIS_COMPLETE;
48 E : }
49 :
50 : class HeapAnalyzerTest : public testing::Test {
51 : public:
52 E : void SetUp() override {
53 E : ASSERT_TRUE(scoped_symbol_path_.Setup());
54 E : }
55 :
56 : private:
57 : testing::ScopedSymbolPath scoped_symbol_path_;
58 : };
59 :
60 : } // namespace
61 :
62 E : TEST_F(HeapAnalyzerTest, AnalyzeHeap) {
63 E : if (testing::IsAppVerifierActive()) {
64 i : LOG(WARNING) << "HeapAnalyzerTest.AnalyzeHeap is incompatible with AV.";
65 i : return;
66 : }
67 :
68 E : testing::ScopedMinidump minidump;
69 E : testing::ScopedHeap heap;
70 :
71 E : ASSERT_TRUE(heap.Create());
72 :
73 E : const size_t kBlockSize = 19;
74 E : void* lfh_block = nullptr;
75 E : void* free_lfh_block = nullptr;
76 E : for (size_t tries = 0; tries < 1000 && !lfh_block; ++tries) {
77 E : void* block = heap.Allocate(kBlockSize);
78 E : if (heap.IsLFHBlock(block)) {
79 : // Grab one block to free later first.
80 E : if (free_lfh_block == nullptr)
81 E : free_lfh_block = block;
82 E : else
83 E : lfh_block = block;
84 : }
85 E : }
86 E : ASSERT_TRUE(free_lfh_block);
87 E : ASSERT_TRUE(lfh_block);
88 E : heap.Free(free_lfh_block);
89 :
90 : ASSERT_TRUE(
91 E : minidump.GenerateMinidump(testing::ScopedMinidump::kMinidumpWithData));
92 E : ProcessState process_state;
93 E : ASSERT_TRUE(AnalyzeMinidump(minidump.minidump_path(), &process_state));
94 :
95 : // Find the lfh_block allocation.
96 E : HeapAllocationLayerPtr alloc_layer;
97 E : ASSERT_TRUE(process_state.FindLayer(&alloc_layer));
98 E : std::vector<HeapAllocationRecordPtr> alloc_records;
99 E : alloc_layer->GetRecordsAt(testing::ToAddress(lfh_block), &alloc_records);
100 E : ASSERT_EQ(1U, alloc_records.size());
101 E : ASSERT_EQ(kBlockSize, alloc_records[0]->range().size());
102 E : ASSERT_FALSE(alloc_records[0]->data().is_free());
103 :
104 : // Find the free_lfh_block allocation.
105 E : alloc_layer->GetRecordsAt(testing::ToAddress(free_lfh_block), &alloc_records);
106 E : ASSERT_EQ(1U, alloc_records.size());
107 E : ASSERT_LE(kBlockSize, alloc_records[0]->range().size());
108 E : ASSERT_TRUE(alloc_records[0]->data().is_free());
109 :
110 : // Find the heap entry preceding the allocation.
111 E : HeapMetadataLayerPtr heap_meta_layer;
112 E : ASSERT_TRUE(process_state.FindLayer(&heap_meta_layer));
113 E : std::vector<HeapMetadataRecordPtr> heap_meta_records;
114 : heap_meta_layer->GetRecordsIntersecting(
115 E : AddressRange(testing::ToAddress(lfh_block) - 1, 1), &heap_meta_records);
116 E : ASSERT_EQ(1U, heap_meta_records.size());
117 E : ASSERT_FALSE(heap_meta_records[0]->data().corrupt());
118 :
119 : // Find the heap entry preceding the freed allocation.
120 : heap_meta_layer->GetRecordsIntersecting(
121 : AddressRange(testing::ToAddress(free_lfh_block) - 1, 1),
122 E : &heap_meta_records);
123 E : ASSERT_EQ(1U, heap_meta_records.size());
124 E : ASSERT_FALSE(heap_meta_records[0]->data().corrupt());
125 E : }
126 :
127 : // TODO(siggi): Test corruption etc.
128 :
129 : } // namespace refinery
|