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 | |