blob: 5fd511f1508ef529501496d48fd61bd3c2f0f23a [file] [log] [blame]
Christopher Ferris63860cb2015-11-16 17:30:32 -08001/*
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
Christopher Ferris2b2b25b2017-04-05 19:13:03 -070029#include <assert.h>
Christopher Ferris63860cb2015-11-16 17:30:32 -080030#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
Josh Gao4956c372019-12-19 16:35:51 -080041#include <platform/bionic/macros.h>
Christopher Ferris63860cb2015-11-16 17:30:32 -080042
43#include "Config.h"
44#include "debug_log.h"
45
Christopher Ferris549e5222016-02-22 19:23:26 -080046// Config constants
47static constexpr uint8_t DEFAULT_FILL_ALLOC_VALUE = 0xeb;
48static constexpr uint8_t DEFAULT_FILL_FREE_VALUE = 0xef;
49
50static constexpr uint8_t DEFAULT_FRONT_GUARD_VALUE = 0xaa;
51static constexpr uint8_t DEFAULT_REAR_GUARD_VALUE = 0xbb;
52
53// Used as the default for all guard values.
54static constexpr size_t DEFAULT_GUARD_BYTES = 32;
55static constexpr size_t MAX_GUARD_BYTES = 16384;
56
57static constexpr size_t DEFAULT_BACKTRACE_FRAMES = 16;
58static constexpr size_t MAX_BACKTRACE_FRAMES = 256;
Christopher Ferris602b88c2017-08-04 13:04:04 -070059static constexpr const char DEFAULT_BACKTRACE_DUMP_PREFIX[] = "/data/local/tmp/backtrace_heap";
Christopher Ferris549e5222016-02-22 19:23:26 -080060
61static constexpr size_t DEFAULT_EXPAND_BYTES = 16;
62static constexpr size_t MAX_EXPAND_BYTES = 16384;
63
64static constexpr size_t DEFAULT_FREE_TRACK_ALLOCATIONS = 100;
65static constexpr size_t MAX_FREE_TRACK_ALLOCATIONS = 16384;
66
Christopher Ferris7bd01782016-04-20 12:30:58 -070067static constexpr size_t DEFAULT_RECORD_ALLOCS = 8000000;
68static constexpr size_t MAX_RECORD_ALLOCS = 50000000;
69static constexpr const char DEFAULT_RECORD_ALLOCS_FILE[] = "/data/local/tmp/record_allocs.txt";
Christopher Ferris63860cb2015-11-16 17:30:32 -080070
Christopher Ferris2b2b25b2017-04-05 19:13:03 -070071const std::unordered_map<std::string, Config::OptionInfo> Config::kOptions = {
Christopher Ferris4da25032018-03-07 13:38:48 -080072 {
Christopher Ferrisb42e8b42022-05-09 14:00:47 -070073 "guard",
74 {FRONT_GUARD | REAR_GUARD | TRACK_ALLOCS, &Config::SetGuard},
Christopher Ferris2b2b25b2017-04-05 19:13:03 -070075 },
Christopher Ferris4da25032018-03-07 13:38:48 -080076 {
Christopher Ferrisb42e8b42022-05-09 14:00:47 -070077 "front_guard",
78 {FRONT_GUARD | TRACK_ALLOCS, &Config::SetFrontGuard},
Christopher Ferris2b2b25b2017-04-05 19:13:03 -070079 },
Christopher Ferris4da25032018-03-07 13:38:48 -080080 {
Christopher Ferrisb42e8b42022-05-09 14:00:47 -070081 "rear_guard",
82 {REAR_GUARD | TRACK_ALLOCS, &Config::SetRearGuard},
Christopher Ferris2b2b25b2017-04-05 19:13:03 -070083 },
Christopher Ferris7bd01782016-04-20 12:30:58 -070084
Christopher Ferris4da25032018-03-07 13:38:48 -080085 {
Christopher Ferrisb42e8b42022-05-09 14:00:47 -070086 "backtrace",
87 {BACKTRACE | TRACK_ALLOCS, &Config::SetBacktrace},
Christopher Ferris2b2b25b2017-04-05 19:13:03 -070088 },
Christopher Ferris4da25032018-03-07 13:38:48 -080089 {
90 "backtrace_enable_on_signal",
91 {BACKTRACE | TRACK_ALLOCS, &Config::SetBacktraceEnableOnSignal},
Christopher Ferris2b2b25b2017-04-05 19:13:03 -070092 },
Christopher Ferris7bd01782016-04-20 12:30:58 -070093
Christopher Ferris4da25032018-03-07 13:38:48 -080094 {
Christopher Ferrisb42e8b42022-05-09 14:00:47 -070095 "backtrace_dump_on_exit",
96 {0, &Config::SetBacktraceDumpOnExit},
Christopher Ferris602b88c2017-08-04 13:04:04 -070097 },
Christopher Ferris4da25032018-03-07 13:38:48 -080098 {
Christopher Ferrisb42e8b42022-05-09 14:00:47 -070099 "backtrace_dump_prefix",
100 {0, &Config::SetBacktraceDumpPrefix},
Christopher Ferris602b88c2017-08-04 13:04:04 -0700101 },
Christopher Ferris93bdd6a2018-04-05 11:12:38 -0700102 {
Christopher Ferrisb42e8b42022-05-09 14:00:47 -0700103 "backtrace_full",
104 {BACKTRACE_FULL, &Config::VerifyValueEmpty},
Christopher Ferris93bdd6a2018-04-05 11:12:38 -0700105 },
Christopher Ferris602b88c2017-08-04 13:04:04 -0700106
Christopher Ferris4da25032018-03-07 13:38:48 -0800107 {
Christopher Ferrisb42e8b42022-05-09 14:00:47 -0700108 "fill",
109 {FILL_ON_ALLOC | FILL_ON_FREE, &Config::SetFill},
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700110 },
Christopher Ferris4da25032018-03-07 13:38:48 -0800111 {
Christopher Ferrisb42e8b42022-05-09 14:00:47 -0700112 "fill_on_alloc",
113 {FILL_ON_ALLOC, &Config::SetFillOnAlloc},
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700114 },
Christopher Ferris4da25032018-03-07 13:38:48 -0800115 {
Christopher Ferrisb42e8b42022-05-09 14:00:47 -0700116 "fill_on_free",
117 {FILL_ON_FREE, &Config::SetFillOnFree},
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700118 },
Christopher Ferris7bd01782016-04-20 12:30:58 -0700119
Christopher Ferris4da25032018-03-07 13:38:48 -0800120 {
Christopher Ferrisb42e8b42022-05-09 14:00:47 -0700121 "expand_alloc",
122 {EXPAND_ALLOC, &Config::SetExpandAlloc},
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700123 },
Christopher Ferris7bd01782016-04-20 12:30:58 -0700124
Christopher Ferris4da25032018-03-07 13:38:48 -0800125 {
Christopher Ferrisb42e8b42022-05-09 14:00:47 -0700126 "free_track",
127 {FREE_TRACK | FILL_ON_FREE | TRACK_ALLOCS, &Config::SetFreeTrack},
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700128 },
Christopher Ferris4da25032018-03-07 13:38:48 -0800129 {
Christopher Ferrisb42e8b42022-05-09 14:00:47 -0700130 "free_track_backtrace_num_frames",
131 {0, &Config::SetFreeTrackBacktraceNumFrames},
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700132 },
133
Christopher Ferris4da25032018-03-07 13:38:48 -0800134 {
Christopher Ferrisb42e8b42022-05-09 14:00:47 -0700135 "leak_track",
136 {LEAK_TRACK | TRACK_ALLOCS, &Config::VerifyValueEmpty},
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700137 },
138
Christopher Ferris4da25032018-03-07 13:38:48 -0800139 {
Christopher Ferrisb42e8b42022-05-09 14:00:47 -0700140 "record_allocs",
141 {RECORD_ALLOCS, &Config::SetRecordAllocs},
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700142 },
Christopher Ferris4da25032018-03-07 13:38:48 -0800143 {
Christopher Ferrisb42e8b42022-05-09 14:00:47 -0700144 "record_allocs_file",
145 {0, &Config::SetRecordAllocsFile},
Christopher Ferris4da25032018-03-07 13:38:48 -0800146 },
147
148 {
Christopher Ferrisb42e8b42022-05-09 14:00:47 -0700149 "verify_pointers",
150 {TRACK_ALLOCS, &Config::VerifyValueEmpty},
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700151 },
Iris Chang7f209a92019-01-16 11:17:15 +0800152 {
Christopher Ferrisb42e8b42022-05-09 14:00:47 -0700153 "abort_on_error",
154 {ABORT_ON_ERROR, &Config::VerifyValueEmpty},
Iris Chang7f209a92019-01-16 11:17:15 +0800155 },
Christopher Ferrisc328e442019-04-01 19:31:26 -0700156 {
Christopher Ferrisb42e8b42022-05-09 14:00:47 -0700157 "verbose",
158 {VERBOSE, &Config::VerifyValueEmpty},
159 },
160 {
161 "check_unreachable_on_signal",
162 {CHECK_UNREACHABLE_ON_SIGNAL, &Config::VerifyValueEmpty},
Christopher Ferrisc328e442019-04-01 19:31:26 -0700163 },
Christopher Ferris63860cb2015-11-16 17:30:32 -0800164};
165
Christopher Ferris4da25032018-03-07 13:38:48 -0800166bool Config::ParseValue(const std::string& option, const std::string& value, size_t min_value,
167 size_t max_value, size_t* parsed_value) const {
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700168 assert(!value.empty());
Christopher Ferris7bd01782016-04-20 12:30:58 -0700169
170 // Parse the value into a size_t value.
171 errno = 0;
172 char* end;
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700173 long long_value = strtol(value.c_str(), &end, 10);
Christopher Ferris7bd01782016-04-20 12:30:58 -0700174 if (errno != 0) {
Christopher Ferris4da25032018-03-07 13:38:48 -0800175 error_log("%s: bad value for option '%s': %s", getprogname(), option.c_str(), strerror(errno));
Christopher Ferris7bd01782016-04-20 12:30:58 -0700176 return false;
177 }
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700178 if (end == value.c_str()) {
179 error_log("%s: bad value for option '%s'", getprogname(), option.c_str());
Christopher Ferris7bd01782016-04-20 12:30:58 -0700180 return false;
181 }
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700182 if (static_cast<size_t>(end - value.c_str()) != value.size()) {
Christopher Ferris4da25032018-03-07 13:38:48 -0800183 error_log("%s: bad value for option '%s', non space found after option: %s", getprogname(),
184 option.c_str(), end);
Christopher Ferris7bd01782016-04-20 12:30:58 -0700185 return false;
186 }
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700187 if (long_value < 0) {
Christopher Ferris4da25032018-03-07 13:38:48 -0800188 error_log("%s: bad value for option '%s', value cannot be negative: %ld", getprogname(),
189 option.c_str(), long_value);
Christopher Ferris7bd01782016-04-20 12:30:58 -0700190 return false;
191 }
192
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700193 if (static_cast<size_t>(long_value) < min_value) {
Christopher Ferris4da25032018-03-07 13:38:48 -0800194 error_log("%s: bad value for option '%s', value must be >= %zu: %ld", getprogname(),
195 option.c_str(), min_value, long_value);
Christopher Ferris7bd01782016-04-20 12:30:58 -0700196 return false;
197 }
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700198 if (static_cast<size_t>(long_value) > max_value) {
Christopher Ferris4da25032018-03-07 13:38:48 -0800199 error_log("%s: bad value for option '%s', value must be <= %zu: %ld", getprogname(),
200 option.c_str(), max_value, long_value);
Christopher Ferris7bd01782016-04-20 12:30:58 -0700201 return false;
202 }
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700203 *parsed_value = static_cast<size_t>(long_value);
Christopher Ferris7bd01782016-04-20 12:30:58 -0700204 return true;
205}
206
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700207bool Config::ParseValue(const std::string& option, const std::string& value, size_t default_value,
208 size_t min_value, size_t max_value, size_t* new_value) const {
209 if (value.empty()) {
210 *new_value = default_value;
211 return true;
212 }
213 return ParseValue(option, value, min_value, max_value, new_value);
214}
Christopher Ferris63860cb2015-11-16 17:30:32 -0800215
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700216bool Config::SetGuard(const std::string& option, const std::string& value) {
217 if (value.empty()) {
218 // Set the defaults.
219 front_guard_bytes_ = DEFAULT_GUARD_BYTES;
220 rear_guard_bytes_ = DEFAULT_GUARD_BYTES;
221 return true;
222 }
Christopher Ferris63860cb2015-11-16 17:30:32 -0800223
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700224 if (!ParseValue(option, value, 1, MAX_GUARD_BYTES, &rear_guard_bytes_)) {
Christopher Ferris63860cb2015-11-16 17:30:32 -0800225 return false;
226 }
227
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700228 // It's necessary to align the front guard to MINIMUM_ALIGNMENT_BYTES to
229 // make sure that the header is aligned properly.
Dan Alberta613d0d2017-10-05 16:39:33 -0700230 front_guard_bytes_ = __BIONIC_ALIGN(rear_guard_bytes_, MINIMUM_ALIGNMENT_BYTES);
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700231 return true;
232}
Christopher Ferris63860cb2015-11-16 17:30:32 -0800233
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700234bool Config::SetFrontGuard(const std::string& option, const std::string& value) {
235 if (!ParseValue(option, value, DEFAULT_GUARD_BYTES, 1, MAX_GUARD_BYTES, &front_guard_bytes_)) {
236 return false;
237 }
238 // It's necessary to align the front guard to MINIMUM_ALIGNMENT_BYTES to
239 // make sure that the header is aligned properly.
Dan Alberta613d0d2017-10-05 16:39:33 -0700240 front_guard_bytes_ = __BIONIC_ALIGN(front_guard_bytes_, MINIMUM_ALIGNMENT_BYTES);
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700241 return true;
242}
Christopher Ferris63860cb2015-11-16 17:30:32 -0800243
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700244bool Config::SetRearGuard(const std::string& option, const std::string& value) {
245 return ParseValue(option, value, DEFAULT_GUARD_BYTES, 1, MAX_GUARD_BYTES, &rear_guard_bytes_);
246}
Christopher Ferris63860cb2015-11-16 17:30:32 -0800247
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700248bool Config::SetFill(const std::string& option, const std::string& value) {
249 if (value.empty()) {
250 // Set the defaults.
251 fill_on_alloc_bytes_ = SIZE_MAX;
252 fill_on_free_bytes_ = SIZE_MAX;
253 return true;
254 }
Christopher Ferris7bd01782016-04-20 12:30:58 -0700255
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700256 if (!ParseValue(option, value, 1, SIZE_MAX, &fill_on_alloc_bytes_)) {
257 return false;
258 }
259 fill_on_free_bytes_ = fill_on_alloc_bytes_;
260 return true;
261}
Christopher Ferris7bd01782016-04-20 12:30:58 -0700262
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700263bool Config::SetFillOnAlloc(const std::string& option, const std::string& value) {
264 return ParseValue(option, value, SIZE_MAX, 1, SIZE_MAX, &fill_on_alloc_bytes_);
265}
266
267bool Config::SetFillOnFree(const std::string& option, const std::string& value) {
268 return ParseValue(option, value, SIZE_MAX, 1, SIZE_MAX, &fill_on_free_bytes_);
269}
270
271bool Config::SetBacktrace(const std::string& option, const std::string& value) {
272 backtrace_enabled_ = true;
273 return ParseValue(option, value, DEFAULT_BACKTRACE_FRAMES, 1, MAX_BACKTRACE_FRAMES,
274 &backtrace_frames_);
275}
276
277bool Config::SetBacktraceEnableOnSignal(const std::string& option, const std::string& value) {
278 backtrace_enable_on_signal_ = true;
279 return ParseValue(option, value, DEFAULT_BACKTRACE_FRAMES, 1, MAX_BACKTRACE_FRAMES,
280 &backtrace_frames_);
281}
282
Christopher Ferris602b88c2017-08-04 13:04:04 -0700283bool Config::SetBacktraceDumpOnExit(const std::string& option, const std::string& value) {
284 if (Config::VerifyValueEmpty(option, value)) {
285 backtrace_dump_on_exit_ = true;
286 return true;
287 }
288 return false;
289}
290
291bool Config::SetBacktraceDumpPrefix(const std::string&, const std::string& value) {
292 if (value.empty()) {
293 backtrace_dump_prefix_ = DEFAULT_BACKTRACE_DUMP_PREFIX;
294 } else {
295 backtrace_dump_prefix_ = value;
296 }
297 return true;
298}
299
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700300bool Config::SetExpandAlloc(const std::string& option, const std::string& value) {
301 return ParseValue(option, value, DEFAULT_EXPAND_BYTES, 1, MAX_EXPAND_BYTES, &expand_alloc_bytes_);
302}
303
304bool Config::SetFreeTrack(const std::string& option, const std::string& value) {
305 // This option enables fill on free, so set the bytes to the default value.
306 if (fill_on_free_bytes_ == 0) {
307 fill_on_free_bytes_ = SIZE_MAX;
308 }
309 if (free_track_backtrace_num_frames_ == 0) {
310 free_track_backtrace_num_frames_ = DEFAULT_BACKTRACE_FRAMES;
311 }
312
313 return ParseValue(option, value, DEFAULT_FREE_TRACK_ALLOCATIONS, 1, MAX_FREE_TRACK_ALLOCATIONS,
314 &free_track_allocations_);
315}
316
317bool Config::SetFreeTrackBacktraceNumFrames(const std::string& option, const std::string& value) {
318 return ParseValue(option, value, DEFAULT_BACKTRACE_FRAMES, 0, MAX_BACKTRACE_FRAMES,
319 &free_track_backtrace_num_frames_);
320}
321
322bool Config::SetRecordAllocs(const std::string& option, const std::string& value) {
323 if (record_allocs_file_.empty()) {
324 record_allocs_file_ = DEFAULT_RECORD_ALLOCS_FILE;
325 }
326 return ParseValue(option, value, DEFAULT_RECORD_ALLOCS, 1, MAX_RECORD_ALLOCS,
327 &record_allocs_num_entries_);
328}
329
330bool Config::SetRecordAllocsFile(const std::string&, const std::string& value) {
331 if (value.empty()) {
332 // Set the default.
333 record_allocs_file_ = DEFAULT_RECORD_ALLOCS_FILE;
334 return true;
335 }
336 record_allocs_file_ = value;
337 return true;
338}
339
340bool Config::VerifyValueEmpty(const std::string& option, const std::string& value) {
341 if (!value.empty()) {
342 // This is not valid.
Christopher Ferris4da25032018-03-07 13:38:48 -0800343 error_log("%s: value set for option '%s' which does not take a value", getprogname(),
344 option.c_str());
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700345 return false;
Christopher Ferris63860cb2015-11-16 17:30:32 -0800346 }
347 return true;
348}
349
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700350void Config::LogUsage() const {
Christopher Ferris770cbb32018-05-25 12:46:55 -0700351 error_log("For malloc debug option descriptions go to:");
352 error_log(" https://android.googlesource.com/platform/bionic/+/master/libc/malloc_debug/README.md");
Christopher Ferris63860cb2015-11-16 17:30:32 -0800353}
354
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700355bool Config::GetOption(const char** options_str, std::string* option, std::string* value) {
356 const char* cur = *options_str;
357 // Process each property name we can find.
Christopher Ferris4da25032018-03-07 13:38:48 -0800358 while (isspace(*cur)) ++cur;
Christopher Ferris63860cb2015-11-16 17:30:32 -0800359
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700360 if (*cur == '\0') {
361 *options_str = cur;
362 return false;
Christopher Ferris7bd01782016-04-20 12:30:58 -0700363 }
364
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700365 const char* start = cur;
Christopher Ferris4da25032018-03-07 13:38:48 -0800366 while (!isspace(*cur) && *cur != '=' && *cur != '\0') ++cur;
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700367
368 *option = std::string(start, cur - start);
369
370 // Skip any spaces after the name.
Christopher Ferris4da25032018-03-07 13:38:48 -0800371 while (isspace(*cur)) ++cur;
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700372
373 value->clear();
374 if (*cur == '=') {
375 ++cur;
376 // Skip the space after the equal.
Christopher Ferris4da25032018-03-07 13:38:48 -0800377 while (isspace(*cur)) ++cur;
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700378
379 start = cur;
Christopher Ferris4da25032018-03-07 13:38:48 -0800380 while (!isspace(*cur) && *cur != '\0') ++cur;
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700381
382 if (cur != start) {
383 *value = std::string(start, cur - start);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800384 }
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700385 }
386 *options_str = cur;
387 return true;
388}
389
390bool Config::Init(const char* options_str) {
391 // Initialize a few default values.
392 fill_alloc_value_ = DEFAULT_FILL_ALLOC_VALUE;
393 fill_free_value_ = DEFAULT_FILL_FREE_VALUE;
394 front_guard_value_ = DEFAULT_FRONT_GUARD_VALUE;
395 rear_guard_value_ = DEFAULT_REAR_GUARD_VALUE;
396 backtrace_signal_ = SIGRTMAX - 19;
Christopher Ferris602b88c2017-08-04 13:04:04 -0700397 backtrace_dump_signal_ = SIGRTMAX - 17;
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700398 record_allocs_signal_ = SIGRTMAX - 18;
399 free_track_backtrace_num_frames_ = 0;
400 record_allocs_file_.clear();
401 fill_on_free_bytes_ = 0;
402 backtrace_enable_on_signal_ = false;
403 backtrace_enabled_ = false;
Christopher Ferris602b88c2017-08-04 13:04:04 -0700404 backtrace_dump_on_exit_ = false;
405 backtrace_dump_prefix_ = DEFAULT_BACKTRACE_DUMP_PREFIX;
Christopher Ferrisb42e8b42022-05-09 14:00:47 -0700406 check_unreachable_signal_ = SIGRTMAX - 16;
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700407
408 // Process each option name we can find.
409 std::string option;
410 std::string value;
411 bool valid = true;
412 while (GetOption(&options_str, &option, &value)) {
413 auto entry = kOptions.find(option);
414 if (entry == kOptions.end()) {
415 error_log("%s: unknown option %s", getprogname(), option.c_str());
Christopher Ferris63860cb2015-11-16 17:30:32 -0800416 valid = false;
417 break;
418 }
Christopher Ferris63860cb2015-11-16 17:30:32 -0800419
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700420 const OptionInfo* info = &entry->second;
421 auto process_func = info->process_func;
422 if (process_func != nullptr && !(this->*process_func)(option, value)) {
423 valid = false;
424 break;
Christopher Ferris63860cb2015-11-16 17:30:32 -0800425 }
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700426 options_ |= info->option;
Christopher Ferris63860cb2015-11-16 17:30:32 -0800427 }
428
Christopher Ferris2b2b25b2017-04-05 19:13:03 -0700429 if (!valid || *options_str != '\0') {
430 LogUsage();
431 return false;
432 }
433
434 return true;
Christopher Ferris63860cb2015-11-16 17:30:32 -0800435}