range_map_truncate_upper_unittest.cc
1 // Copyright 2016 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 // range_map_shrink_down_unittest.cc: Unit tests for RangeMap that specifically 30 // test shrink down when ranges overlap. 31 // 32 // Author: Ivan Penkov 33 34 #ifdef HAVE_CONFIG_H 35 #include <config.h> // Must come first 36 #endif 37 38 #include <limits.h> 39 #include <stdio.h> 40 41 #include "processor/range_map-inl.h" 42 43 #include "breakpad_googletest_includes.h" 44 #include "processor/linked_ptr.h" 45 #include "processor/logging.h" 46 47 namespace { 48 49 using google_breakpad::linked_ptr; 50 using google_breakpad::MergeRangeStrategy; 51 using google_breakpad::RangeMap; 52 53 // A CountedObject holds an int. A global (not thread safe!) count of 54 // allocated CountedObjects is maintained to help test memory management. 55 class CountedObject { 56 public: 57 explicit CountedObject(int id) : id_(id) { ++count_; } 58 ~CountedObject() { --count_; } 59 60 static int count() { return count_; } 61 int id() const { return id_; } 62 63 private: 64 static int count_; 65 int id_; 66 }; 67 68 int CountedObject::count_; 69 70 typedef int AddressType; 71 typedef RangeMap<AddressType, linked_ptr<CountedObject>> TestMap; 72 73 // Same range cannot be stored wice. 74 TEST(RangeMapTruncateUpper, SameRange) { 75 TestMap range_map; 76 range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateUpper); 77 linked_ptr<CountedObject> object_1(new CountedObject(1)); 78 EXPECT_TRUE(range_map.StoreRange(0 /* base address */, 100 /* size */, 79 object_1)); 80 81 // Same range cannot be stored wice. 82 linked_ptr<CountedObject> object_2(new CountedObject(2)); 83 EXPECT_FALSE(range_map.StoreRange(0 /* base address */, 100 /* size */, 84 object_2)); 85 } 86 87 // If a range is completely contained by another range, then the larger range 88 // should be shrinked down. 89 TEST(RangeMapTruncateUpper, CompletelyContained) { 90 TestMap range_map; 91 range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateUpper); 92 // Larger range is added first. 93 linked_ptr<CountedObject> object_1(new CountedObject(1)); 94 EXPECT_TRUE(range_map.StoreRange(0 /* base address */, 100 /* size */, 95 object_1)); 96 // Smaller (contained) range is added second. 97 linked_ptr<CountedObject> object_2(new CountedObject(2)); 98 EXPECT_TRUE(range_map.StoreRange(10 /* base address */, 80 /* size */, 99 object_2)); 100 linked_ptr<CountedObject> object; 101 AddressType retrieved_base = AddressType(); 102 AddressType retrieved_delta = AddressType(); 103 AddressType retrieved_size = AddressType(); 104 // The first range contains the second, so the first range should have been 105 // shrunk to [90, 99]. Range [0, 9] should be free. 106 EXPECT_FALSE(range_map.RetrieveRange(0, &object, &retrieved_base, 107 &retrieved_delta, &retrieved_size)); 108 EXPECT_FALSE(range_map.RetrieveRange(9, &object, &retrieved_base, 109 &retrieved_delta, &retrieved_size)); 110 EXPECT_TRUE(range_map.RetrieveRange(90, &object, &retrieved_base, 111 &retrieved_delta, &retrieved_size)); 112 EXPECT_EQ(1, object->id()); 113 EXPECT_EQ(90, retrieved_base); 114 EXPECT_EQ(90, retrieved_delta); 115 EXPECT_EQ(10, retrieved_size); 116 // Validate the properties of the smaller range (should be untouched). 117 EXPECT_TRUE(range_map.RetrieveRange(10, &object, &retrieved_base, 118 &retrieved_delta, &retrieved_size)); 119 EXPECT_EQ(2, object->id()); 120 EXPECT_EQ(10, retrieved_base); 121 EXPECT_EQ(0, retrieved_delta); 122 EXPECT_EQ(80, retrieved_size); 123 } 124 125 // Same as the previous test, however the larger range is added second. 126 TEST(RangeMapTruncateUpper, CompletelyContained_LargerAddedSecond) { 127 TestMap range_map; 128 range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateUpper); 129 // Smaller (contained) range is added first. 130 linked_ptr<CountedObject> object_1(new CountedObject(1)); 131 EXPECT_TRUE(range_map.StoreRange(10 /* base address */, 80 /* size */, 132 object_1)); 133 // Larger range is added second. 134 linked_ptr<CountedObject> object_2(new CountedObject(2)); 135 EXPECT_TRUE(range_map.StoreRange(0 /* base address */, 100 /* size */, 136 object_2)); 137 linked_ptr<CountedObject> object; 138 AddressType retrieved_base = AddressType(); 139 AddressType retrieved_delta = AddressType(); 140 AddressType retrieved_size = AddressType(); 141 // The second range contains the first, so the second range should have been 142 // shrunk to [90, 99]. Range [0, 9] should be free. 143 EXPECT_FALSE(range_map.RetrieveRange(0, &object, &retrieved_base, 144 &retrieved_delta, &retrieved_size)); 145 EXPECT_FALSE(range_map.RetrieveRange(9, &object, &retrieved_base, 146 &retrieved_delta, &retrieved_size)); 147 EXPECT_TRUE(range_map.RetrieveRange(90, &object, &retrieved_base, 148 &retrieved_delta, &retrieved_size)); 149 EXPECT_EQ(2, object->id()); 150 EXPECT_EQ(90, retrieved_base); 151 EXPECT_EQ(90, retrieved_delta); 152 EXPECT_EQ(10, retrieved_size); 153 // Validate the properties of the smaller range (should be untouched). 154 EXPECT_TRUE(range_map.RetrieveRange(10, &object, &retrieved_base, 155 &retrieved_delta, &retrieved_size)); 156 EXPECT_EQ(1, object->id()); 157 EXPECT_EQ(10, retrieved_base); 158 EXPECT_EQ(0, retrieved_delta); 159 EXPECT_EQ(80, retrieved_size); 160 } 161 162 TEST(RangeMapTruncateUpper, PartialOverlap_AtBeginning) { 163 TestMap range_map; 164 range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateUpper); 165 linked_ptr<CountedObject> object_1(new CountedObject(1)); 166 EXPECT_TRUE(range_map.StoreRange(0 /* base address */, 100 /* size */, 167 object_1)); 168 169 // Partial overlap at the beginning of the new range. 170 linked_ptr<CountedObject> object_2(new CountedObject(2)); 171 EXPECT_TRUE(range_map.StoreRange(90 /* base address */, 110 /* size */, 172 object_2)); 173 174 linked_ptr<CountedObject> object; 175 AddressType retrieved_base = AddressType(); 176 AddressType retrieved_delta = AddressType(); 177 AddressType retrieved_size = AddressType(); 178 // The second range is supposed to be shrunk down so the following address 179 // should resize in the first range. 180 EXPECT_TRUE(range_map.RetrieveRange(99, &object, &retrieved_base, 181 &retrieved_delta, &retrieved_size)); 182 EXPECT_EQ(1, object->id()); 183 EXPECT_EQ(0, retrieved_base); 184 EXPECT_EQ(0, retrieved_delta); 185 EXPECT_EQ(100, retrieved_size); 186 // Validate the properties of the shrunk down range. 187 EXPECT_TRUE(range_map.RetrieveRange(100, &object, &retrieved_base, 188 &retrieved_delta, &retrieved_size)); 189 EXPECT_EQ(2, object->id()); 190 EXPECT_EQ(100, retrieved_base); 191 EXPECT_EQ(10, retrieved_delta); 192 EXPECT_EQ(100, retrieved_size); 193 } 194 195 TEST(RangeMapTruncateUpper, PartialOverlap_AtEnd) { 196 TestMap range_map; 197 range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateUpper); 198 linked_ptr<CountedObject> object_1(new CountedObject(1)); 199 EXPECT_TRUE(range_map.StoreRange(50 /* base address */, 50 /* size */, 200 object_1)); 201 202 // Partial overlap at the end of the new range. 203 linked_ptr<CountedObject> object_2(new CountedObject(2)); 204 EXPECT_TRUE(range_map.StoreRange(0 /* base address */, 70 /* size */, 205 object_2)); 206 207 linked_ptr<CountedObject> object; 208 AddressType retrieved_base = AddressType(); 209 AddressType retrieved_delta = AddressType(); 210 AddressType retrieved_size = AddressType(); 211 // The first range is supposed to be shrunk down so the following address 212 // should resize in the first range. 213 EXPECT_TRUE(range_map.RetrieveRange(69, &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(70, retrieved_size); 219 // Validate the properties of the shrunk down range. 220 EXPECT_TRUE(range_map.RetrieveRange(70, &object, &retrieved_base, 221 &retrieved_delta, &retrieved_size)); 222 EXPECT_EQ(1, object->id()); 223 EXPECT_EQ(70, retrieved_base); 224 EXPECT_EQ(20, retrieved_delta); 225 EXPECT_EQ(30, retrieved_size); 226 } 227 228 // A new range is overlapped at both ends. The new range and the range 229 // that overlaps at the end should be shrink. The range that overlaps at the 230 // beginning should be left untouched. 231 TEST(RangeMapTruncateUpper, OverlapAtBothEnds) { 232 TestMap range_map; 233 range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateUpper); 234 // This should overlap object_3 at the beginning. 235 linked_ptr<CountedObject> object_1(new CountedObject(1)); 236 EXPECT_TRUE(range_map.StoreRange(0 /* base address */, 100 /* size */, 237 object_1)); 238 239 // This should overlap object_3 at the end. 240 linked_ptr<CountedObject> object_2(new CountedObject(2)); 241 EXPECT_TRUE(range_map.StoreRange(100 /* base address */, 100 /* size */, 242 object_2)); 243 244 // This should be overlapped on both ends by object_1 and object_2. 245 linked_ptr<CountedObject> object_3(new CountedObject(3)); 246 EXPECT_TRUE(range_map.StoreRange(50 /* base address */, 100 /* size */, 247 object_3)); 248 249 linked_ptr<CountedObject> object; 250 AddressType retrieved_base = AddressType(); 251 AddressType retrieved_delta = AddressType(); 252 AddressType retrieved_size = AddressType(); 253 // The first range should be intact. 254 EXPECT_TRUE(range_map.RetrieveRange(0, &object, &retrieved_base, 255 &retrieved_delta, &retrieved_size)); 256 EXPECT_EQ(1, object->id()); 257 EXPECT_EQ(0, retrieved_base); 258 EXPECT_EQ(0, retrieved_delta); 259 EXPECT_EQ(100, retrieved_size); 260 // The second range should be shrunk down by 50. 261 EXPECT_TRUE(range_map.RetrieveRange(150, &object, &retrieved_base, 262 &retrieved_delta, &retrieved_size)); 263 EXPECT_EQ(2, object->id()); 264 EXPECT_EQ(150, retrieved_base); 265 EXPECT_EQ(50, retrieved_delta); 266 EXPECT_EQ(50, retrieved_size); 267 // The third range (in the middle) should be shrunk down by 50. 268 EXPECT_TRUE(range_map.RetrieveRange(100, &object, &retrieved_base, 269 &retrieved_delta, &retrieved_size)); 270 EXPECT_EQ(3, object->id()); 271 EXPECT_EQ(100, retrieved_base); 272 EXPECT_EQ(50, retrieved_delta); 273 EXPECT_EQ(50, retrieved_size); 274 } 275 276 TEST(RangeMapTruncateUpper, MultipleConflicts) { 277 TestMap range_map; 278 range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateUpper); 279 // This should overlap with object_3. 280 linked_ptr<CountedObject> object_1(new CountedObject(1)); 281 EXPECT_TRUE(range_map.StoreRange(10 /* base address */, 90 /* size */, 282 object_1)); 283 284 // This should also overlap with object_3 but after object_1. 285 linked_ptr<CountedObject> object_2(new CountedObject(2)); 286 EXPECT_TRUE(range_map.StoreRange(100 /* base address */, 100 /* size */, 287 object_2)); 288 289 // This should be overlapped on both object_1 and object_2. Since 290 // object_3 ends with the higher address it must be shrunk. 291 linked_ptr<CountedObject> object_3(new CountedObject(3)); 292 EXPECT_TRUE(range_map.StoreRange(0 /* base address */, 300 /* size */, 293 object_3)); 294 295 linked_ptr<CountedObject> object; 296 AddressType retrieved_base = AddressType(); 297 AddressType retrieved_delta = AddressType(); 298 AddressType retrieved_size = AddressType(); 299 // The first range should be intact. 300 EXPECT_TRUE(range_map.RetrieveRange(99, &object, &retrieved_base, 301 &retrieved_delta, &retrieved_size)); 302 EXPECT_EQ(1, object->id()); 303 EXPECT_EQ(10, retrieved_base); 304 EXPECT_EQ(0, retrieved_delta); 305 EXPECT_EQ(90, retrieved_size); 306 // The second range should be intact. 307 EXPECT_TRUE(range_map.RetrieveRange(199, &object, &retrieved_base, 308 &retrieved_delta, &retrieved_size)); 309 EXPECT_EQ(2, object->id()); 310 EXPECT_EQ(100, retrieved_base); 311 EXPECT_EQ(0, retrieved_delta); 312 EXPECT_EQ(100, retrieved_size); 313 // The third range should be shrunk down by 200. 314 EXPECT_TRUE(range_map.RetrieveRange(299, &object, &retrieved_base, 315 &retrieved_delta, &retrieved_size)); 316 EXPECT_EQ(3, object->id()); 317 EXPECT_EQ(200, retrieved_base); 318 EXPECT_EQ(200, retrieved_delta); 319 EXPECT_EQ(100, retrieved_size); 320 } 321 322 // Adding two ranges without overlap should succeed and the ranges should 323 // be left intact. 324 TEST(RangeMapTruncateUpper, NoConflicts) { 325 TestMap range_map; 326 range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateUpper); 327 // Adding range 1. 328 linked_ptr<CountedObject> object_1(new CountedObject(1)); 329 EXPECT_TRUE(range_map.StoreRange(10 /* base address */, 90 /* size */, 330 object_1)); 331 332 // Adding range 2 - no overlap with range 1. 333 linked_ptr<CountedObject> object_2(new CountedObject(2)); 334 EXPECT_TRUE(range_map.StoreRange(110 /* base address */, 90 /* size */, 335 object_2)); 336 337 linked_ptr<CountedObject> object; 338 AddressType retrieved_base = AddressType(); 339 AddressType retrieved_delta = AddressType(); 340 AddressType retrieved_size = AddressType(); 341 // The first range should be intact. 342 EXPECT_TRUE(range_map.RetrieveRange(99, &object, &retrieved_base, 343 &retrieved_delta, &retrieved_size)); 344 EXPECT_EQ(1, object->id()); 345 EXPECT_EQ(10, retrieved_base); 346 EXPECT_EQ(0, retrieved_delta); 347 EXPECT_EQ(90, retrieved_size); 348 // The second range should be intact. 349 EXPECT_TRUE(range_map.RetrieveRange(199, &object, &retrieved_base, 350 &retrieved_delta, &retrieved_size)); 351 EXPECT_EQ(2, object->id()); 352 EXPECT_EQ(110, retrieved_base); 353 EXPECT_EQ(0, retrieved_delta); 354 EXPECT_EQ(90, retrieved_size); 355 } 356 357 } // namespace