• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <platform/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",
74         {FRONT_GUARD | REAR_GUARD | TRACK_ALLOCS, &Config::SetGuard},
75     },
76     {
77         "front_guard",
78         {FRONT_GUARD | TRACK_ALLOCS, &Config::SetFrontGuard},
79     },
80     {
81         "rear_guard",
82         {REAR_GUARD | TRACK_ALLOCS, &Config::SetRearGuard},
83     },
84 
85     {
86         "backtrace_size",
87         {BACKTRACE_SPECIFIC_SIZES, &Config::SetBacktraceSize},
88     },
89     {
90         "bt_sz",
91         {BACKTRACE_SPECIFIC_SIZES, &Config::SetBacktraceSize},
92     },
93     {
94         "backtrace_min_size",
95         {BACKTRACE_SPECIFIC_SIZES, &Config::SetBacktraceMinSize},
96     },
97     {
98         "bt_min_sz",
99         {BACKTRACE_SPECIFIC_SIZES, &Config::SetBacktraceMinSize},
100     },
101     {
102         "backtrace_max_size",
103         {BACKTRACE_SPECIFIC_SIZES, &Config::SetBacktraceMaxSize},
104     },
105     {
106         "bt_max_sz",
107         {BACKTRACE_SPECIFIC_SIZES, &Config::SetBacktraceMaxSize},
108     },
109     {
110         "backtrace",
111         {BACKTRACE | TRACK_ALLOCS, &Config::SetBacktrace},
112     },
113     {
114         "bt",
115         {BACKTRACE | TRACK_ALLOCS, &Config::SetBacktrace},
116     },
117     {
118         "backtrace_enable_on_signal",
119         {BACKTRACE | TRACK_ALLOCS, &Config::SetBacktraceEnableOnSignal},
120     },
121     {
122         "bt_en_on_sig",
123         {BACKTRACE | TRACK_ALLOCS, &Config::SetBacktraceEnableOnSignal},
124     },
125     {
126         "backtrace_dump_on_exit",
127         {0, &Config::SetBacktraceDumpOnExit},
128     },
129     {
130         "bt_dmp_on_ex",
131         {0, &Config::SetBacktraceDumpOnExit},
132     },
133     {
134         "backtrace_dump_prefix",
135         {0, &Config::SetBacktraceDumpPrefix},
136     },
137     {
138         "bt_dmp_pre",
139         {0, &Config::SetBacktraceDumpPrefix},
140     },
141     {
142         "backtrace_full",
143         {BACKTRACE_FULL, &Config::VerifyValueEmpty},
144     },
145     {
146         "bt_full",
147         {BACKTRACE_FULL, &Config::VerifyValueEmpty},
148     },
149 
150     {
151         "fill",
152         {FILL_ON_ALLOC | FILL_ON_FREE, &Config::SetFill},
153     },
154     {
155         "fill_on_alloc",
156         {FILL_ON_ALLOC, &Config::SetFillOnAlloc},
157     },
158     {
159         "fill_on_free",
160         {FILL_ON_FREE, &Config::SetFillOnFree},
161     },
162 
163     {
164         "expand_alloc",
165         {EXPAND_ALLOC, &Config::SetExpandAlloc},
166     },
167 
168     {
169         "free_track",
170         {FREE_TRACK | FILL_ON_FREE | TRACK_ALLOCS, &Config::SetFreeTrack},
171     },
172     {
173         "free_track_backtrace_num_frames",
174         {0, &Config::SetFreeTrackBacktraceNumFrames},
175     },
176 
177     {
178         "leak_track",
179         {LEAK_TRACK | TRACK_ALLOCS, &Config::VerifyValueEmpty},
180     },
181 
182     {
183         "record_allocs",
184         {RECORD_ALLOCS, &Config::SetRecordAllocs},
185     },
186     {
187         "record_allocs_file",
188         {0, &Config::SetRecordAllocsFile},
189     },
190 
191     {
192         "verify_pointers",
193         {TRACK_ALLOCS, &Config::VerifyValueEmpty},
194     },
195     {
196         "abort_on_error",
197         {ABORT_ON_ERROR, &Config::VerifyValueEmpty},
198     },
199     {
200         "verbose",
201         {VERBOSE, &Config::VerifyValueEmpty},
202     },
203     {
204         "check_unreachable_on_signal",
205         {CHECK_UNREACHABLE_ON_SIGNAL, &Config::VerifyValueEmpty},
206     },
207 };
208 
ParseValue(const std::string & option,const std::string & value,size_t min_value,size_t max_value,size_t * parsed_value) const209 bool Config::ParseValue(const std::string& option, const std::string& value, size_t min_value,
210                         size_t max_value, size_t* parsed_value) const {
211   assert(!value.empty());
212 
213   // Parse the value into a size_t value.
214   errno = 0;
215   char* end;
216   long long_value = strtol(value.c_str(), &end, 10);
217   if (errno != 0) {
218     error_log("%s: bad value for option '%s': %s", getprogname(), option.c_str(), strerror(errno));
219     return false;
220   }
221   if (end == value.c_str()) {
222     error_log("%s: bad value for option '%s'", getprogname(), option.c_str());
223     return false;
224   }
225   if (static_cast<size_t>(end - value.c_str()) != value.size()) {
226     error_log("%s: bad value for option '%s', non space found after option: %s", getprogname(),
227               option.c_str(), end);
228     return false;
229   }
230   if (long_value < 0) {
231     error_log("%s: bad value for option '%s', value cannot be negative: %ld", getprogname(),
232               option.c_str(), long_value);
233     return false;
234   }
235 
236   if (static_cast<size_t>(long_value) < min_value) {
237     error_log("%s: bad value for option '%s', value must be >= %zu: %ld", getprogname(),
238               option.c_str(), min_value, long_value);
239     return false;
240   }
241   if (static_cast<size_t>(long_value) > max_value) {
242     error_log("%s: bad value for option '%s', value must be <= %zu: %ld", getprogname(),
243               option.c_str(), max_value, long_value);
244     return false;
245   }
246   *parsed_value = static_cast<size_t>(long_value);
247   return true;
248 }
249 
ParseValue(const std::string & option,const std::string & value,size_t default_value,size_t min_value,size_t max_value,size_t * new_value) const250 bool Config::ParseValue(const std::string& option, const std::string& value, size_t default_value,
251                         size_t min_value, size_t max_value, size_t* new_value) const {
252   if (value.empty()) {
253     *new_value = default_value;
254     return true;
255   }
256   return ParseValue(option, value, min_value, max_value, new_value);
257 }
258 
SetGuard(const std::string & option,const std::string & value)259 bool Config::SetGuard(const std::string& option, const std::string& value) {
260   if (value.empty()) {
261     // Set the defaults.
262     front_guard_bytes_ = DEFAULT_GUARD_BYTES;
263     rear_guard_bytes_ = DEFAULT_GUARD_BYTES;
264     return true;
265   }
266 
267   if (!ParseValue(option, value, 1, MAX_GUARD_BYTES, &rear_guard_bytes_)) {
268     return false;
269   }
270 
271   // It's necessary to align the front guard to MINIMUM_ALIGNMENT_BYTES to
272   // make sure that the header is aligned properly.
273   front_guard_bytes_ = __BIONIC_ALIGN(rear_guard_bytes_, MINIMUM_ALIGNMENT_BYTES);
274   return true;
275 }
276 
SetFrontGuard(const std::string & option,const std::string & value)277 bool Config::SetFrontGuard(const std::string& option, const std::string& value) {
278   if (!ParseValue(option, value, DEFAULT_GUARD_BYTES, 1, MAX_GUARD_BYTES, &front_guard_bytes_)) {
279     return false;
280   }
281   // It's necessary to align the front guard to MINIMUM_ALIGNMENT_BYTES to
282   // make sure that the header is aligned properly.
283   front_guard_bytes_ = __BIONIC_ALIGN(front_guard_bytes_, MINIMUM_ALIGNMENT_BYTES);
284   return true;
285 }
286 
SetRearGuard(const std::string & option,const std::string & value)287 bool Config::SetRearGuard(const std::string& option, const std::string& value) {
288   return ParseValue(option, value, DEFAULT_GUARD_BYTES, 1, MAX_GUARD_BYTES, &rear_guard_bytes_);
289 }
290 
SetFill(const std::string & option,const std::string & value)291 bool Config::SetFill(const std::string& option, const std::string& value) {
292   if (value.empty()) {
293     // Set the defaults.
294     fill_on_alloc_bytes_ = SIZE_MAX;
295     fill_on_free_bytes_ = SIZE_MAX;
296     return true;
297   }
298 
299   if (!ParseValue(option, value, 1, SIZE_MAX, &fill_on_alloc_bytes_)) {
300     return false;
301   }
302   fill_on_free_bytes_ = fill_on_alloc_bytes_;
303   return true;
304 }
305 
SetFillOnAlloc(const std::string & option,const std::string & value)306 bool Config::SetFillOnAlloc(const std::string& option, const std::string& value) {
307   return ParseValue(option, value, SIZE_MAX, 1, SIZE_MAX, &fill_on_alloc_bytes_);
308 }
309 
SetFillOnFree(const std::string & option,const std::string & value)310 bool Config::SetFillOnFree(const std::string& option, const std::string& value) {
311   return ParseValue(option, value, SIZE_MAX, 1, SIZE_MAX, &fill_on_free_bytes_);
312 }
313 
SetBacktrace(const std::string & option,const std::string & value)314 bool Config::SetBacktrace(const std::string& option, const std::string& value) {
315   backtrace_enabled_ = true;
316   return ParseValue(option, value, DEFAULT_BACKTRACE_FRAMES, 1, MAX_BACKTRACE_FRAMES,
317                     &backtrace_frames_);
318 }
319 
SetBacktraceEnableOnSignal(const std::string & option,const std::string & value)320 bool Config::SetBacktraceEnableOnSignal(const std::string& option, const std::string& value) {
321   backtrace_enable_on_signal_ = true;
322   return ParseValue(option, value, DEFAULT_BACKTRACE_FRAMES, 1, MAX_BACKTRACE_FRAMES,
323                     &backtrace_frames_);
324 }
325 
SetBacktraceDumpOnExit(const std::string & option,const std::string & value)326 bool Config::SetBacktraceDumpOnExit(const std::string& option, const std::string& value) {
327   if (Config::VerifyValueEmpty(option, value)) {
328     backtrace_dump_on_exit_ = true;
329     return true;
330   }
331   return false;
332 }
333 
SetBacktraceDumpPrefix(const std::string &,const std::string & value)334 bool Config::SetBacktraceDumpPrefix(const std::string&, const std::string& value) {
335   if (value.empty()) {
336     backtrace_dump_prefix_ = DEFAULT_BACKTRACE_DUMP_PREFIX;
337   } else {
338     backtrace_dump_prefix_ = value;
339   }
340   return true;
341 }
342 
SetBacktraceSize(const std::string & option,const std::string & value)343 bool Config::SetBacktraceSize(const std::string& option, const std::string& value) {
344   if (!ParseValue(option, value, 1, SIZE_MAX, &backtrace_min_size_bytes_)) {
345     return false;
346   }
347   backtrace_max_size_bytes_ = backtrace_min_size_bytes_;
348 
349   return true;
350 }
351 
SetBacktraceMinSize(const std::string & option,const std::string & value)352 bool Config::SetBacktraceMinSize(const std::string& option, const std::string& value) {
353   return ParseValue(option, value, 1, SIZE_MAX, &backtrace_min_size_bytes_);
354 }
355 
SetBacktraceMaxSize(const std::string & option,const std::string & value)356 bool Config::SetBacktraceMaxSize(const std::string& option, const std::string& value) {
357   return ParseValue(option, value, 1, SIZE_MAX, &backtrace_max_size_bytes_);
358 }
359 
SetExpandAlloc(const std::string & option,const std::string & value)360 bool Config::SetExpandAlloc(const std::string& option, const std::string& value) {
361   return ParseValue(option, value, DEFAULT_EXPAND_BYTES, 1, MAX_EXPAND_BYTES, &expand_alloc_bytes_);
362 }
363 
SetFreeTrack(const std::string & option,const std::string & value)364 bool Config::SetFreeTrack(const std::string& option, const std::string& value) {
365   // This option enables fill on free, so set the bytes to the default value.
366   if (fill_on_free_bytes_ == 0) {
367     fill_on_free_bytes_ = SIZE_MAX;
368   }
369   if (free_track_backtrace_num_frames_ == 0) {
370     free_track_backtrace_num_frames_ = DEFAULT_BACKTRACE_FRAMES;
371   }
372 
373   return ParseValue(option, value, DEFAULT_FREE_TRACK_ALLOCATIONS, 1, MAX_FREE_TRACK_ALLOCATIONS,
374                     &free_track_allocations_);
375 }
376 
SetFreeTrackBacktraceNumFrames(const std::string & option,const std::string & value)377 bool Config::SetFreeTrackBacktraceNumFrames(const std::string& option, const std::string& value) {
378   return ParseValue(option, value, DEFAULT_BACKTRACE_FRAMES, 0, MAX_BACKTRACE_FRAMES,
379                     &free_track_backtrace_num_frames_);
380 }
381 
SetRecordAllocs(const std::string & option,const std::string & value)382 bool Config::SetRecordAllocs(const std::string& option, const std::string& value) {
383   if (record_allocs_file_.empty()) {
384     record_allocs_file_ = DEFAULT_RECORD_ALLOCS_FILE;
385   }
386   return ParseValue(option, value, DEFAULT_RECORD_ALLOCS, 1, MAX_RECORD_ALLOCS,
387                     &record_allocs_num_entries_);
388 }
389 
SetRecordAllocsFile(const std::string &,const std::string & value)390 bool Config::SetRecordAllocsFile(const std::string&, const std::string& value) {
391   if (value.empty()) {
392     // Set the default.
393     record_allocs_file_ = DEFAULT_RECORD_ALLOCS_FILE;
394     return true;
395   }
396   record_allocs_file_ = value;
397   return true;
398 }
399 
VerifyValueEmpty(const std::string & option,const std::string & value)400 bool Config::VerifyValueEmpty(const std::string& option, const std::string& value) {
401   if (!value.empty()) {
402     // This is not valid.
403     error_log("%s: value set for option '%s' which does not take a value", getprogname(),
404               option.c_str());
405     return false;
406   }
407   return true;
408 }
409 
LogUsage() const410 void Config::LogUsage() const {
411   error_log("For malloc debug option descriptions go to:");
412   error_log("  https://android.googlesource.com/platform/bionic/+/master/libc/malloc_debug/README.md");
413 }
414 
GetOption(const char ** options_str,std::string * option,std::string * value)415 bool Config::GetOption(const char** options_str, std::string* option, std::string* value) {
416   const char* cur = *options_str;
417   // Process each property name we can find.
418   while (isspace(*cur)) ++cur;
419 
420   if (*cur == '\0') {
421     *options_str = cur;
422     return false;
423   }
424 
425   const char* start = cur;
426   while (!isspace(*cur) && *cur != '=' && *cur != '\0') ++cur;
427 
428   *option = std::string(start, cur - start);
429 
430   // Skip any spaces after the name.
431   while (isspace(*cur)) ++cur;
432 
433   value->clear();
434   if (*cur == '=') {
435     ++cur;
436     // Skip the space after the equal.
437     while (isspace(*cur)) ++cur;
438 
439     start = cur;
440     while (!isspace(*cur) && *cur != '\0') ++cur;
441 
442     if (cur != start) {
443       *value = std::string(start, cur - start);
444     }
445   }
446   *options_str = cur;
447   return true;
448 }
449 
Init(const char * options_str)450 bool Config::Init(const char* options_str) {
451   // Initialize a few default values.
452   fill_alloc_value_ = DEFAULT_FILL_ALLOC_VALUE;
453   fill_free_value_ = DEFAULT_FILL_FREE_VALUE;
454   front_guard_value_ = DEFAULT_FRONT_GUARD_VALUE;
455   rear_guard_value_ = DEFAULT_REAR_GUARD_VALUE;
456   backtrace_signal_ = SIGRTMAX - 19;
457   backtrace_dump_signal_ = SIGRTMAX - 17;
458   record_allocs_signal_ = SIGRTMAX - 18;
459   free_track_backtrace_num_frames_ = 0;
460   record_allocs_file_.clear();
461   fill_on_free_bytes_ = 0;
462   backtrace_enable_on_signal_ = false;
463   backtrace_enabled_ = false;
464   backtrace_dump_on_exit_ = false;
465   backtrace_dump_prefix_ = DEFAULT_BACKTRACE_DUMP_PREFIX;
466   backtrace_min_size_bytes_ = 0;
467   backtrace_max_size_bytes_ = SIZE_MAX;
468   check_unreachable_signal_ = SIGRTMAX - 16;
469 
470   // Process each option name we can find.
471   std::string option;
472   std::string value;
473   bool valid = true;
474   while (GetOption(&options_str, &option, &value)) {
475     auto entry = kOptions.find(option);
476     if (entry == kOptions.end()) {
477       error_log("%s: unknown option %s", getprogname(), option.c_str());
478       valid = false;
479       break;
480     }
481 
482     const OptionInfo* info = &entry->second;
483     auto process_func = info->process_func;
484     if (process_func != nullptr && !(this->*process_func)(option, value)) {
485       valid = false;
486       break;
487     }
488     options_ |= info->option;
489   }
490 
491   if (!valid || *options_str != '\0') {
492     LogUsage();
493     return false;
494   }
495 
496   return true;
497 }
498