/ src / processor / range_map_truncate_lower_unittest.cc
range_map_truncate_lower_unittest.cc
  1  // Copyright 2019 Google LLC
  2  //
  3  // Redistribution and use in source and binary forms, with or without
  4  // modification, are permitted provided that the following conditions are
  5  // met:
  6  //
  7  //     * Redistributions of source code must retain the above copyright
  8  // notice, this list of conditions and the following disclaimer.
  9  //     * Redistributions in binary form must reproduce the above
 10  // copyright notice, this list of conditions and the following disclaimer
 11  // in the documentation and/or other materials provided with the
 12  // distribution.
 13  //     * Neither the name of Google LLC nor the names of its
 14  // contributors may be used to endorse or promote products derived from
 15  // this software without specific prior written permission.
 16  //
 17  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 18  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 19  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 20  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 21  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 22  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 23  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 24  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 25  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 26  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 27  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 28  
 29  #ifdef HAVE_CONFIG_H
 30  #include <config.h>  // Must come first
 31  #endif
 32  
 33  #include <limits.h>
 34  #include <stdio.h>
 35  
 36  #include "processor/range_map-inl.h"
 37  
 38  #include "breakpad_googletest_includes.h"
 39  #include "processor/linked_ptr.h"
 40  #include "processor/logging.h"
 41  
 42  namespace {
 43  
 44  using google_breakpad::linked_ptr;
 45  using google_breakpad::MergeRangeStrategy;
 46  using google_breakpad::RangeMap;
 47  
 48  // A CountedObject holds an int.  A global (not thread safe!) count of
 49  // allocated CountedObjects is maintained to help test memory management.
 50  class CountedObject {
 51   public:
 52    explicit CountedObject(int id) : id_(id) { ++count_; }
 53    ~CountedObject() { --count_; }
 54  
 55    static int count() { return count_; }
 56    int id() const { return id_; }
 57  
 58   private:
 59    static int count_;
 60    int id_;
 61  };
 62  
 63  int CountedObject::count_;
 64  
 65  typedef int AddressType;
 66  typedef RangeMap<AddressType, linked_ptr<CountedObject>> TestMap;
 67  
 68  // Same range cannot be stored wice.
 69  TEST(RangeMapTruncateLower, SameRange) {
 70    TestMap range_map;
 71    range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateLower);
 72    linked_ptr<CountedObject> object_1(new CountedObject(1));
 73    EXPECT_TRUE(
 74        range_map.StoreRange(0 /* base address */, 100 /* size */, object_1));
 75  
 76    // Same range cannot be stored wice.
 77    linked_ptr<CountedObject> object_2(new CountedObject(2));
 78    EXPECT_FALSE(
 79        range_map.StoreRange(0 /* base address */, 100 /* size */, object_2));
 80  }
 81  
 82  // If a range is completely contained by another range, then the larger range
 83  // should be truncated.
 84  TEST(RangeMapTruncateLower, CompletelyContained) {
 85    TestMap range_map;
 86    range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateLower);
 87    // Larger range is added first.
 88    linked_ptr<CountedObject> object_1(new CountedObject(1));
 89    EXPECT_TRUE(
 90        range_map.StoreRange(0 /* base address */, 100 /* size */, object_1));
 91    // Smaller (contained) range is added second.
 92    linked_ptr<CountedObject> object_2(new CountedObject(2));
 93    EXPECT_TRUE(
 94        range_map.StoreRange(10 /* base address */, 80 /* size */, object_2));
 95    linked_ptr<CountedObject> object;
 96    AddressType retrieved_base = AddressType();
 97    AddressType retrieved_delta = AddressType();
 98    AddressType retrieved_size = AddressType();
 99    // The first range contains the second, so the first range should have been
100    // shrunk to [0, 10].  Range [90, 99] should be free.
101    EXPECT_FALSE(range_map.RetrieveRange(90, &object, &retrieved_base,
102                                         &retrieved_delta, &retrieved_size));
103    EXPECT_FALSE(range_map.RetrieveRange(99, &object, &retrieved_base,
104                                         &retrieved_delta, &retrieved_size));
105    EXPECT_TRUE(range_map.RetrieveRange(9, &object, &retrieved_base,
106                                        &retrieved_delta, &retrieved_size));
107    EXPECT_EQ(1, object->id());
108    EXPECT_EQ(0, retrieved_base);
109    EXPECT_EQ(0, retrieved_delta);
110    EXPECT_EQ(10, retrieved_size);
111    // Validate the properties of the smaller range (should be untouched).
112    EXPECT_TRUE(range_map.RetrieveRange(10, &object, &retrieved_base,
113                                        &retrieved_delta, &retrieved_size));
114    EXPECT_EQ(2, object->id());
115    EXPECT_EQ(10, retrieved_base);
116    EXPECT_EQ(0, retrieved_delta);
117    EXPECT_EQ(80, retrieved_size);
118  }
119  
120  // Same as the previous test, however the larger range is added second.
121  TEST(RangeMapTruncateLower, CompletelyContained_LargerAddedSecond) {
122    TestMap range_map;
123    range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateLower);
124    // Smaller (contained) range is added first.
125    linked_ptr<CountedObject> object_1(new CountedObject(1));
126    EXPECT_TRUE(
127        range_map.StoreRange(10 /* base address */, 80 /* size */, object_1));
128    // Larger range is added second.
129    linked_ptr<CountedObject> object_2(new CountedObject(2));
130    EXPECT_TRUE(
131        range_map.StoreRange(0 /* base address */, 100 /* size */, object_2));
132    linked_ptr<CountedObject> object;
133    AddressType retrieved_base = AddressType();
134    AddressType retrieved_delta = AddressType();
135    AddressType retrieved_size = AddressType();
136    // The second range contains the first, so the second range should have been
137    // truncated to [0, 9].  Range [90, 99] should be free.
138    EXPECT_FALSE(range_map.RetrieveRange(90, &object, &retrieved_base,
139                                         &retrieved_delta, &retrieved_size));
140    EXPECT_FALSE(range_map.RetrieveRange(99, &object, &retrieved_base,
141                                         &retrieved_delta, &retrieved_size));
142    EXPECT_TRUE(range_map.RetrieveRange(9, &object, &retrieved_base,
143                                        &retrieved_delta, &retrieved_size));
144    EXPECT_EQ(2, object->id());
145    EXPECT_EQ(0, retrieved_base);
146    EXPECT_EQ(0, retrieved_delta);
147    EXPECT_EQ(10, retrieved_size);
148    // Validate the properties of the smaller range (should be untouched).
149    EXPECT_TRUE(range_map.RetrieveRange(10, &object, &retrieved_base,
150                                        &retrieved_delta, &retrieved_size));
151    EXPECT_EQ(1, object->id());
152    EXPECT_EQ(10, retrieved_base);
153    EXPECT_EQ(0, retrieved_delta);
154    EXPECT_EQ(80, retrieved_size);
155  }
156  
157  TEST(RangeMapTruncateLower, PartialOverlap_AtBeginning) {
158    TestMap range_map;
159    range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateLower);
160    linked_ptr<CountedObject> object_1(new CountedObject(1));
161    EXPECT_TRUE(
162        range_map.StoreRange(0 /* base address */, 100 /* size */, object_1));
163  
164    // Partial overlap at the beginning of the new range.
165    linked_ptr<CountedObject> object_2(new CountedObject(2));
166    EXPECT_TRUE(
167        range_map.StoreRange(90 /* base address */, 110 /* size */, object_2));
168  
169    linked_ptr<CountedObject> object;
170    AddressType retrieved_base = AddressType();
171    AddressType retrieved_delta = AddressType();
172    AddressType retrieved_size = AddressType();
173    // The first range should be truncated, so 99 should address the second range.
174    EXPECT_TRUE(range_map.RetrieveRange(99, &object, &retrieved_base,
175                                        &retrieved_delta, &retrieved_size));
176    EXPECT_EQ(2, object->id());
177    EXPECT_EQ(90, retrieved_base);
178    EXPECT_EQ(0, retrieved_delta);
179    EXPECT_EQ(110, retrieved_size);
180    // Validate the properties of the truncated range.
181    EXPECT_TRUE(range_map.RetrieveRange(89, &object, &retrieved_base,
182                                        &retrieved_delta, &retrieved_size));
183    EXPECT_EQ(1, object->id());
184    EXPECT_EQ(0, retrieved_base);
185    EXPECT_EQ(0, retrieved_delta);
186    EXPECT_EQ(90, retrieved_size);
187  }
188  
189  TEST(RangeMapTruncateLower, PartialOverlap_AtEnd) {
190    TestMap range_map;
191    range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateLower);
192    linked_ptr<CountedObject> object_1(new CountedObject(1));
193    EXPECT_TRUE(
194        range_map.StoreRange(50 /* base address */, 50 /* size */, object_1));
195  
196    // Partial overlap at the end of the new range.
197    linked_ptr<CountedObject> object_2(new CountedObject(2));
198    EXPECT_TRUE(
199        range_map.StoreRange(0 /* base address */, 70 /* size */, object_2));
200  
201    linked_ptr<CountedObject> object;
202    AddressType retrieved_base = AddressType();
203    AddressType retrieved_delta = AddressType();
204    AddressType retrieved_size = AddressType();
205    // The second range should be truncated so 69 addresses the first range.
206    EXPECT_TRUE(range_map.RetrieveRange(69, &object, &retrieved_base,
207                                        &retrieved_delta, &retrieved_size));
208    EXPECT_EQ(1, object->id());
209    EXPECT_EQ(50, retrieved_base);
210    EXPECT_EQ(0, retrieved_delta);
211    EXPECT_EQ(50, retrieved_size);
212    // Validate the properties of the truncated range.
213    EXPECT_TRUE(range_map.RetrieveRange(49, &object, &retrieved_base,
214                                        &retrieved_delta, &retrieved_size));
215    EXPECT_EQ(2, object->id());
216    EXPECT_EQ(0, retrieved_base);
217    EXPECT_EQ(0, retrieved_delta);
218    EXPECT_EQ(50, retrieved_size);
219  }
220  
221  // A new range is overlapped at both ends.  The new range and the range
222  // that overlaps at the beginning should be truncated.  The range that overlaps
223  // at the end should be left untouched.
224  TEST(RangeMapTruncateLower, OverlapAtBothEnds) {
225    TestMap range_map;
226    range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateLower);
227    // This should overlap object_3 at the beginning.
228    linked_ptr<CountedObject> object_1(new CountedObject(1));
229    EXPECT_TRUE(
230        range_map.StoreRange(0 /* base address */, 100 /* size */, object_1));
231  
232    // This should overlap object_3 at the end.
233    linked_ptr<CountedObject> object_2(new CountedObject(2));
234    EXPECT_TRUE(
235        range_map.StoreRange(100 /* base address */, 100 /* size */, object_2));
236  
237    // This should be overlapped on both ends by object_1 and object_2.
238    linked_ptr<CountedObject> object_3(new CountedObject(3));
239    EXPECT_TRUE(
240        range_map.StoreRange(50 /* base address */, 100 /* size */, object_3));
241  
242    linked_ptr<CountedObject> object;
243    AddressType retrieved_base = AddressType();
244    AddressType retrieved_delta = AddressType();
245    AddressType retrieved_size = AddressType();
246    // The first range should be truncated.
247    EXPECT_TRUE(range_map.RetrieveRange(0, &object, &retrieved_base,
248                                        &retrieved_delta, &retrieved_size));
249    EXPECT_EQ(1, object->id());
250    EXPECT_EQ(0, retrieved_base);
251    EXPECT_EQ(0, retrieved_delta);
252    EXPECT_EQ(50, retrieved_size);
253    // The second range should be intact.
254    EXPECT_TRUE(range_map.RetrieveRange(150, &object, &retrieved_base,
255                                        &retrieved_delta, &retrieved_size));
256    EXPECT_EQ(2, object->id());
257    EXPECT_EQ(100, retrieved_base);
258    EXPECT_EQ(0, retrieved_delta);
259    EXPECT_EQ(100, retrieved_size);
260    // The third range (in the middle) should be truncated.
261    EXPECT_TRUE(range_map.RetrieveRange(99, &object, &retrieved_base,
262                                        &retrieved_delta, &retrieved_size));
263    EXPECT_EQ(3, object->id());
264    EXPECT_EQ(50, retrieved_base);
265    EXPECT_EQ(0, retrieved_delta);
266    EXPECT_EQ(50, retrieved_size);
267  }
268  
269  TEST(RangeMapTruncateLower, MultipleConflicts) {
270    TestMap range_map;
271    range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateLower);
272    // This should overlap with object_3.
273    linked_ptr<CountedObject> object_1(new CountedObject(1));
274    EXPECT_TRUE(
275        range_map.StoreRange(10 /* base address */, 90 /* size */, object_1));
276  
277    // This should also overlap with object_3 but after object_1.
278    linked_ptr<CountedObject> object_2(new CountedObject(2));
279    EXPECT_TRUE(
280        range_map.StoreRange(100 /* base address */, 100 /* size */, object_2));
281  
282    // This should be overlapped on both object_1 and object_2.
283    linked_ptr<CountedObject> object_3(new CountedObject(3));
284    EXPECT_TRUE(
285        range_map.StoreRange(0 /* base address */, 300 /* size */, object_3));
286  
287    linked_ptr<CountedObject> object;
288    AddressType retrieved_base = AddressType();
289    AddressType retrieved_delta = AddressType();
290    AddressType retrieved_size = AddressType();
291    // The first range should be intact.
292    EXPECT_TRUE(range_map.RetrieveRange(99, &object, &retrieved_base,
293                                        &retrieved_delta, &retrieved_size));
294    EXPECT_EQ(1, object->id());
295    EXPECT_EQ(10, retrieved_base);
296    EXPECT_EQ(0, retrieved_delta);
297    EXPECT_EQ(90, retrieved_size);
298    // The second range should be intact.
299    EXPECT_TRUE(range_map.RetrieveRange(199, &object, &retrieved_base,
300                                        &retrieved_delta, &retrieved_size));
301    EXPECT_EQ(2, object->id());
302    EXPECT_EQ(100, retrieved_base);
303    EXPECT_EQ(0, retrieved_delta);
304    EXPECT_EQ(100, retrieved_size);
305    // The third range should be truncated.
306    EXPECT_TRUE(range_map.RetrieveRange(9, &object, &retrieved_base,
307                                        &retrieved_delta, &retrieved_size));
308    EXPECT_EQ(3, object->id());
309    EXPECT_EQ(0, retrieved_base);
310    EXPECT_EQ(0, retrieved_delta);
311    EXPECT_EQ(10, retrieved_size);
312  }
313  
314  // Adding two ranges without overlap should succeed and the ranges should
315  // be left intact.
316  TEST(RangeMapTruncateLower, NoConflicts) {
317    TestMap range_map;
318    range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateLower);
319    // Adding range 1.
320    linked_ptr<CountedObject> object_1(new CountedObject(1));
321    EXPECT_TRUE(
322        range_map.StoreRange(10 /* base address */, 90 /* size */, object_1));
323  
324    // Adding range 2 - no overlap with range 1.
325    linked_ptr<CountedObject> object_2(new CountedObject(2));
326    EXPECT_TRUE(
327        range_map.StoreRange(110 /* base address */, 90 /* size */, object_2));
328  
329    linked_ptr<CountedObject> object;
330    AddressType retrieved_base = AddressType();
331    AddressType retrieved_delta = AddressType();
332    AddressType retrieved_size = AddressType();
333    // The first range should be intact.
334    EXPECT_TRUE(range_map.RetrieveRange(99, &object, &retrieved_base,
335                                        &retrieved_delta, &retrieved_size));
336    EXPECT_EQ(1, object->id());
337    EXPECT_EQ(10, retrieved_base);
338    EXPECT_EQ(0, retrieved_delta);
339    EXPECT_EQ(90, retrieved_size);
340    // The second range should be intact.
341    EXPECT_TRUE(range_map.RetrieveRange(199, &object, &retrieved_base,
342                                        &retrieved_delta, &retrieved_size));
343    EXPECT_EQ(2, object->id());
344    EXPECT_EQ(110, retrieved_base);
345    EXPECT_EQ(0, retrieved_delta);
346    EXPECT_EQ(90, retrieved_size);
347  }
348  
349  }  // namespace