• 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 <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 
ParseValue(const std::string & option,const std::string & value,size_t min_value,size_t max_value,size_t * parsed_value) const143 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 
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) const184 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 
SetGuard(const std::string & option,const std::string & value)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 
SetFrontGuard(const std::string & option,const std::string & value)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 
SetRearGuard(const std::string & option,const std::string & value)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 
SetFill(const std::string & option,const std::string & value)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 
SetFillOnAlloc(const std::string & option,const std::string & value)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 
SetFillOnFree(const std::string & option,const std::string & value)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 
SetBacktrace(const std::string & option,const std::string & value)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 
SetBacktraceEnableOnSignal(const std::string & option,const std::string & value)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 
SetBacktraceDumpOnExit(const std::string & option,const std::string & value)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 
SetBacktraceDumpPrefix(const std::string &,const std::string & value)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 
SetExpandAlloc(const std::string & option,const std::string & value)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 
SetFreeTrack(const std::string & option,const std::string & value)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 
SetFreeTrackBacktraceNumFrames(const std::string & option,const std::string & value)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 
SetRecordAllocs(const std::string & option,const std::string & value)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 
SetRecordAllocsFile(const std::string &,const std::string & value)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 
VerifyValueEmpty(const std::string & option,const std::string & value)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 
LogUsage() const327 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 
GetOption(const char ** options_str,std::string * option,std::string * value)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 
Init(const char * options_str)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