1 //===-- sanitizer_flag_parser.cc ------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is a part of ThreadSanitizer/AddressSanitizer runtime.
10 //===----------------------------------------------------------------------===//
12 #include "sanitizer_flag_parser.h"
14 #include "sanitizer_common.h"
15 #include "sanitizer_libc.h"
16 #include "sanitizer_flags.h"
17 #include "sanitizer_flag_parser.h"
19 namespace __sanitizer
{
21 LowLevelAllocator
FlagParser::Alloc
;
24 static const int kMaxUnknownFlags
= 20;
25 const char *unknown_flags_
[kMaxUnknownFlags
];
29 void Add(const char *name
) {
30 CHECK_LT(n_unknown_flags_
, kMaxUnknownFlags
);
31 unknown_flags_
[n_unknown_flags_
++] = name
;
35 if (!n_unknown_flags_
) return;
36 Printf("WARNING: found %d unrecognized flag(s):\n", n_unknown_flags_
);
37 for (int i
= 0; i
< n_unknown_flags_
; ++i
)
38 Printf(" %s\n", unknown_flags_
[i
]);
43 UnknownFlags unknown_flags
;
45 void ReportUnrecognizedFlags() {
46 unknown_flags
.Report();
49 char *FlagParser::ll_strndup(const char *s
, uptr n
) {
50 uptr len
= internal_strnlen(s
, n
);
51 char *s2
= (char*)Alloc
.Allocate(len
+ 1);
52 internal_memcpy(s2
, s
, len
);
57 void FlagParser::PrintFlagDescriptions() {
58 Printf("Available flags for %s:\n", SanitizerToolName
);
59 for (int i
= 0; i
< n_flags_
; ++i
)
60 Printf("\t%s\n\t\t- %s\n", flags_
[i
].name
, flags_
[i
].desc
);
63 void FlagParser::fatal_error(const char *err
) {
64 Printf("ERROR: %s\n", err
);
68 bool FlagParser::is_space(char c
) {
69 return c
== ' ' || c
== ',' || c
== ':' || c
== '\n' || c
== '\t' ||
73 void FlagParser::skip_whitespace() {
74 while (is_space(buf_
[pos_
])) ++pos_
;
77 void FlagParser::parse_flag() {
78 uptr name_start
= pos_
;
79 while (buf_
[pos_
] != 0 && buf_
[pos_
] != '=' && !is_space(buf_
[pos_
])) ++pos_
;
80 if (buf_
[pos_
] != '=') fatal_error("expected '='");
81 char *name
= ll_strndup(buf_
+ name_start
, pos_
- name_start
);
83 uptr value_start
= ++pos_
;
85 if (buf_
[pos_
] == '\'' || buf_
[pos_
] == '"') {
86 char quote
= buf_
[pos_
++];
87 while (buf_
[pos_
] != 0 && buf_
[pos_
] != quote
) ++pos_
;
88 if (buf_
[pos_
] == 0) fatal_error("unterminated string");
89 value
= ll_strndup(buf_
+ value_start
+ 1, pos_
- value_start
- 1);
90 ++pos_
; // consume the closing quote
92 while (buf_
[pos_
] != 0 && !is_space(buf_
[pos_
])) ++pos_
;
93 if (buf_
[pos_
] != 0 && !is_space(buf_
[pos_
]))
94 fatal_error("expected separator or eol");
95 value
= ll_strndup(buf_
+ value_start
, pos_
- value_start
);
98 bool res
= run_handler(name
, value
);
99 if (!res
) fatal_error("Flag parsing failed.");
102 void FlagParser::parse_flags() {
105 if (buf_
[pos_
] == 0) break;
109 // Do a sanity check for certain flags.
110 if (common_flags_dont_use
.malloc_context_size
< 1)
111 common_flags_dont_use
.malloc_context_size
= 1;
114 void FlagParser::ParseString(const char *s
) {
116 // Backup current parser state to allow nested ParseString() calls.
117 const char *old_buf_
= buf_
;
118 uptr old_pos_
= pos_
;
128 bool FlagParser::ParseFile(const char *path
, bool ignore_missing
) {
129 static const uptr kMaxIncludeSize
= 1 << 15;
131 uptr data_mapped_size
;
134 if (!ReadFileToBuffer(path
, &data
, &data_mapped_size
, &len
,
135 Max(kMaxIncludeSize
, GetPageSizeCached()), &err
)) {
138 Printf("Failed to read options from '%s': error %d\n", path
, err
);
142 UnmapOrDie(data
, data_mapped_size
);
146 bool FlagParser::run_handler(const char *name
, const char *value
) {
147 for (int i
= 0; i
< n_flags_
; ++i
) {
148 if (internal_strcmp(name
, flags_
[i
].name
) == 0)
149 return flags_
[i
].handler
->Parse(value
);
151 // Unrecognized flag. This is not a fatal error, we may print a warning later.
152 unknown_flags
.Add(name
);
156 void FlagParser::RegisterHandler(const char *name
, FlagHandlerBase
*handler
,
158 CHECK_LT(n_flags_
, kMaxFlags
);
159 flags_
[n_flags_
].name
= name
;
160 flags_
[n_flags_
].desc
= desc
;
161 flags_
[n_flags_
].handler
= handler
;
165 FlagParser::FlagParser() : n_flags_(0), buf_(nullptr), pos_(0) {
166 flags_
= (Flag
*)Alloc
.Allocate(sizeof(Flag
) * kMaxFlags
);
169 } // namespace __sanitizer