| 1 | //===-- sanitizer_flags_test.cpp ------------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // This file is a part of ThreadSanitizer/AddressSanitizer runtime. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | #include "sanitizer_common/sanitizer_common.h" |
| 13 | #include "sanitizer_common/sanitizer_flags.h" |
| 14 | #include "sanitizer_common/sanitizer_flag_parser.h" |
| 15 | #include "sanitizer_common/sanitizer_libc.h" |
| 16 | #include "sanitizer_common/sanitizer_allocator_internal.h" |
| 17 | #include "gtest/gtest.h" |
| 18 | |
| 19 | #include <stdint.h> |
| 20 | #include <string.h> |
| 21 | |
| 22 | namespace __sanitizer { |
| 23 | |
| 24 | static const char kFlagName[] = "flag_name" ; |
| 25 | static const char kFlagDesc[] = "flag description" ; |
| 26 | |
| 27 | template <typename T> |
| 28 | static void TestFlag(T start_value, const char *env, T final_value) { |
| 29 | T flag = start_value; |
| 30 | |
| 31 | FlagParser parser; |
| 32 | RegisterFlag(&parser, kFlagName, kFlagDesc, &flag); |
| 33 | |
| 34 | parser.ParseString(s: env); |
| 35 | |
| 36 | EXPECT_EQ(final_value, flag); |
| 37 | |
| 38 | // Reporting unrecognized flags is needed to reset them. |
| 39 | ReportUnrecognizedFlags(); |
| 40 | } |
| 41 | |
| 42 | template <> |
| 43 | void TestFlag(const char *start_value, const char *env, |
| 44 | const char *final_value) { |
| 45 | const char *flag = start_value; |
| 46 | |
| 47 | FlagParser parser; |
| 48 | RegisterFlag(parser: &parser, name: kFlagName, desc: kFlagDesc, var: &flag); |
| 49 | |
| 50 | parser.ParseString(s: env); |
| 51 | |
| 52 | EXPECT_EQ(0, internal_strcmp(s1: final_value, s2: flag)); |
| 53 | |
| 54 | // Reporting unrecognized flags is needed to reset them. |
| 55 | ReportUnrecognizedFlags(); |
| 56 | } |
| 57 | |
| 58 | TEST(SanitizerCommon, BooleanFlags) { |
| 59 | TestFlag(start_value: false, env: "flag_name=1" , final_value: true); |
| 60 | TestFlag(start_value: false, env: "flag_name=yes" , final_value: true); |
| 61 | TestFlag(start_value: false, env: "flag_name=true" , final_value: true); |
| 62 | TestFlag(start_value: true, env: "flag_name=0" , final_value: false); |
| 63 | TestFlag(start_value: true, env: "flag_name=no" , final_value: false); |
| 64 | TestFlag(start_value: true, env: "flag_name=false" , final_value: false); |
| 65 | |
| 66 | EXPECT_DEATH(TestFlag(start_value: false, env: "flag_name" , final_value: true), "expected '='" ); |
| 67 | EXPECT_DEATH(TestFlag(start_value: false, env: "flag_name=" , final_value: true), |
| 68 | "Invalid value for bool option: ''" ); |
| 69 | EXPECT_DEATH(TestFlag(start_value: false, env: "flag_name=2" , final_value: true), |
| 70 | "Invalid value for bool option: '2'" ); |
| 71 | EXPECT_DEATH(TestFlag(start_value: false, env: "flag_name=-1" , final_value: true), |
| 72 | "Invalid value for bool option: '-1'" ); |
| 73 | EXPECT_DEATH(TestFlag(start_value: false, env: "flag_name=on" , final_value: true), |
| 74 | "Invalid value for bool option: 'on'" ); |
| 75 | } |
| 76 | |
| 77 | TEST(SanitizerCommon, HandleSignalMode) { |
| 78 | TestFlag(start_value: kHandleSignalNo, env: "flag_name=1" , final_value: kHandleSignalYes); |
| 79 | TestFlag(start_value: kHandleSignalNo, env: "flag_name=yes" , final_value: kHandleSignalYes); |
| 80 | TestFlag(start_value: kHandleSignalNo, env: "flag_name=true" , final_value: kHandleSignalYes); |
| 81 | TestFlag(start_value: kHandleSignalYes, env: "flag_name=0" , final_value: kHandleSignalNo); |
| 82 | TestFlag(start_value: kHandleSignalYes, env: "flag_name=no" , final_value: kHandleSignalNo); |
| 83 | TestFlag(start_value: kHandleSignalYes, env: "flag_name=false" , final_value: kHandleSignalNo); |
| 84 | TestFlag(start_value: kHandleSignalNo, env: "flag_name=2" , final_value: kHandleSignalExclusive); |
| 85 | TestFlag(start_value: kHandleSignalYes, env: "flag_name=exclusive" , final_value: kHandleSignalExclusive); |
| 86 | |
| 87 | EXPECT_DEATH(TestFlag(start_value: kHandleSignalNo, env: "flag_name" , final_value: kHandleSignalNo), |
| 88 | "expected '='" ); |
| 89 | EXPECT_DEATH(TestFlag(start_value: kHandleSignalNo, env: "flag_name=" , final_value: kHandleSignalNo), |
| 90 | "Invalid value for signal handler option: ''" ); |
| 91 | EXPECT_DEATH(TestFlag(start_value: kHandleSignalNo, env: "flag_name=3" , final_value: kHandleSignalNo), |
| 92 | "Invalid value for signal handler option: '3'" ); |
| 93 | EXPECT_DEATH(TestFlag(start_value: kHandleSignalNo, env: "flag_name=-1" , final_value: kHandleSignalNo), |
| 94 | "Invalid value for signal handler option: '-1'" ); |
| 95 | EXPECT_DEATH(TestFlag(start_value: kHandleSignalNo, env: "flag_name=on" , final_value: kHandleSignalNo), |
| 96 | "Invalid value for signal handler option: 'on'" ); |
| 97 | } |
| 98 | |
| 99 | TEST(SanitizerCommon, IntFlags) { |
| 100 | TestFlag(start_value: -11, env: 0, final_value: -11); |
| 101 | TestFlag(start_value: -11, env: "flag_name=0" , final_value: 0); |
| 102 | TestFlag(start_value: -11, env: "flag_name=42" , final_value: 42); |
| 103 | TestFlag(start_value: -11, env: "flag_name=-42" , final_value: -42); |
| 104 | |
| 105 | // Unrecognized flags are ignored. |
| 106 | TestFlag(start_value: -11, env: "--flag_name=42" , final_value: -11); |
| 107 | TestFlag(start_value: -11, env: "zzzzzzz=42" , final_value: -11); |
| 108 | |
| 109 | EXPECT_DEATH(TestFlag(start_value: -11, env: "flag_name" , final_value: 0), "expected '='" ); |
| 110 | EXPECT_DEATH(TestFlag(start_value: -11, env: "flag_name=42U" , final_value: 0), |
| 111 | "Invalid value for int option" ); |
| 112 | } |
| 113 | |
| 114 | TEST(SanitizerCommon, LongLongIntFlags) { |
| 115 | s64 InitValue = -5; |
| 116 | s64 IntMin = INT64_MIN; |
| 117 | s64 IntMax = INT64_MAX; |
| 118 | TestFlag(start_value: InitValue, env: "flag_name=0" , final_value: 0ll); |
| 119 | TestFlag(start_value: InitValue, env: "flag_name=42" , final_value: 42ll); |
| 120 | TestFlag(start_value: InitValue, env: "flag_name=-42" , final_value: -42ll); |
| 121 | |
| 122 | TestFlag(start_value: InitValue, env: "flag_name=-9223372036854775808" , final_value: IntMin); |
| 123 | TestFlag(start_value: InitValue, env: "flag_name=9223372036854775807" , final_value: IntMax); |
| 124 | |
| 125 | TestFlag(start_value: InitValue, env: "flag_name=-92233720368547758080000" , final_value: IntMin); |
| 126 | TestFlag(start_value: InitValue, env: "flag_name=92233720368547758070000" , final_value: IntMax); |
| 127 | } |
| 128 | |
| 129 | TEST(SanitizerCommon, StrFlags) { |
| 130 | TestFlag(start_value: "zzz" , env: 0, final_value: "zzz" ); |
| 131 | TestFlag(start_value: "zzz" , env: "flag_name=" , final_value: "" ); |
| 132 | TestFlag(start_value: "zzz" , env: "flag_name=abc" , final_value: "abc" ); |
| 133 | TestFlag(start_value: "" , env: "flag_name=abc" , final_value: "abc" ); |
| 134 | TestFlag(start_value: "" , env: "flag_name='abc zxc'" , final_value: "abc zxc" ); |
| 135 | // TestStrFlag("", "flag_name=\"abc qwe\" asd", "abc qwe"); |
| 136 | } |
| 137 | |
| 138 | static void TestTwoFlags(const char *env, bool expected_flag1, |
| 139 | const char *expected_flag2, |
| 140 | const char *name1 = "flag1" , |
| 141 | const char *name2 = "flag2" ) { |
| 142 | bool flag1 = !expected_flag1; |
| 143 | const char *flag2 = "" ; |
| 144 | |
| 145 | FlagParser parser; |
| 146 | RegisterFlag(parser: &parser, name: name1, desc: kFlagDesc, var: &flag1); |
| 147 | RegisterFlag(parser: &parser, name: name2, desc: kFlagDesc, var: &flag2); |
| 148 | |
| 149 | parser.ParseString(s: env); |
| 150 | |
| 151 | EXPECT_EQ(expected_flag1, flag1); |
| 152 | EXPECT_EQ(0, internal_strcmp(s1: flag2, s2: expected_flag2)); |
| 153 | |
| 154 | // Reporting unrecognized flags is needed to reset them. |
| 155 | ReportUnrecognizedFlags(); |
| 156 | } |
| 157 | |
| 158 | TEST(SanitizerCommon, MultipleFlags) { |
| 159 | TestTwoFlags(env: "flag1=1 flag2='zzz'" , expected_flag1: true, expected_flag2: "zzz" ); |
| 160 | TestTwoFlags(env: "flag2='qxx' flag1=0" , expected_flag1: false, expected_flag2: "qxx" ); |
| 161 | TestTwoFlags(env: "flag1=false:flag2='zzz'" , expected_flag1: false, expected_flag2: "zzz" ); |
| 162 | TestTwoFlags(env: "flag2=qxx:flag1=yes" , expected_flag1: true, expected_flag2: "qxx" ); |
| 163 | TestTwoFlags(env: "flag2=qxx\nflag1=yes" , expected_flag1: true, expected_flag2: "qxx" ); |
| 164 | TestTwoFlags(env: "flag2=qxx\r\nflag1=yes" , expected_flag1: true, expected_flag2: "qxx" ); |
| 165 | TestTwoFlags(env: "flag2=qxx\tflag1=yes" , expected_flag1: true, expected_flag2: "qxx" ); |
| 166 | } |
| 167 | |
| 168 | TEST(SanitizerCommon, CommonSuffixFlags) { |
| 169 | TestTwoFlags(env: "flag=1 other_flag='zzz'" , expected_flag1: true, expected_flag2: "zzz" , name1: "flag" , name2: "other_flag" ); |
| 170 | TestTwoFlags(env: "other_flag='zzz' flag=1" , expected_flag1: true, expected_flag2: "zzz" , name1: "flag" , name2: "other_flag" ); |
| 171 | TestTwoFlags(env: "other_flag=' flag=0 ' flag=1" , expected_flag1: true, expected_flag2: " flag=0 " , name1: "flag" , |
| 172 | name2: "other_flag" ); |
| 173 | TestTwoFlags(env: "flag=1 other_flag=' flag=0 '" , expected_flag1: true, expected_flag2: " flag=0 " , name1: "flag" , |
| 174 | name2: "other_flag" ); |
| 175 | } |
| 176 | |
| 177 | TEST(SanitizerCommon, CommonFlags) { |
| 178 | CommonFlags cf; |
| 179 | FlagParser parser; |
| 180 | RegisterCommonFlags(parser: &parser, cf: &cf); |
| 181 | |
| 182 | cf.SetDefaults(); |
| 183 | EXPECT_TRUE(cf.symbolize); |
| 184 | EXPECT_STREQ("." , cf.coverage_dir); |
| 185 | |
| 186 | cf.symbolize = false; |
| 187 | cf.coverage = true; |
| 188 | cf.heap_profile = true; |
| 189 | cf.log_path = "path/one" ; |
| 190 | |
| 191 | parser.ParseString(s: "symbolize=1:heap_profile=false log_path='path/two'" ); |
| 192 | EXPECT_TRUE(cf.symbolize); |
| 193 | EXPECT_TRUE(cf.coverage); |
| 194 | EXPECT_FALSE(cf.heap_profile); |
| 195 | EXPECT_STREQ("path/two" , cf.log_path); |
| 196 | } |
| 197 | |
| 198 | } // namespace __sanitizer |
| 199 | |