• 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         "log_allocator_stats_on_signal",
209         {LOG_ALLOCATOR_STATS_ON_SIGNAL, &Config::VerifyValueEmpty},
210     },
211 };
212 
ParseValue(const std::string & option,const std::string & value,size_t min_value,size_t max_value,size_t * parsed_value) const213 bool Config::ParseValue(const std::string& option, const std::string& value, size_t min_value,
214                         size_t max_value, size_t* parsed_value) const {
215   assert(!value.empty());
216 
217   // Parse the value into a size_t value.
218   errno = 0;
219   char* end;
220   long long_value = strtol(value.c_str(), &end, 10);
221   if (errno != 0) {
222     error_log("%s: bad value for option '%s': %s", getprogname(), option.c_str(), strerror(errno));
223     return false;
224   }
225   if (end == value.c_str()) {
226     error_log("%s: bad value for option '%s'", getprogname(), option.c_str());
227     return false;
228   }
229   if (static_cast<size_t>(end - value.c_str()) != value.size()) {
230     error_log("%s: bad value for option '%s', non space found after option: %s", getprogname(),
231               option.c_str(), end);
232     return false;
233   }
234   if (long_value < 0) {
235     error_log("%s: bad value for option '%s', value cannot be negative: %ld", getprogname(),
236               option.c_str(), long_value);
237     return false;
238   }
239 
240   if (static_cast<size_t>(long_value) < min_value) {
241     error_log("%s: bad value for option '%s', value must be >= %zu: %ld", getprogname(),
242               option.c_str(), min_value, long_value);
243     return false;
244   }
245   if (static_cast<size_t>(long_value) > max_value) {
246     error_log("%s: bad value for option '%s', value must be <= %zu: %ld", getprogname(),
247               option.c_str(), max_value, long_value);
248     return false;
249   }
250   *parsed_value = static_cast<size_t>(long_value);
251   return true;
252 }
253 
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) const254 bool Config::ParseValue(const std::string& option, const std::string& value, size_t default_value,
255                         size_t min_value, size_t max_value, size_t* new_value) const {
256   if (value.empty()) {
257     *new_value = default_value;
258     return true;
259   }
260   return ParseValue(option, value, min_value, max_value, new_value);
261 }
262 
SetGuard(const std::string & option,const std::string & value)263 bool Config::SetGuard(const std::string& option, const std::string& value) {
264   if (value.empty()) {
265     // Set the defaults.
266     front_guard_bytes_ = DEFAULT_GUARD_BYTES;
267     rear_guard_bytes_ = DEFAULT_GUARD_BYTES;
268     return true;
269   }
270 
271   if (!ParseValue(option, value, 1, MAX_GUARD_BYTES, &rear_guard_bytes_)) {
272     return false;
273   }
274 
275   // It's necessary to align the front guard to MINIMUM_ALIGNMENT_BYTES to
276   // make sure that the header is aligned properly.
277   front_guard_bytes_ = __BIONIC_ALIGN(rear_guard_bytes_, MINIMUM_ALIGNMENT_BYTES);
278   return true;
279 }
280 
SetFrontGuard(const std::string & option,const std::string & value)281 bool Config::SetFrontGuard(const std::string& option, const std::string& value) {
282   if (!ParseValue(option, value, DEFAULT_GUARD_BYTES, 1, MAX_GUARD_BYTES, &front_guard_bytes_)) {
283     return false;
284   }
285   // It's necessary to align the front guard to MINIMUM_ALIGNMENT_BYTES to
286   // make sure that the header is aligned properly.
287   front_guard_bytes_ = __BIONIC_ALIGN(front_guard_bytes_, MINIMUM_ALIGNMENT_BYTES);
288   return true;
289 }
290 
SetRearGuard(const std::string & option,const std::string & value)291 bool Config::SetRearGuard(const std::string& option, const std::string& value) {
292   return ParseValue(option, value, DEFAULT_GUARD_BYTES, 1, MAX_GUARD_BYTES, &rear_guard_bytes_);
293 }
294 
SetFill(const std::string & option,const std::string & value)295 bool Config::SetFill(const std::string& option, const std::string& value) {
296   if (value.empty()) {
297     // Set the defaults.
298     fill_on_alloc_bytes_ = SIZE_MAX;
299     fill_on_free_bytes_ = SIZE_MAX;
300     return true;
301   }
302 
303   if (!ParseValue(option, value, 1, SIZE_MAX, &fill_on_alloc_bytes_)) {
304     return false;
305   }
306   fill_on_free_bytes_ = fill_on_alloc_bytes_;
307   return true;
308 }
309 
SetFillOnAlloc(const std::string & option,const std::string & value)310 bool Config::SetFillOnAlloc(const std::string& option, const std::string& value) {
311   return ParseValue(option, value, SIZE_MAX, 1, SIZE_MAX, &fill_on_alloc_bytes_);
312 }
313 
SetFillOnFree(const std::string & option,const std::string & value)314 bool Config::SetFillOnFree(const std::string& option, const std::string& value) {
315   return ParseValue(option, value, SIZE_MAX, 1, SIZE_MAX, &fill_on_free_bytes_);
316 }
317 
SetBacktrace(const std::string & option,const std::string & value)318 bool Config::SetBacktrace(const std::string& option, const std::string& value) {
319   backtrace_enabled_ = true;
320   return ParseValue(option, value, DEFAULT_BACKTRACE_FRAMES, 1, MAX_BACKTRACE_FRAMES,
321                     &backtrace_frames_);
322 }
323 
SetBacktraceEnableOnSignal(const std::string & option,const std::string & value)324 bool Config::SetBacktraceEnableOnSignal(const std::string& option, const std::string& value) {
325   backtrace_enable_on_signal_ = true;
326   return ParseValue(option, value, DEFAULT_BACKTRACE_FRAMES, 1, MAX_BACKTRACE_FRAMES,
327                     &backtrace_frames_);
328 }
329 
SetBacktraceDumpOnExit(const std::string & option,const std::string & value)330 bool Config::SetBacktraceDumpOnExit(const std::string& option, const std::string& value) {
331   if (Config::VerifyValueEmpty(option, value)) {
332     backtrace_dump_on_exit_ = true;
333     return true;
334   }
335   return false;
336 }
337 
SetBacktraceDumpPrefix(const std::string &,const std::string & value)338 bool Config::SetBacktraceDumpPrefix(const std::string&, const std::string& value) {
339   if (value.empty()) {
340     backtrace_dump_prefix_ = DEFAULT_BACKTRACE_DUMP_PREFIX;
341   } else {
342     backtrace_dump_prefix_ = value;
343   }
344   return true;
345 }
346 
SetBacktraceSize(const std::string & option,const std::string & value)347 bool Config::SetBacktraceSize(const std::string& option, const std::string& value) {
348   if (!ParseValue(option, value, 1, SIZE_MAX, &backtrace_min_size_bytes_)) {
349     return false;
350   }
351   backtrace_max_size_bytes_ = backtrace_min_size_bytes_;
352 
353   return true;
354 }
355 
SetBacktraceMinSize(const std::string & option,const std::string & value)356 bool Config::SetBacktraceMinSize(const std::string& option, const std::string& value) {
357   return ParseValue(option, value, 1, SIZE_MAX, &backtrace_min_size_bytes_);
358 }
359 
SetBacktraceMaxSize(const std::string & option,const std::string & value)360 bool Config::SetBacktraceMaxSize(const std::string& option, const std::string& value) {
361   return ParseValue(option, value, 1, SIZE_MAX, &backtrace_max_size_bytes_);
362 }
363 
SetExpandAlloc(const std::string & option,const std::string & value)364 bool Config::SetExpandAlloc(const std::string& option, const std::string& value) {
365   return ParseValue(option, value, DEFAULT_EXPAND_BYTES, 1, MAX_EXPAND_BYTES, &expand_alloc_bytes_);
366 }
367 
SetFreeTrack(const std::string & option,const std::string & value)368 bool Config::SetFreeTrack(const std::string& option, const std::string& value) {
369   // This option enables fill on free, so set the bytes to the default value.
370   if (fill_on_free_bytes_ == 0) {
371     fill_on_free_bytes_ = SIZE_MAX;
372   }
373   if (free_track_backtrace_num_frames_ == 0) {
374     free_track_backtrace_num_frames_ = DEFAULT_BACKTRACE_FRAMES;
375   }
376 
377   return ParseValue(option, value, DEFAULT_FREE_TRACK_ALLOCATIONS, 1, MAX_FREE_TRACK_ALLOCATIONS,
378                     &free_track_allocations_);
379 }
380 
SetFreeTrackBacktraceNumFrames(const std::string & option,const std::string & value)381 bool Config::SetFreeTrackBacktraceNumFrames(const std::string& option, const std::string& value) {
382   return ParseValue(option, value, DEFAULT_BACKTRACE_FRAMES, 0, MAX_BACKTRACE_FRAMES,
383                     &free_track_backtrace_num_frames_);
384 }
385 
SetRecordAllocs(const std::string & option,const std::string & value)386 bool Config::SetRecordAllocs(const std::string& option, const std::string& value) {
387   if (record_allocs_file_.empty()) {
388     record_allocs_file_ = DEFAULT_RECORD_ALLOCS_FILE;
389   }
390   return ParseValue(option, value, DEFAULT_RECORD_ALLOCS, 1, MAX_RECORD_ALLOCS,
391                     &record_allocs_num_entries_);
392 }
393 
SetRecordAllocsFile(const std::string &,const std::string & value)394 bool Config::SetRecordAllocsFile(const std::string&, const std::string& value) {
395   if (value.empty()) {
396     // Set the default.
397     record_allocs_file_ = DEFAULT_RECORD_ALLOCS_FILE;
398     return true;
399   }
400   record_allocs_file_ = value;
401   return true;
402 }
403 
VerifyValueEmpty(const std::string & option,const std::string & value)404 bool Config::VerifyValueEmpty(const std::string& option, const std::string& value) {
405   if (!value.empty()) {
406     // This is not valid.
407     error_log("%s: value set for option '%s' which does not take a value", getprogname(),
408               option.c_str());
409     return false;
410   }
411   return true;
412 }
413 
LogUsage() const414 void Config::LogUsage() const {
415   error_log("For malloc debug option descriptions go to:");
416   error_log(
417       "  https://android.googlesource.com/platform/bionic/+/main/libc/malloc_debug/README.md");
418 }
419 
GetOption(const char ** options_str,std::string * option,std::string * value)420 bool Config::GetOption(const char** options_str, std::string* option, std::string* value) {
421   const char* cur = *options_str;
422   // Process each property name we can find.
423   while (isspace(*cur)) ++cur;
424 
425   if (*cur == '\0') {
426     *options_str = cur;
427     return false;
428   }
429 
430   const char* start = cur;
431   while (!isspace(*cur) && *cur != '=' && *cur != '\0') ++cur;
432 
433   *option = std::string(start, cur - start);
434 
435   // Skip any spaces after the name.
436   while (isspace(*cur)) ++cur;
437 
438   value->clear();
439   if (*cur == '=') {
440     ++cur;
441     // Skip the space after the equal.
442     while (isspace(*cur)) ++cur;
443 
444     start = cur;
445     while (!isspace(*cur) && *cur != '\0') ++cur;
446 
447     if (cur != start) {
448       *value = std::string(start, cur - start);
449     }
450   }
451   *options_str = cur;
452   return true;
453 }
454 
Init(const char * options_str)455 bool Config::Init(const char* options_str) {
456   // Initialize a few default values.
457   fill_alloc_value_ = DEFAULT_FILL_ALLOC_VALUE;
458   fill_free_value_ = DEFAULT_FILL_FREE_VALUE;
459   front_guard_value_ = DEFAULT_FRONT_GUARD_VALUE;
460   rear_guard_value_ = DEFAULT_REAR_GUARD_VALUE;
461   backtrace_signal_ = SIGRTMAX - 19;
462   backtrace_dump_signal_ = SIGRTMAX - 17;
463   record_allocs_signal_ = SIGRTMAX - 18;
464   free_track_backtrace_num_frames_ = 0;
465   record_allocs_file_.clear();
466   fill_on_free_bytes_ = 0;
467   backtrace_enable_on_signal_ = false;
468   backtrace_enabled_ = false;
469   backtrace_dump_on_exit_ = false;
470   backtrace_dump_prefix_ = DEFAULT_BACKTRACE_DUMP_PREFIX;
471   backtrace_min_size_bytes_ = 0;
472   backtrace_max_size_bytes_ = SIZE_MAX;
473   check_unreachable_signal_ = SIGRTMAX - 16;
474   log_allocator_stats_signal_ = SIGRTMAX - 15;
475 
476   // Process each option name we can find.
477   std::string option;
478   std::string value;
479   bool valid = true;
480   while (GetOption(&options_str, &option, &value)) {
481     auto entry = kOptions.find(option);
482     if (entry == kOptions.end()) {
483       error_log("%s: unknown option %s", getprogname(), option.c_str());
484       valid = false;
485       break;
486     }
487 
488     const OptionInfo* info = &entry->second;
489     auto process_func = info->process_func;
490     if (process_func != nullptr && !(this->*process_func)(option, value)) {
491       valid = false;
492       break;
493     }
494     options_ |= info->option;
495   }
496 
497   if (!valid || *options_str != '\0') {
498     LogUsage();
499     return false;
500   }
501 
502   return true;
503 }
504