diff options
-rw-r--r-- | libc/malloc_debug/Config.cpp | 57 | ||||
-rw-r--r-- | libc/malloc_debug/tests/malloc_debug_config_tests.cpp | 176 |
2 files changed, 209 insertions, 24 deletions
diff --git a/libc/malloc_debug/Config.cpp b/libc/malloc_debug/Config.cpp index 76901e2bf..224bb08ed 100644 --- a/libc/malloc_debug/Config.cpp +++ b/libc/malloc_debug/Config.cpp @@ -45,12 +45,14 @@ #include "debug_log.h" struct Feature { - Feature(std::string name, size_t default_value, uint64_t option, size_t* value, - bool* config, bool combo_option) - : name(name), default_value(default_value), option(option), value(value), - config(config), combo_option(combo_option) {} + Feature(std::string name, size_t default_value, size_t min_value, size_t max_value, + uint64_t option, size_t* value, bool* config, bool combo_option) + : name(name), default_value(default_value), min_value(min_value), max_value(max_value), + option(option), value(value), config(config), combo_option(combo_option) {} std::string name; size_t default_value = 0; + size_t min_value = 0; + size_t max_value = 0; uint64_t option = 0; size_t* value = nullptr; @@ -123,8 +125,8 @@ bool PropertyParser::Get(std::string* property, size_t* value, bool* value_set) getprogname(), property->c_str(), end); } return false; - } else if (read_value <= 0) { - error_log("%s: bad value for option '%s', value must be > 0: %ld", + } else if (read_value < 0) { + error_log("%s: bad value for option '%s', value cannot be negative: %ld", getprogname(), property->c_str(), read_value); return false; } @@ -200,19 +202,29 @@ void PropertyParser::LogUsage() { error_log(" Enable the leak tracking of memory allocations."); } -static bool SetFeature(const Feature& feature, size_t value, bool value_set) { +static bool SetFeature( + const std::string name, const Feature& feature, size_t value, bool value_set) { if (feature.config) { *feature.config = true; } if (feature.value != nullptr) { if (value_set) { + if (value < feature.min_value) { + error_log("%s: bad value for option '%s', value must be >= %zu: %zu", + getprogname(), name.c_str(), feature.min_value, value); + return false; + } else if (value > feature.max_value) { + error_log("%s: bad value for option '%s', value must be <= %zu: %zu", + getprogname(), name.c_str(), feature.max_value, value); + return false; + } *feature.value = value; } else { *feature.value = feature.default_value; } } else if (value_set) { error_log("%s: value set for option '%s' which does not take a value", - getprogname(), feature.name.c_str()); + getprogname(), name.c_str()); return false; } return true; @@ -239,43 +251,44 @@ bool Config::SetFromProperties() { // Supported features: const Feature features[] = { - Feature("guard", 32, 0, nullptr, nullptr, true), + Feature("guard", 32, 1, 16384, 0, nullptr, nullptr, true), // Enable front guard. Value is the size of the guard. - Feature("front_guard", 32, FRONT_GUARD, &this->front_guard_bytes, nullptr, true), + Feature("front_guard", 32, 1, 16384, FRONT_GUARD, &this->front_guard_bytes, nullptr, true), // Enable end guard. Value is the size of the guard. - Feature("rear_guard", 32, REAR_GUARD, &this->rear_guard_bytes, nullptr, true), + Feature("rear_guard", 32, 1, 16384, REAR_GUARD, &this->rear_guard_bytes, nullptr, true), // Enable logging the backtrace on allocation. Value is the total // number of frames to log. - Feature("backtrace", 16, BACKTRACE | TRACK_ALLOCS, &this->backtrace_frames, + Feature("backtrace", 16, 1, 256, BACKTRACE | TRACK_ALLOCS, &this->backtrace_frames, &this->backtrace_enabled, false), // Enable gathering backtrace values on a signal. - Feature("backtrace_enable_on_signal", 16, BACKTRACE | TRACK_ALLOCS, &this->backtrace_frames, - &this->backtrace_enable_on_signal, false), + Feature("backtrace_enable_on_signal", 16, 1, 256, BACKTRACE | TRACK_ALLOCS, + &this->backtrace_frames, &this->backtrace_enable_on_signal, false), - Feature("fill", SIZE_MAX, 0, nullptr, nullptr, true), + Feature("fill", SIZE_MAX, 1, SIZE_MAX, 0, nullptr, nullptr, true), // Fill the allocation with an arbitrary pattern on allocation. // Value is the number of bytes of the allocation to fill // (default entire allocation). - Feature("fill_on_alloc", SIZE_MAX, FILL_ON_ALLOC, &this->fill_on_alloc_bytes, + Feature("fill_on_alloc", SIZE_MAX, 1, SIZE_MAX, FILL_ON_ALLOC, &this->fill_on_alloc_bytes, nullptr, true), // Fill the allocation with an arbitrary pattern on free. // Value is the number of bytes of the allocation to fill // (default entire allocation). - Feature("fill_on_free", SIZE_MAX, FILL_ON_FREE, &this->fill_on_free_bytes, nullptr, true), + Feature("fill_on_free", SIZE_MAX, 1, SIZE_MAX, FILL_ON_FREE, &this->fill_on_free_bytes, nullptr, true), // Expand the size of every alloc by this number bytes. Value is // the total number of bytes to expand every allocation by. - Feature ("expand_alloc", 16, EXPAND_ALLOC, &this->expand_alloc_bytes, nullptr, false), + Feature ("expand_alloc", 16, 1, 16384, EXPAND_ALLOC, &this->expand_alloc_bytes, + nullptr, false), // Keep track of the freed allocations and verify at a later date // that they have not been used. Turning this on, also turns on // fill on free. - Feature("free_track", 100, FREE_TRACK | FILL_ON_FREE, &this->free_track_allocations, + Feature("free_track", 100, 1, 16384, FREE_TRACK | FILL_ON_FREE, &this->free_track_allocations, nullptr, false), // Enable printing leaked allocations. - Feature("leak_track", 0, LEAK_TRACK | TRACK_ALLOCS, nullptr, nullptr, false), + Feature("leak_track", 0, 0, 0, LEAK_TRACK | TRACK_ALLOCS, nullptr, nullptr, false), }; // Process each property name we can find. @@ -291,7 +304,7 @@ bool Config::SetFromProperties() { if (features[i].option == 0 && features[i].combo_option) { i++; for (; i < sizeof(features)/sizeof(Feature) && features[i].combo_option; i++) { - if (!SetFeature(features[i], value, value_set)) { + if (!SetFeature(property, features[i], value, value_set)) { valid = false; break; } @@ -301,7 +314,7 @@ bool Config::SetFromProperties() { break; } } else { - if (!SetFeature(features[i], value, value_set)) { + if (!SetFeature(property, features[i], value, value_set)) { valid = false; break; } diff --git a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp index ad25948b1..247e31979 100644 --- a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp +++ b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp @@ -127,7 +127,8 @@ TEST_F(MallocDebugConfigTest, illegal_value_zero) { ASSERT_FALSE(InitConfig("backtrace=0")); ASSERT_STREQ("", getFakeLogBuf().c_str()); - std::string log_msg("6 malloc_debug malloc_testing: bad value for option 'backtrace', value must be > 0: 0\n"); + std::string log_msg( + "6 malloc_debug malloc_testing: bad value for option 'backtrace', value must be >= 1: 0\n"); ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str()); } @@ -145,7 +146,9 @@ TEST_F(MallocDebugConfigTest, illegal_value_negative) { ASSERT_FALSE(InitConfig("backtrace=-1")); ASSERT_STREQ("", getFakeLogBuf().c_str()); - std::string log_msg("6 malloc_debug malloc_testing: bad value for option 'backtrace', value must be > 0: -1\n"); + std::string log_msg( + "6 malloc_debug malloc_testing: bad value for option 'backtrace', " + "value cannot be negative: -1\n"); ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str()); } @@ -378,3 +381,172 @@ TEST_F(MallocDebugConfigTest, leak_track_fail) { "which does not take a value\n"); ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str()); } + +TEST_F(MallocDebugConfigTest, guard_min_error) { + ASSERT_FALSE(InitConfig("guard=0")); + + ASSERT_STREQ("", getFakeLogBuf().c_str()); + std::string log_msg( + "6 malloc_debug malloc_testing: bad value for option 'guard', value must be >= 1: 0\n"); + ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str()); +} + +TEST_F(MallocDebugConfigTest, guard_max_error) { + ASSERT_FALSE(InitConfig("guard=20000")); + + ASSERT_STREQ("", getFakeLogBuf().c_str()); + std::string log_msg( + "6 malloc_debug malloc_testing: bad value for option 'guard', " + "value must be <= 16384: 20000\n"); + ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str()); +} + +TEST_F(MallocDebugConfigTest, front_guard_min_error) { + ASSERT_FALSE(InitConfig("front_guard=0")); + + ASSERT_STREQ("", getFakeLogBuf().c_str()); + std::string log_msg( + "6 malloc_debug malloc_testing: bad value for option 'front_guard', " + "value must be >= 1: 0\n"); + ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str()); +} + +TEST_F(MallocDebugConfigTest, front_guard_max_error) { + ASSERT_FALSE(InitConfig("front_guard=20000")); + + ASSERT_STREQ("", getFakeLogBuf().c_str()); + std::string log_msg( + "6 malloc_debug malloc_testing: bad value for option 'front_guard', " + "value must be <= 16384: 20000\n"); + ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str()); +} + +TEST_F(MallocDebugConfigTest, rear_guard_min_error) { + ASSERT_FALSE(InitConfig("rear_guard=0")); + + ASSERT_STREQ("", getFakeLogBuf().c_str()); + std::string log_msg( + "6 malloc_debug malloc_testing: bad value for option 'rear_guard', " + "value must be >= 1: 0\n"); + ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str()); +} + +TEST_F(MallocDebugConfigTest, rear_guard_max_error) { + ASSERT_FALSE(InitConfig("rear_guard=20000")); + + ASSERT_STREQ("", getFakeLogBuf().c_str()); + std::string log_msg( + "6 malloc_debug malloc_testing: bad value for option 'rear_guard', " + "value must be <= 16384: 20000\n"); + ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str()); +} + +TEST_F(MallocDebugConfigTest, fill_min_error) { + ASSERT_FALSE(InitConfig("fill=0")); + + ASSERT_STREQ("", getFakeLogBuf().c_str()); + std::string log_msg( + "6 malloc_debug malloc_testing: bad value for option 'fill', " + "value must be >= 1: 0\n"); + ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str()); +} + +TEST_F(MallocDebugConfigTest, fill_on_alloc_min_error) { + ASSERT_FALSE(InitConfig("fill_on_alloc=0")); + + ASSERT_STREQ("", getFakeLogBuf().c_str()); + std::string log_msg( + "6 malloc_debug malloc_testing: bad value for option 'fill_on_alloc', " + "value must be >= 1: 0\n"); + ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str()); +} + +TEST_F(MallocDebugConfigTest, fill_on_free_min_error) { + ASSERT_FALSE(InitConfig("fill_on_free=0")); + + ASSERT_STREQ("", getFakeLogBuf().c_str()); + std::string log_msg( + "6 malloc_debug malloc_testing: bad value for option 'fill_on_free', " + "value must be >= 1: 0\n"); + ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str()); +} + +TEST_F(MallocDebugConfigTest, backtrace_min_error) { + ASSERT_FALSE(InitConfig("backtrace=0")); + + ASSERT_STREQ("", getFakeLogBuf().c_str()); + std::string log_msg( + "6 malloc_debug malloc_testing: bad value for option 'backtrace', " + "value must be >= 1: 0\n"); + ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str()); +} + +TEST_F(MallocDebugConfigTest, backtrace_max_error) { + ASSERT_FALSE(InitConfig("backtrace=300")); + + ASSERT_STREQ("", getFakeLogBuf().c_str()); + std::string log_msg( + "6 malloc_debug malloc_testing: bad value for option 'backtrace', " + "value must be <= 256: 300\n"); + ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str()); +} + +TEST_F(MallocDebugConfigTest, backtrace_enable_on_signal_min_error) { + ASSERT_FALSE(InitConfig("backtrace_enable_on_signal=0")); + + ASSERT_STREQ("", getFakeLogBuf().c_str()); + std::string log_msg( + "6 malloc_debug malloc_testing: bad value for option 'backtrace_enable_on_signal', " + "value must be >= 1: 0\n"); + ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str()); +} + +TEST_F(MallocDebugConfigTest, backtrace_enable_on_signal_max_error) { + ASSERT_FALSE(InitConfig("backtrace_enable_on_signal=300")); + + ASSERT_STREQ("", getFakeLogBuf().c_str()); + std::string log_msg( + "6 malloc_debug malloc_testing: bad value for option 'backtrace_enable_on_signal', " + "value must be <= 256: 300\n"); + ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str()); +} + +TEST_F(MallocDebugConfigTest, expand_alloc_min_error) { + ASSERT_FALSE(InitConfig("expand_alloc=0")); + + ASSERT_STREQ("", getFakeLogBuf().c_str()); + std::string log_msg( + "6 malloc_debug malloc_testing: bad value for option 'expand_alloc', " + "value must be >= 1: 0\n"); + ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str()); +} + +TEST_F(MallocDebugConfigTest, expand_alloc_max_error) { + ASSERT_FALSE(InitConfig("expand_alloc=21000")); + + ASSERT_STREQ("", getFakeLogBuf().c_str()); + std::string log_msg( + "6 malloc_debug malloc_testing: bad value for option 'expand_alloc', " + "value must be <= 16384: 21000\n"); + ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str()); +} + +TEST_F(MallocDebugConfigTest, free_track_min_error) { + ASSERT_FALSE(InitConfig("free_track=0")); + + ASSERT_STREQ("", getFakeLogBuf().c_str()); + std::string log_msg( + "6 malloc_debug malloc_testing: bad value for option 'free_track', " + "value must be >= 1: 0\n"); + ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str()); +} + +TEST_F(MallocDebugConfigTest, free_track_max_error) { + ASSERT_FALSE(InitConfig("free_track=21000")); + + ASSERT_STREQ("", getFakeLogBuf().c_str()); + std::string log_msg( + "6 malloc_debug malloc_testing: bad value for option 'free_track', " + "value must be <= 16384: 21000\n"); + ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str()); +} |