1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <assert.h> 30 #include <ctype.h> 31 #include <errno.h> 32 #include <limits.h> 33 #include <signal.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <sys/cdefs.h> 37 38 #include <string> 39 #include <vector> 40 41 #include <private/bionic_macros.h> 42 43 #include "Config.h" 44 #include "debug_log.h" 45 46 // Config constants 47 static constexpr uint8_t DEFAULT_FILL_ALLOC_VALUE = 0xeb; 48 static constexpr uint8_t DEFAULT_FILL_FREE_VALUE = 0xef; 49 50 static constexpr uint8_t DEFAULT_FRONT_GUARD_VALUE = 0xaa; 51 static constexpr uint8_t DEFAULT_REAR_GUARD_VALUE = 0xbb; 52 53 // Used as the default for all guard values. 54 static constexpr size_t DEFAULT_GUARD_BYTES = 32; 55 static constexpr size_t MAX_GUARD_BYTES = 16384; 56 57 static constexpr size_t DEFAULT_BACKTRACE_FRAMES = 16; 58 static constexpr size_t MAX_BACKTRACE_FRAMES = 256; 59 static constexpr const char DEFAULT_BACKTRACE_DUMP_PREFIX[] = "/data/local/tmp/backtrace_heap"; 60 61 static constexpr size_t DEFAULT_EXPAND_BYTES = 16; 62 static constexpr size_t MAX_EXPAND_BYTES = 16384; 63 64 static constexpr size_t DEFAULT_FREE_TRACK_ALLOCATIONS = 100; 65 static constexpr size_t MAX_FREE_TRACK_ALLOCATIONS = 16384; 66 67 static constexpr size_t DEFAULT_RECORD_ALLOCS = 8000000; 68 static constexpr size_t MAX_RECORD_ALLOCS = 50000000; 69 static constexpr const char DEFAULT_RECORD_ALLOCS_FILE[] = "/data/local/tmp/record_allocs.txt"; 70 71 const std::unordered_map<std::string, Config::OptionInfo> Config::kOptions = { 72 { 73 "guard", {FRONT_GUARD | REAR_GUARD | TRACK_ALLOCS, &Config::SetGuard}, 74 }, 75 { 76 "front_guard", {FRONT_GUARD | TRACK_ALLOCS, &Config::SetFrontGuard}, 77 }, 78 { 79 "rear_guard", {REAR_GUARD | TRACK_ALLOCS, &Config::SetRearGuard}, 80 }, 81 82 { 83 "backtrace", {BACKTRACE | TRACK_ALLOCS, &Config::SetBacktrace}, 84 }, 85 { 86 "backtrace_enable_on_signal", 87 {BACKTRACE | TRACK_ALLOCS, &Config::SetBacktraceEnableOnSignal}, 88 }, 89 90 { 91 "backtrace_dump_on_exit", {0, &Config::SetBacktraceDumpOnExit}, 92 }, 93 { 94 "backtrace_dump_prefix", {0, &Config::SetBacktraceDumpPrefix}, 95 }, 96 { 97 "backtrace_full", {BACKTRACE_FULL, &Config::VerifyValueEmpty}, 98 }, 99 100 { 101 "fill", {FILL_ON_ALLOC | FILL_ON_FREE, &Config::SetFill}, 102 }, 103 { 104 "fill_on_alloc", {FILL_ON_ALLOC, &Config::SetFillOnAlloc}, 105 }, 106 { 107 "fill_on_free", {FILL_ON_FREE, &Config::SetFillOnFree}, 108 }, 109 110 { 111 "expand_alloc", {EXPAND_ALLOC, &Config::SetExpandAlloc}, 112 }, 113 114 { 115 "free_track", {FREE_TRACK | FILL_ON_FREE | TRACK_ALLOCS, &Config::SetFreeTrack}, 116 }, 117 { 118 "free_track_backtrace_num_frames", {0, &Config::SetFreeTrackBacktraceNumFrames}, 119 }, 120 121 { 122 "leak_track", {LEAK_TRACK | TRACK_ALLOCS, &Config::VerifyValueEmpty}, 123 }, 124 125 { 126 "record_allocs", {RECORD_ALLOCS, &Config::SetRecordAllocs}, 127 }, 128 { 129 "record_allocs_file", {0, &Config::SetRecordAllocsFile}, 130 }, 131 132 { 133 "verify_pointers", {TRACK_ALLOCS, &Config::VerifyValueEmpty}, 134 }, 135 { 136 "abort_on_error", {ABORT_ON_ERROR, &Config::VerifyValueEmpty}, 137 }, 138 { 139 "verbose", {VERBOSE, &Config::VerifyValueEmpty}, 140 }, 141 }; 142 143 bool Config::ParseValue(const std::string& option, const std::string& value, size_t min_value, 144 size_t max_value, size_t* parsed_value) const { 145 assert(!value.empty()); 146 147 // Parse the value into a size_t value. 148 errno = 0; 149 char* end; 150 long long_value = strtol(value.c_str(), &end, 10); 151 if (errno != 0) { 152 error_log("%s: bad value for option '%s': %s", getprogname(), option.c_str(), strerror(errno)); 153 return false; 154 } 155 if (end == value.c_str()) { 156 error_log("%s: bad value for option '%s'", getprogname(), option.c_str()); 157 return false; 158 } 159 if (static_cast<size_t>(end - value.c_str()) != value.size()) { 160 error_log("%s: bad value for option '%s', non space found after option: %s", getprogname(), 161 option.c_str(), end); 162 return false; 163 } 164 if (long_value < 0) { 165 error_log("%s: bad value for option '%s', value cannot be negative: %ld", getprogname(), 166 option.c_str(), long_value); 167 return false; 168 } 169 170 if (static_cast<size_t>(long_value) < min_value) { 171 error_log("%s: bad value for option '%s', value must be >= %zu: %ld", getprogname(), 172 option.c_str(), min_value, long_value); 173 return false; 174 } 175 if (static_cast<size_t>(long_value) > max_value) { 176 error_log("%s: bad value for option '%s', value must be <= %zu: %ld", getprogname(), 177 option.c_str(), max_value, long_value); 178 return false; 179 } 180 *parsed_value = static_cast<size_t>(long_value); 181 return true; 182 } 183 184 bool Config::ParseValue(const std::string& option, const std::string& value, size_t default_value, 185 size_t min_value, size_t max_value, size_t* new_value) const { 186 if (value.empty()) { 187 *new_value = default_value; 188 return true; 189 } 190 return ParseValue(option, value, min_value, max_value, new_value); 191 } 192 193 bool Config::SetGuard(const std::string& option, const std::string& value) { 194 if (value.empty()) { 195 // Set the defaults. 196 front_guard_bytes_ = DEFAULT_GUARD_BYTES; 197 rear_guard_bytes_ = DEFAULT_GUARD_BYTES; 198 return true; 199 } 200 201 if (!ParseValue(option, value, 1, MAX_GUARD_BYTES, &rear_guard_bytes_)) { 202 return false; 203 } 204 205 // It's necessary to align the front guard to MINIMUM_ALIGNMENT_BYTES to 206 // make sure that the header is aligned properly. 207 front_guard_bytes_ = __BIONIC_ALIGN(rear_guard_bytes_, MINIMUM_ALIGNMENT_BYTES); 208 return true; 209 } 210 211 bool Config::SetFrontGuard(const std::string& option, const std::string& value) { 212 if (!ParseValue(option, value, DEFAULT_GUARD_BYTES, 1, MAX_GUARD_BYTES, &front_guard_bytes_)) { 213 return false; 214 } 215 // It's necessary to align the front guard to MINIMUM_ALIGNMENT_BYTES to 216 // make sure that the header is aligned properly. 217 front_guard_bytes_ = __BIONIC_ALIGN(front_guard_bytes_, MINIMUM_ALIGNMENT_BYTES); 218 return true; 219 } 220 221 bool Config::SetRearGuard(const std::string& option, const std::string& value) { 222 return ParseValue(option, value, DEFAULT_GUARD_BYTES, 1, MAX_GUARD_BYTES, &rear_guard_bytes_); 223 } 224 225 bool Config::SetFill(const std::string& option, const std::string& value) { 226 if (value.empty()) { 227 // Set the defaults. 228 fill_on_alloc_bytes_ = SIZE_MAX; 229 fill_on_free_bytes_ = SIZE_MAX; 230 return true; 231 } 232 233 if (!ParseValue(option, value, 1, SIZE_MAX, &fill_on_alloc_bytes_)) { 234 return false; 235 } 236 fill_on_free_bytes_ = fill_on_alloc_bytes_; 237 return true; 238 } 239 240 bool Config::SetFillOnAlloc(const std::string& option, const std::string& value) { 241 return ParseValue(option, value, SIZE_MAX, 1, SIZE_MAX, &fill_on_alloc_bytes_); 242 } 243 244 bool Config::SetFillOnFree(const std::string& option, const std::string& value) { 245 return ParseValue(option, value, SIZE_MAX, 1, SIZE_MAX, &fill_on_free_bytes_); 246 } 247 248 bool Config::SetBacktrace(const std::string& option, const std::string& value) { 249 backtrace_enabled_ = true; 250 return ParseValue(option, value, DEFAULT_BACKTRACE_FRAMES, 1, MAX_BACKTRACE_FRAMES, 251 &backtrace_frames_); 252 } 253 254 bool Config::SetBacktraceEnableOnSignal(const std::string& option, const std::string& value) { 255 backtrace_enable_on_signal_ = true; 256 return ParseValue(option, value, DEFAULT_BACKTRACE_FRAMES, 1, MAX_BACKTRACE_FRAMES, 257 &backtrace_frames_); 258 } 259 260 bool Config::SetBacktraceDumpOnExit(const std::string& option, const std::string& value) { 261 if (Config::VerifyValueEmpty(option, value)) { 262 backtrace_dump_on_exit_ = true; 263 return true; 264 } 265 return false; 266 } 267 268 bool Config::SetBacktraceDumpPrefix(const std::string&, const std::string& value) { 269 if (value.empty()) { 270 backtrace_dump_prefix_ = DEFAULT_BACKTRACE_DUMP_PREFIX; 271 } else { 272 backtrace_dump_prefix_ = value; 273 } 274 return true; 275 } 276 277 bool Config::SetExpandAlloc(const std::string& option, const std::string& value) { 278 return ParseValue(option, value, DEFAULT_EXPAND_BYTES, 1, MAX_EXPAND_BYTES, &expand_alloc_bytes_); 279 } 280 281 bool Config::SetFreeTrack(const std::string& option, const std::string& value) { 282 // This option enables fill on free, so set the bytes to the default value. 283 if (fill_on_free_bytes_ == 0) { 284 fill_on_free_bytes_ = SIZE_MAX; 285 } 286 if (free_track_backtrace_num_frames_ == 0) { 287 free_track_backtrace_num_frames_ = DEFAULT_BACKTRACE_FRAMES; 288 } 289 290 return ParseValue(option, value, DEFAULT_FREE_TRACK_ALLOCATIONS, 1, MAX_FREE_TRACK_ALLOCATIONS, 291 &free_track_allocations_); 292 } 293 294 bool Config::SetFreeTrackBacktraceNumFrames(const std::string& option, const std::string& value) { 295 return ParseValue(option, value, DEFAULT_BACKTRACE_FRAMES, 0, MAX_BACKTRACE_FRAMES, 296 &free_track_backtrace_num_frames_); 297 } 298 299 bool Config::SetRecordAllocs(const std::string& option, const std::string& value) { 300 if (record_allocs_file_.empty()) { 301 record_allocs_file_ = DEFAULT_RECORD_ALLOCS_FILE; 302 } 303 return ParseValue(option, value, DEFAULT_RECORD_ALLOCS, 1, MAX_RECORD_ALLOCS, 304 &record_allocs_num_entries_); 305 } 306 307 bool Config::SetRecordAllocsFile(const std::string&, const std::string& value) { 308 if (value.empty()) { 309 // Set the default. 310 record_allocs_file_ = DEFAULT_RECORD_ALLOCS_FILE; 311 return true; 312 } 313 record_allocs_file_ = value; 314 return true; 315 } 316 317 bool Config::VerifyValueEmpty(const std::string& option, const std::string& value) { 318 if (!value.empty()) { 319 // This is not valid. 320 error_log("%s: value set for option '%s' which does not take a value", getprogname(), 321 option.c_str()); 322 return false; 323 } 324 return true; 325 } 326 327 void Config::LogUsage() const { 328 error_log("For malloc debug option descriptions go to:"); 329 error_log(" https://android.googlesource.com/platform/bionic/+/master/libc/malloc_debug/README.md"); 330 } 331 332 bool Config::GetOption(const char** options_str, std::string* option, std::string* value) { 333 const char* cur = *options_str; 334 // Process each property name we can find. 335 while (isspace(*cur)) ++cur; 336 337 if (*cur == '\0') { 338 *options_str = cur; 339 return false; 340 } 341 342 const char* start = cur; 343 while (!isspace(*cur) && *cur != '=' && *cur != '\0') ++cur; 344 345 *option = std::string(start, cur - start); 346 347 // Skip any spaces after the name. 348 while (isspace(*cur)) ++cur; 349 350 value->clear(); 351 if (*cur == '=') { 352 ++cur; 353 // Skip the space after the equal. 354 while (isspace(*cur)) ++cur; 355 356 start = cur; 357 while (!isspace(*cur) && *cur != '\0') ++cur; 358 359 if (cur != start) { 360 *value = std::string(start, cur - start); 361 } 362 } 363 *options_str = cur; 364 return true; 365 } 366 367 bool Config::Init(const char* options_str) { 368 // Initialize a few default values. 369 fill_alloc_value_ = DEFAULT_FILL_ALLOC_VALUE; 370 fill_free_value_ = DEFAULT_FILL_FREE_VALUE; 371 front_guard_value_ = DEFAULT_FRONT_GUARD_VALUE; 372 rear_guard_value_ = DEFAULT_REAR_GUARD_VALUE; 373 backtrace_signal_ = SIGRTMAX - 19; 374 backtrace_dump_signal_ = SIGRTMAX - 17; 375 record_allocs_signal_ = SIGRTMAX - 18; 376 free_track_backtrace_num_frames_ = 0; 377 record_allocs_file_.clear(); 378 fill_on_free_bytes_ = 0; 379 backtrace_enable_on_signal_ = false; 380 backtrace_enabled_ = false; 381 backtrace_dump_on_exit_ = false; 382 backtrace_dump_prefix_ = DEFAULT_BACKTRACE_DUMP_PREFIX; 383 384 // Process each option name we can find. 385 std::string option; 386 std::string value; 387 bool valid = true; 388 while (GetOption(&options_str, &option, &value)) { 389 auto entry = kOptions.find(option); 390 if (entry == kOptions.end()) { 391 error_log("%s: unknown option %s", getprogname(), option.c_str()); 392 valid = false; 393 break; 394 } 395 396 const OptionInfo* info = &entry->second; 397 auto process_func = info->process_func; 398 if (process_func != nullptr && !(this->*process_func)(option, value)) { 399 valid = false; 400 break; 401 } 402 options_ |= info->option; 403 } 404 405 if (!valid || *options_str != '\0') { 406 LogUsage(); 407 return false; 408 } 409 410 return true; 411 } 412