1 : // Copyright 2016 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/agent/asan/reporters/kasko_reporter.h"
16 :
17 : #include "base/bind.h"
18 : #include "gmock/gmock.h"
19 : #include "gtest/gtest.h"
20 :
21 : namespace agent {
22 : namespace asan {
23 : namespace reporters {
24 :
25 : namespace {
26 :
27 : using testing::_;
28 :
29 : static const char* kDummyAddress =
30 : reinterpret_cast<const char*>(0xBAADCA57);
31 : static EXCEPTION_POINTERS* kDummyExceptionPointers =
32 : reinterpret_cast<EXCEPTION_POINTERS*>(0xBAADF00D);
33 :
34 : class LenientMockKaskoFunctions {
35 : public:
36 E : LenientMockKaskoFunctions() {}
37 E : virtual ~LenientMockKaskoFunctions() {}
38 :
39 E : MOCK_METHOD3(ReportCrashWithProtobuf, void(EXCEPTION_POINTERS* info,
40 : const char* protobuf,
41 E : size_t protobuf_length));
42 E : MOCK_METHOD5(ReportCrashWithProtobufAndMemoryRanges,
43 : void(EXCEPTION_POINTERS* info,
44 : const char* protobuf,
45 : size_t protobuf_length,
46 : const void* const* base_addresses,
47 E : const size_t* lengths));
48 E : MOCK_METHOD2(SetCrashKeyValueImpl, void(const wchar_t* key,
49 E : const wchar_t* value));
50 : private:
51 : DISALLOW_COPY_AND_ASSIGN(LenientMockKaskoFunctions);
52 : };
53 : using MockKaskoFunctions = testing::StrictMock<LenientMockKaskoFunctions>;
54 :
55 : } // namespace
56 :
57 : class KaskoReporterTest : public testing::Test {
58 : public:
59 E : KaskoReporterTest() {}
60 E : virtual ~KaskoReporterTest() {}
61 :
62 E : void BindReportCrashWithProtobuf() {
63 E : kasko_functions_.report_crash_with_protobuf.set_callback(
64 : base::Bind(&MockKaskoFunctions::ReportCrashWithProtobuf,
65 : base::Unretained(&mock_)));
66 E : }
67 :
68 E : void BindReportCrashWithProtobufAndMemoryRanges() {
69 E : kasko_functions_.report_crash_with_protobuf_and_memory_ranges.set_callback(
70 : base::Bind(&MockKaskoFunctions::ReportCrashWithProtobufAndMemoryRanges,
71 : base::Unretained(&mock_)));
72 E : }
73 :
74 E : void BindSetCrashKeyValueImpl() {
75 E : kasko_functions_.set_crash_key_value_impl.set_callback(
76 : base::Bind(&MockKaskoFunctions::SetCrashKeyValueImpl,
77 : base::Unretained(&mock_)));
78 E : }
79 :
80 E : void BindAll() {
81 E : BindReportCrashWithProtobuf();
82 E : BindReportCrashWithProtobufAndMemoryRanges();
83 E : BindSetCrashKeyValueImpl();
84 E : }
85 :
86 E : void CreateReporter() {
87 E : reporter_.reset(new KaskoReporter(kasko_functions_));
88 E : }
89 :
90 : // @name Access to KaskoReporter internals.
91 : // @{
92 E : static bool SupportsEarlyCrashKeys() {
93 E : return KaskoReporter::SupportsEarlyCrashKeys();
94 E : }
95 E : const std::vector<const void*>& range_bases() const {
96 E : return reporter_->range_bases_;
97 E : }
98 E : const std::vector<size_t>& range_lengths() const {
99 E : return reporter_->range_lengths_;
100 E : }
101 E : const std::string& protobuf() const {
102 E : return reporter_->protobuf_;
103 E : }
104 : // @}
105 :
106 : std::unique_ptr<KaskoReporter> reporter_;
107 : KaskoReporter::KaskoFunctions kasko_functions_;
108 : MockKaskoFunctions mock_;
109 : };
110 :
111 E : TEST_F(KaskoReporterTest, CreateFails) {
112 : // This should fail because the unittest executable doesn't satisfy the
113 : // expected exports.
114 E : reporter_ = KaskoReporter::Create();
115 E : EXPECT_TRUE(reporter_.get() == nullptr);
116 E : }
117 :
118 E : TEST_F(KaskoReporterTest, SupportsEarlyCrashKeysFails) {
119 E : EXPECT_FALSE(SupportsEarlyCrashKeys());
120 E : }
121 :
122 E : TEST_F(KaskoReporterTest, AreValid) {
123 E : EXPECT_FALSE(KaskoReporter::AreValid(kasko_functions_));
124 E : BindSetCrashKeyValueImpl();
125 E : EXPECT_FALSE(KaskoReporter::AreValid(kasko_functions_));
126 E : BindReportCrashWithProtobuf();
127 E : EXPECT_TRUE(KaskoReporter::AreValid(kasko_functions_));
128 E : BindReportCrashWithProtobufAndMemoryRanges();
129 E : EXPECT_TRUE(KaskoReporter::AreValid(kasko_functions_));
130 E : kasko_functions_.set_crash_key_value_impl.Reset();
131 E : EXPECT_FALSE(KaskoReporter::AreValid(kasko_functions_));
132 E : }
133 :
134 E : TEST_F(KaskoReporterTest, BasicPropertiesWithMemoryRanges) {
135 E : BindAll();
136 E : CreateReporter();
137 :
138 E : EXPECT_TRUE(reporter_->GetName() != nullptr);
139 E : EXPECT_EQ(ReporterInterface::FEATURE_CRASH_KEYS |
140 : ReporterInterface::FEATURE_MEMORY_RANGES |
141 : ReporterInterface::FEATURE_CUSTOM_STREAMS,
142 E : reporter_->GetFeatures());
143 E : }
144 :
145 E : TEST_F(KaskoReporterTest, BasicPropertiesWithoutMemoryRanges) {
146 E : BindReportCrashWithProtobuf();
147 E : BindSetCrashKeyValueImpl();
148 E : CreateReporter();
149 :
150 E : EXPECT_TRUE(reporter_->GetName() != nullptr);
151 E : EXPECT_EQ(ReporterInterface::FEATURE_CRASH_KEYS |
152 : ReporterInterface::FEATURE_CUSTOM_STREAMS,
153 E : reporter_->GetFeatures());
154 E : }
155 :
156 E : TEST_F(KaskoReporterTest, SetCrashKey) {
157 E : BindAll();
158 E : CreateReporter();
159 :
160 E : EXPECT_CALL(mock_, SetCrashKeyValueImpl(testing::StrEq(L"key"),
161 : testing::StrEq(L"value")));
162 E : EXPECT_TRUE(reporter_->SetCrashKey("key", "value"));
163 E : }
164 :
165 E : TEST_F(KaskoReporterTest, SetMemoryRangesFails) {
166 E : BindReportCrashWithProtobuf();
167 E : BindSetCrashKeyValueImpl();
168 E : CreateReporter();
169 :
170 E : ReporterInterface::MemoryRanges memory_ranges;
171 E : memory_ranges.push_back(ReporterInterface::MemoryRange(kDummyAddress, 42));
172 E : EXPECT_FALSE(reporter_->SetMemoryRanges(memory_ranges));
173 E : }
174 :
175 E : TEST_F(KaskoReporterTest, SetMemoryRangesSucceeds) {
176 E : BindAll();
177 E : CreateReporter();
178 :
179 E : ReporterInterface::MemoryRanges memory_ranges;
180 E : memory_ranges.push_back(ReporterInterface::MemoryRange(kDummyAddress, 42));
181 E : EXPECT_TRUE(reporter_->SetMemoryRanges(memory_ranges));
182 E : EXPECT_THAT(range_bases(),
183 : testing::ElementsAre(reinterpret_cast<const void*>(kDummyAddress),
184 E : reinterpret_cast<const void*>(nullptr)));
185 E : EXPECT_THAT(range_lengths(), testing::ElementsAre(42, 0));
186 E : }
187 :
188 E : TEST_F(KaskoReporterTest, SetCustomStream) {
189 E : BindAll();
190 E : CreateReporter();
191 :
192 E : std::string s("hey");
193 E : EXPECT_FALSE(reporter_->SetCustomStream(
194 : ReporterInterface::kCrashdataProtobufStreamType + 1,
195 : reinterpret_cast<const uint8_t*>(s.data()),
196 E : s.size()));
197 E : EXPECT_TRUE(reporter_->SetCustomStream(
198 : ReporterInterface::kCrashdataProtobufStreamType,
199 : reinterpret_cast<const uint8_t*>(s.data()),
200 E : s.size()));
201 E : EXPECT_THAT(protobuf(), testing::StrEq(s));
202 E : }
203 :
204 E : TEST_F(KaskoReporterTest, DumpWithoutCrashFails) {
205 E : BindAll();
206 E : CreateReporter();
207 :
208 E : CONTEXT dummy_context = {};
209 E : EXPECT_FALSE(reporter_->DumpWithoutCrash(dummy_context));
210 E : }
211 :
212 E : TEST_F(KaskoReporterTest, DumpWithoutMemoryRanges) {
213 E : BindReportCrashWithProtobuf();
214 E : BindSetCrashKeyValueImpl();
215 E : CreateReporter();
216 :
217 E : std::string s("hey");
218 E : ASSERT_TRUE(reporter_->SetCustomStream(
219 : ReporterInterface::kCrashdataProtobufStreamType,
220 : reinterpret_cast<const uint8_t*>(s.data()),
221 E : s.size() + 1));
222 :
223 E : EXPECT_CALL(mock_, ReportCrashWithProtobuf(
224 : testing::Eq(kDummyExceptionPointers),
225 : testing::Eq(protobuf().data()),
226 : testing::Eq(protobuf().size())));
227 E : reporter_->DumpAndCrash(kDummyExceptionPointers);
228 E : }
229 :
230 E : TEST_F(KaskoReporterTest, DumpWithMemoryRanges) {
231 E : BindAll();
232 E : CreateReporter();
233 :
234 E : std::string s("hey");
235 E : ASSERT_TRUE(reporter_->SetCustomStream(
236 : ReporterInterface::kCrashdataProtobufStreamType,
237 : reinterpret_cast<const uint8_t*>(s.data()),
238 E : s.size() + 1));
239 :
240 E : ReporterInterface::MemoryRanges memory_ranges;
241 E : memory_ranges.push_back(ReporterInterface::MemoryRange(kDummyAddress, 42));
242 E : ASSERT_TRUE(reporter_->SetMemoryRanges(memory_ranges));
243 :
244 E : EXPECT_CALL(mock_, ReportCrashWithProtobufAndMemoryRanges(
245 : testing::Eq(kDummyExceptionPointers),
246 : testing::Eq(protobuf().data()),
247 : testing::Eq(protobuf().size()),
248 : testing::Eq(range_bases().data()),
249 : testing::Eq(range_lengths().data())));
250 E : reporter_->DumpAndCrash(kDummyExceptionPointers);
251 E : }
252 :
253 : } // namespace reporters
254 : } // namespace asan
255 : } // namespace agent
|