annotate clang/lib/AST/ScanfFormatString.cpp @ 176:de4ac79aef9d

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 17:13:11 +0900
parents 1d019706d866
children c4bab56944e8
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
150
anatofuz
parents:
diff changeset
1 //= ScanfFormatString.cpp - Analysis of printf format strings --*- C++ -*-===//
anatofuz
parents:
diff changeset
2 //
anatofuz
parents:
diff changeset
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
anatofuz
parents:
diff changeset
4 // See https://llvm.org/LICENSE.txt for license information.
anatofuz
parents:
diff changeset
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
anatofuz
parents:
diff changeset
6 //
anatofuz
parents:
diff changeset
7 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
8 //
anatofuz
parents:
diff changeset
9 // Handling of format string in scanf and friends. The structure of format
anatofuz
parents:
diff changeset
10 // strings for fscanf() are described in C99 7.19.6.2.
anatofuz
parents:
diff changeset
11 //
anatofuz
parents:
diff changeset
12 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
13
anatofuz
parents:
diff changeset
14 #include "clang/AST/FormatString.h"
anatofuz
parents:
diff changeset
15 #include "FormatStringParsing.h"
anatofuz
parents:
diff changeset
16 #include "clang/Basic/TargetInfo.h"
anatofuz
parents:
diff changeset
17
anatofuz
parents:
diff changeset
18 using clang::analyze_format_string::ArgType;
anatofuz
parents:
diff changeset
19 using clang::analyze_format_string::FormatStringHandler;
anatofuz
parents:
diff changeset
20 using clang::analyze_format_string::LengthModifier;
anatofuz
parents:
diff changeset
21 using clang::analyze_format_string::OptionalAmount;
anatofuz
parents:
diff changeset
22 using clang::analyze_format_string::ConversionSpecifier;
anatofuz
parents:
diff changeset
23 using clang::analyze_scanf::ScanfConversionSpecifier;
anatofuz
parents:
diff changeset
24 using clang::analyze_scanf::ScanfSpecifier;
anatofuz
parents:
diff changeset
25 using clang::UpdateOnReturn;
anatofuz
parents:
diff changeset
26 using namespace clang;
anatofuz
parents:
diff changeset
27
anatofuz
parents:
diff changeset
28 typedef clang::analyze_format_string::SpecifierResult<ScanfSpecifier>
anatofuz
parents:
diff changeset
29 ScanfSpecifierResult;
anatofuz
parents:
diff changeset
30
anatofuz
parents:
diff changeset
31 static bool ParseScanList(FormatStringHandler &H,
anatofuz
parents:
diff changeset
32 ScanfConversionSpecifier &CS,
anatofuz
parents:
diff changeset
33 const char *&Beg, const char *E) {
anatofuz
parents:
diff changeset
34 const char *I = Beg;
anatofuz
parents:
diff changeset
35 const char *start = I - 1;
anatofuz
parents:
diff changeset
36 UpdateOnReturn <const char*> UpdateBeg(Beg, I);
anatofuz
parents:
diff changeset
37
anatofuz
parents:
diff changeset
38 // No more characters?
anatofuz
parents:
diff changeset
39 if (I == E) {
anatofuz
parents:
diff changeset
40 H.HandleIncompleteScanList(start, I);
anatofuz
parents:
diff changeset
41 return true;
anatofuz
parents:
diff changeset
42 }
anatofuz
parents:
diff changeset
43
anatofuz
parents:
diff changeset
44 // Special case: ']' is the first character.
anatofuz
parents:
diff changeset
45 if (*I == ']') {
anatofuz
parents:
diff changeset
46 if (++I == E) {
anatofuz
parents:
diff changeset
47 H.HandleIncompleteScanList(start, I - 1);
anatofuz
parents:
diff changeset
48 return true;
anatofuz
parents:
diff changeset
49 }
anatofuz
parents:
diff changeset
50 }
anatofuz
parents:
diff changeset
51
anatofuz
parents:
diff changeset
52 // Special case: "^]" are the first characters.
anatofuz
parents:
diff changeset
53 if (I + 1 != E && I[0] == '^' && I[1] == ']') {
anatofuz
parents:
diff changeset
54 I += 2;
anatofuz
parents:
diff changeset
55 if (I == E) {
anatofuz
parents:
diff changeset
56 H.HandleIncompleteScanList(start, I - 1);
anatofuz
parents:
diff changeset
57 return true;
anatofuz
parents:
diff changeset
58 }
anatofuz
parents:
diff changeset
59 }
anatofuz
parents:
diff changeset
60
anatofuz
parents:
diff changeset
61 // Look for a ']' character which denotes the end of the scan list.
anatofuz
parents:
diff changeset
62 while (*I != ']') {
anatofuz
parents:
diff changeset
63 if (++I == E) {
anatofuz
parents:
diff changeset
64 H.HandleIncompleteScanList(start, I - 1);
anatofuz
parents:
diff changeset
65 return true;
anatofuz
parents:
diff changeset
66 }
anatofuz
parents:
diff changeset
67 }
anatofuz
parents:
diff changeset
68
anatofuz
parents:
diff changeset
69 CS.setEndScanList(I);
anatofuz
parents:
diff changeset
70 return false;
anatofuz
parents:
diff changeset
71 }
anatofuz
parents:
diff changeset
72
anatofuz
parents:
diff changeset
73 // FIXME: Much of this is copy-paste from ParsePrintfSpecifier.
anatofuz
parents:
diff changeset
74 // We can possibly refactor.
anatofuz
parents:
diff changeset
75 static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
anatofuz
parents:
diff changeset
76 const char *&Beg,
anatofuz
parents:
diff changeset
77 const char *E,
anatofuz
parents:
diff changeset
78 unsigned &argIndex,
anatofuz
parents:
diff changeset
79 const LangOptions &LO,
anatofuz
parents:
diff changeset
80 const TargetInfo &Target) {
anatofuz
parents:
diff changeset
81 using namespace clang::analyze_format_string;
anatofuz
parents:
diff changeset
82 using namespace clang::analyze_scanf;
anatofuz
parents:
diff changeset
83 const char *I = Beg;
anatofuz
parents:
diff changeset
84 const char *Start = nullptr;
anatofuz
parents:
diff changeset
85 UpdateOnReturn <const char*> UpdateBeg(Beg, I);
anatofuz
parents:
diff changeset
86
anatofuz
parents:
diff changeset
87 // Look for a '%' character that indicates the start of a format specifier.
anatofuz
parents:
diff changeset
88 for ( ; I != E ; ++I) {
anatofuz
parents:
diff changeset
89 char c = *I;
anatofuz
parents:
diff changeset
90 if (c == '\0') {
anatofuz
parents:
diff changeset
91 // Detect spurious null characters, which are likely errors.
anatofuz
parents:
diff changeset
92 H.HandleNullChar(I);
anatofuz
parents:
diff changeset
93 return true;
anatofuz
parents:
diff changeset
94 }
anatofuz
parents:
diff changeset
95 if (c == '%') {
anatofuz
parents:
diff changeset
96 Start = I++; // Record the start of the format specifier.
anatofuz
parents:
diff changeset
97 break;
anatofuz
parents:
diff changeset
98 }
anatofuz
parents:
diff changeset
99 }
anatofuz
parents:
diff changeset
100
anatofuz
parents:
diff changeset
101 // No format specifier found?
anatofuz
parents:
diff changeset
102 if (!Start)
anatofuz
parents:
diff changeset
103 return false;
anatofuz
parents:
diff changeset
104
anatofuz
parents:
diff changeset
105 if (I == E) {
anatofuz
parents:
diff changeset
106 // No more characters left?
anatofuz
parents:
diff changeset
107 H.HandleIncompleteSpecifier(Start, E - Start);
anatofuz
parents:
diff changeset
108 return true;
anatofuz
parents:
diff changeset
109 }
anatofuz
parents:
diff changeset
110
anatofuz
parents:
diff changeset
111 ScanfSpecifier FS;
anatofuz
parents:
diff changeset
112 if (ParseArgPosition(H, FS, Start, I, E))
anatofuz
parents:
diff changeset
113 return true;
anatofuz
parents:
diff changeset
114
anatofuz
parents:
diff changeset
115 if (I == E) {
anatofuz
parents:
diff changeset
116 // No more characters left?
anatofuz
parents:
diff changeset
117 H.HandleIncompleteSpecifier(Start, E - Start);
anatofuz
parents:
diff changeset
118 return true;
anatofuz
parents:
diff changeset
119 }
anatofuz
parents:
diff changeset
120
anatofuz
parents:
diff changeset
121 // Look for '*' flag if it is present.
anatofuz
parents:
diff changeset
122 if (*I == '*') {
anatofuz
parents:
diff changeset
123 FS.setSuppressAssignment(I);
anatofuz
parents:
diff changeset
124 if (++I == E) {
anatofuz
parents:
diff changeset
125 H.HandleIncompleteSpecifier(Start, E - Start);
anatofuz
parents:
diff changeset
126 return true;
anatofuz
parents:
diff changeset
127 }
anatofuz
parents:
diff changeset
128 }
anatofuz
parents:
diff changeset
129
anatofuz
parents:
diff changeset
130 // Look for the field width (if any). Unlike printf, this is either
anatofuz
parents:
diff changeset
131 // a fixed integer or isn't present.
anatofuz
parents:
diff changeset
132 const OptionalAmount &Amt = clang::analyze_format_string::ParseAmount(I, E);
anatofuz
parents:
diff changeset
133 if (Amt.getHowSpecified() != OptionalAmount::NotSpecified) {
anatofuz
parents:
diff changeset
134 assert(Amt.getHowSpecified() == OptionalAmount::Constant);
anatofuz
parents:
diff changeset
135 FS.setFieldWidth(Amt);
anatofuz
parents:
diff changeset
136
anatofuz
parents:
diff changeset
137 if (I == E) {
anatofuz
parents:
diff changeset
138 // No more characters left?
anatofuz
parents:
diff changeset
139 H.HandleIncompleteSpecifier(Start, E - Start);
anatofuz
parents:
diff changeset
140 return true;
anatofuz
parents:
diff changeset
141 }
anatofuz
parents:
diff changeset
142 }
anatofuz
parents:
diff changeset
143
anatofuz
parents:
diff changeset
144 // Look for the length modifier.
anatofuz
parents:
diff changeset
145 if (ParseLengthModifier(FS, I, E, LO, /*IsScanf=*/true) && I == E) {
anatofuz
parents:
diff changeset
146 // No more characters left?
anatofuz
parents:
diff changeset
147 H.HandleIncompleteSpecifier(Start, E - Start);
anatofuz
parents:
diff changeset
148 return true;
anatofuz
parents:
diff changeset
149 }
anatofuz
parents:
diff changeset
150
anatofuz
parents:
diff changeset
151 // Detect spurious null characters, which are likely errors.
anatofuz
parents:
diff changeset
152 if (*I == '\0') {
anatofuz
parents:
diff changeset
153 H.HandleNullChar(I);
anatofuz
parents:
diff changeset
154 return true;
anatofuz
parents:
diff changeset
155 }
anatofuz
parents:
diff changeset
156
anatofuz
parents:
diff changeset
157 // Finally, look for the conversion specifier.
anatofuz
parents:
diff changeset
158 const char *conversionPosition = I++;
anatofuz
parents:
diff changeset
159 ScanfConversionSpecifier::Kind k = ScanfConversionSpecifier::InvalidSpecifier;
anatofuz
parents:
diff changeset
160 switch (*conversionPosition) {
anatofuz
parents:
diff changeset
161 default:
anatofuz
parents:
diff changeset
162 break;
anatofuz
parents:
diff changeset
163 case '%': k = ConversionSpecifier::PercentArg; break;
anatofuz
parents:
diff changeset
164 case 'A': k = ConversionSpecifier::AArg; break;
anatofuz
parents:
diff changeset
165 case 'E': k = ConversionSpecifier::EArg; break;
anatofuz
parents:
diff changeset
166 case 'F': k = ConversionSpecifier::FArg; break;
anatofuz
parents:
diff changeset
167 case 'G': k = ConversionSpecifier::GArg; break;
anatofuz
parents:
diff changeset
168 case 'X': k = ConversionSpecifier::XArg; break;
anatofuz
parents:
diff changeset
169 case 'a': k = ConversionSpecifier::aArg; break;
anatofuz
parents:
diff changeset
170 case 'd': k = ConversionSpecifier::dArg; break;
anatofuz
parents:
diff changeset
171 case 'e': k = ConversionSpecifier::eArg; break;
anatofuz
parents:
diff changeset
172 case 'f': k = ConversionSpecifier::fArg; break;
anatofuz
parents:
diff changeset
173 case 'g': k = ConversionSpecifier::gArg; break;
anatofuz
parents:
diff changeset
174 case 'i': k = ConversionSpecifier::iArg; break;
anatofuz
parents:
diff changeset
175 case 'n': k = ConversionSpecifier::nArg; break;
anatofuz
parents:
diff changeset
176 case 'c': k = ConversionSpecifier::cArg; break;
anatofuz
parents:
diff changeset
177 case 'C': k = ConversionSpecifier::CArg; break;
anatofuz
parents:
diff changeset
178 case 'S': k = ConversionSpecifier::SArg; break;
anatofuz
parents:
diff changeset
179 case '[': k = ConversionSpecifier::ScanListArg; break;
anatofuz
parents:
diff changeset
180 case 'u': k = ConversionSpecifier::uArg; break;
anatofuz
parents:
diff changeset
181 case 'x': k = ConversionSpecifier::xArg; break;
anatofuz
parents:
diff changeset
182 case 'o': k = ConversionSpecifier::oArg; break;
anatofuz
parents:
diff changeset
183 case 's': k = ConversionSpecifier::sArg; break;
anatofuz
parents:
diff changeset
184 case 'p': k = ConversionSpecifier::pArg; break;
anatofuz
parents:
diff changeset
185 // Apple extensions
anatofuz
parents:
diff changeset
186 // Apple-specific
anatofuz
parents:
diff changeset
187 case 'D':
anatofuz
parents:
diff changeset
188 if (Target.getTriple().isOSDarwin())
anatofuz
parents:
diff changeset
189 k = ConversionSpecifier::DArg;
anatofuz
parents:
diff changeset
190 break;
anatofuz
parents:
diff changeset
191 case 'O':
anatofuz
parents:
diff changeset
192 if (Target.getTriple().isOSDarwin())
anatofuz
parents:
diff changeset
193 k = ConversionSpecifier::OArg;
anatofuz
parents:
diff changeset
194 break;
anatofuz
parents:
diff changeset
195 case 'U':
anatofuz
parents:
diff changeset
196 if (Target.getTriple().isOSDarwin())
anatofuz
parents:
diff changeset
197 k = ConversionSpecifier::UArg;
anatofuz
parents:
diff changeset
198 break;
anatofuz
parents:
diff changeset
199 }
anatofuz
parents:
diff changeset
200 ScanfConversionSpecifier CS(conversionPosition, k);
anatofuz
parents:
diff changeset
201 if (k == ScanfConversionSpecifier::ScanListArg) {
anatofuz
parents:
diff changeset
202 if (ParseScanList(H, CS, I, E))
anatofuz
parents:
diff changeset
203 return true;
anatofuz
parents:
diff changeset
204 }
anatofuz
parents:
diff changeset
205 FS.setConversionSpecifier(CS);
anatofuz
parents:
diff changeset
206 if (CS.consumesDataArgument() && !FS.getSuppressAssignment()
anatofuz
parents:
diff changeset
207 && !FS.usesPositionalArg())
anatofuz
parents:
diff changeset
208 FS.setArgIndex(argIndex++);
anatofuz
parents:
diff changeset
209
anatofuz
parents:
diff changeset
210 // FIXME: '%' and '*' doesn't make sense. Issue a warning.
anatofuz
parents:
diff changeset
211 // FIXME: 'ConsumedSoFar' and '*' doesn't make sense.
anatofuz
parents:
diff changeset
212
anatofuz
parents:
diff changeset
213 if (k == ScanfConversionSpecifier::InvalidSpecifier) {
anatofuz
parents:
diff changeset
214 unsigned Len = I - Beg;
anatofuz
parents:
diff changeset
215 if (ParseUTF8InvalidSpecifier(Beg, E, Len)) {
anatofuz
parents:
diff changeset
216 CS.setEndScanList(Beg + Len);
anatofuz
parents:
diff changeset
217 FS.setConversionSpecifier(CS);
anatofuz
parents:
diff changeset
218 }
anatofuz
parents:
diff changeset
219 // Assume the conversion takes one argument.
anatofuz
parents:
diff changeset
220 return !H.HandleInvalidScanfConversionSpecifier(FS, Beg, Len);
anatofuz
parents:
diff changeset
221 }
anatofuz
parents:
diff changeset
222 return ScanfSpecifierResult(Start, FS);
anatofuz
parents:
diff changeset
223 }
anatofuz
parents:
diff changeset
224
anatofuz
parents:
diff changeset
225 ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
anatofuz
parents:
diff changeset
226 const ScanfConversionSpecifier &CS = getConversionSpecifier();
anatofuz
parents:
diff changeset
227
anatofuz
parents:
diff changeset
228 if (!CS.consumesDataArgument())
anatofuz
parents:
diff changeset
229 return ArgType::Invalid();
anatofuz
parents:
diff changeset
230
anatofuz
parents:
diff changeset
231 switch(CS.getKind()) {
anatofuz
parents:
diff changeset
232 // Signed int.
anatofuz
parents:
diff changeset
233 case ConversionSpecifier::dArg:
anatofuz
parents:
diff changeset
234 case ConversionSpecifier::DArg:
anatofuz
parents:
diff changeset
235 case ConversionSpecifier::iArg:
anatofuz
parents:
diff changeset
236 switch (LM.getKind()) {
anatofuz
parents:
diff changeset
237 case LengthModifier::None:
anatofuz
parents:
diff changeset
238 return ArgType::PtrTo(Ctx.IntTy);
anatofuz
parents:
diff changeset
239 case LengthModifier::AsChar:
anatofuz
parents:
diff changeset
240 return ArgType::PtrTo(ArgType::AnyCharTy);
anatofuz
parents:
diff changeset
241 case LengthModifier::AsShort:
anatofuz
parents:
diff changeset
242 return ArgType::PtrTo(Ctx.ShortTy);
anatofuz
parents:
diff changeset
243 case LengthModifier::AsLong:
anatofuz
parents:
diff changeset
244 return ArgType::PtrTo(Ctx.LongTy);
anatofuz
parents:
diff changeset
245 case LengthModifier::AsLongLong:
anatofuz
parents:
diff changeset
246 case LengthModifier::AsQuad:
anatofuz
parents:
diff changeset
247 return ArgType::PtrTo(Ctx.LongLongTy);
anatofuz
parents:
diff changeset
248 case LengthModifier::AsInt64:
anatofuz
parents:
diff changeset
249 return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));
anatofuz
parents:
diff changeset
250 case LengthModifier::AsIntMax:
anatofuz
parents:
diff changeset
251 return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
anatofuz
parents:
diff changeset
252 case LengthModifier::AsSizeT:
anatofuz
parents:
diff changeset
253 return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
anatofuz
parents:
diff changeset
254 case LengthModifier::AsPtrDiff:
anatofuz
parents:
diff changeset
255 return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
anatofuz
parents:
diff changeset
256 case LengthModifier::AsLongDouble:
anatofuz
parents:
diff changeset
257 // GNU extension.
anatofuz
parents:
diff changeset
258 return ArgType::PtrTo(Ctx.LongLongTy);
anatofuz
parents:
diff changeset
259 case LengthModifier::AsAllocate:
anatofuz
parents:
diff changeset
260 case LengthModifier::AsMAllocate:
anatofuz
parents:
diff changeset
261 case LengthModifier::AsInt32:
anatofuz
parents:
diff changeset
262 case LengthModifier::AsInt3264:
anatofuz
parents:
diff changeset
263 case LengthModifier::AsWide:
anatofuz
parents:
diff changeset
264 case LengthModifier::AsShortLong:
anatofuz
parents:
diff changeset
265 return ArgType::Invalid();
anatofuz
parents:
diff changeset
266 }
anatofuz
parents:
diff changeset
267 llvm_unreachable("Unsupported LengthModifier Type");
anatofuz
parents:
diff changeset
268
anatofuz
parents:
diff changeset
269 // Unsigned int.
anatofuz
parents:
diff changeset
270 case ConversionSpecifier::oArg:
anatofuz
parents:
diff changeset
271 case ConversionSpecifier::OArg:
anatofuz
parents:
diff changeset
272 case ConversionSpecifier::uArg:
anatofuz
parents:
diff changeset
273 case ConversionSpecifier::UArg:
anatofuz
parents:
diff changeset
274 case ConversionSpecifier::xArg:
anatofuz
parents:
diff changeset
275 case ConversionSpecifier::XArg:
anatofuz
parents:
diff changeset
276 switch (LM.getKind()) {
anatofuz
parents:
diff changeset
277 case LengthModifier::None:
anatofuz
parents:
diff changeset
278 return ArgType::PtrTo(Ctx.UnsignedIntTy);
anatofuz
parents:
diff changeset
279 case LengthModifier::AsChar:
anatofuz
parents:
diff changeset
280 return ArgType::PtrTo(Ctx.UnsignedCharTy);
anatofuz
parents:
diff changeset
281 case LengthModifier::AsShort:
anatofuz
parents:
diff changeset
282 return ArgType::PtrTo(Ctx.UnsignedShortTy);
anatofuz
parents:
diff changeset
283 case LengthModifier::AsLong:
anatofuz
parents:
diff changeset
284 return ArgType::PtrTo(Ctx.UnsignedLongTy);
anatofuz
parents:
diff changeset
285 case LengthModifier::AsLongLong:
anatofuz
parents:
diff changeset
286 case LengthModifier::AsQuad:
anatofuz
parents:
diff changeset
287 return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
anatofuz
parents:
diff changeset
288 case LengthModifier::AsInt64:
anatofuz
parents:
diff changeset
289 return ArgType::PtrTo(ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64"));
anatofuz
parents:
diff changeset
290 case LengthModifier::AsIntMax:
anatofuz
parents:
diff changeset
291 return ArgType::PtrTo(ArgType(Ctx.getUIntMaxType(), "uintmax_t"));
anatofuz
parents:
diff changeset
292 case LengthModifier::AsSizeT:
anatofuz
parents:
diff changeset
293 return ArgType::PtrTo(ArgType(Ctx.getSizeType(), "size_t"));
anatofuz
parents:
diff changeset
294 case LengthModifier::AsPtrDiff:
anatofuz
parents:
diff changeset
295 return ArgType::PtrTo(
anatofuz
parents:
diff changeset
296 ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));
anatofuz
parents:
diff changeset
297 case LengthModifier::AsLongDouble:
anatofuz
parents:
diff changeset
298 // GNU extension.
anatofuz
parents:
diff changeset
299 return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
anatofuz
parents:
diff changeset
300 case LengthModifier::AsAllocate:
anatofuz
parents:
diff changeset
301 case LengthModifier::AsMAllocate:
anatofuz
parents:
diff changeset
302 case LengthModifier::AsInt32:
anatofuz
parents:
diff changeset
303 case LengthModifier::AsInt3264:
anatofuz
parents:
diff changeset
304 case LengthModifier::AsWide:
anatofuz
parents:
diff changeset
305 case LengthModifier::AsShortLong:
anatofuz
parents:
diff changeset
306 return ArgType::Invalid();
anatofuz
parents:
diff changeset
307 }
anatofuz
parents:
diff changeset
308 llvm_unreachable("Unsupported LengthModifier Type");
anatofuz
parents:
diff changeset
309
anatofuz
parents:
diff changeset
310 // Float.
anatofuz
parents:
diff changeset
311 case ConversionSpecifier::aArg:
anatofuz
parents:
diff changeset
312 case ConversionSpecifier::AArg:
anatofuz
parents:
diff changeset
313 case ConversionSpecifier::eArg:
anatofuz
parents:
diff changeset
314 case ConversionSpecifier::EArg:
anatofuz
parents:
diff changeset
315 case ConversionSpecifier::fArg:
anatofuz
parents:
diff changeset
316 case ConversionSpecifier::FArg:
anatofuz
parents:
diff changeset
317 case ConversionSpecifier::gArg:
anatofuz
parents:
diff changeset
318 case ConversionSpecifier::GArg:
anatofuz
parents:
diff changeset
319 switch (LM.getKind()) {
anatofuz
parents:
diff changeset
320 case LengthModifier::None:
anatofuz
parents:
diff changeset
321 return ArgType::PtrTo(Ctx.FloatTy);
anatofuz
parents:
diff changeset
322 case LengthModifier::AsLong:
anatofuz
parents:
diff changeset
323 return ArgType::PtrTo(Ctx.DoubleTy);
anatofuz
parents:
diff changeset
324 case LengthModifier::AsLongDouble:
anatofuz
parents:
diff changeset
325 return ArgType::PtrTo(Ctx.LongDoubleTy);
anatofuz
parents:
diff changeset
326 default:
anatofuz
parents:
diff changeset
327 return ArgType::Invalid();
anatofuz
parents:
diff changeset
328 }
anatofuz
parents:
diff changeset
329
anatofuz
parents:
diff changeset
330 // Char, string and scanlist.
anatofuz
parents:
diff changeset
331 case ConversionSpecifier::cArg:
anatofuz
parents:
diff changeset
332 case ConversionSpecifier::sArg:
anatofuz
parents:
diff changeset
333 case ConversionSpecifier::ScanListArg:
anatofuz
parents:
diff changeset
334 switch (LM.getKind()) {
anatofuz
parents:
diff changeset
335 case LengthModifier::None:
anatofuz
parents:
diff changeset
336 return ArgType::PtrTo(ArgType::AnyCharTy);
anatofuz
parents:
diff changeset
337 case LengthModifier::AsLong:
anatofuz
parents:
diff changeset
338 case LengthModifier::AsWide:
anatofuz
parents:
diff changeset
339 return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));
anatofuz
parents:
diff changeset
340 case LengthModifier::AsAllocate:
anatofuz
parents:
diff changeset
341 case LengthModifier::AsMAllocate:
anatofuz
parents:
diff changeset
342 return ArgType::PtrTo(ArgType::CStrTy);
anatofuz
parents:
diff changeset
343 case LengthModifier::AsShort:
anatofuz
parents:
diff changeset
344 if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
anatofuz
parents:
diff changeset
345 return ArgType::PtrTo(ArgType::AnyCharTy);
anatofuz
parents:
diff changeset
346 LLVM_FALLTHROUGH;
anatofuz
parents:
diff changeset
347 default:
anatofuz
parents:
diff changeset
348 return ArgType::Invalid();
anatofuz
parents:
diff changeset
349 }
anatofuz
parents:
diff changeset
350 case ConversionSpecifier::CArg:
anatofuz
parents:
diff changeset
351 case ConversionSpecifier::SArg:
anatofuz
parents:
diff changeset
352 // FIXME: Mac OS X specific?
anatofuz
parents:
diff changeset
353 switch (LM.getKind()) {
anatofuz
parents:
diff changeset
354 case LengthModifier::None:
anatofuz
parents:
diff changeset
355 case LengthModifier::AsWide:
anatofuz
parents:
diff changeset
356 return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));
anatofuz
parents:
diff changeset
357 case LengthModifier::AsAllocate:
anatofuz
parents:
diff changeset
358 case LengthModifier::AsMAllocate:
anatofuz
parents:
diff changeset
359 return ArgType::PtrTo(ArgType(ArgType::WCStrTy, "wchar_t *"));
anatofuz
parents:
diff changeset
360 case LengthModifier::AsShort:
anatofuz
parents:
diff changeset
361 if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
anatofuz
parents:
diff changeset
362 return ArgType::PtrTo(ArgType::AnyCharTy);
anatofuz
parents:
diff changeset
363 LLVM_FALLTHROUGH;
anatofuz
parents:
diff changeset
364 default:
anatofuz
parents:
diff changeset
365 return ArgType::Invalid();
anatofuz
parents:
diff changeset
366 }
anatofuz
parents:
diff changeset
367
anatofuz
parents:
diff changeset
368 // Pointer.
anatofuz
parents:
diff changeset
369 case ConversionSpecifier::pArg:
anatofuz
parents:
diff changeset
370 return ArgType::PtrTo(ArgType::CPointerTy);
anatofuz
parents:
diff changeset
371
anatofuz
parents:
diff changeset
372 // Write-back.
anatofuz
parents:
diff changeset
373 case ConversionSpecifier::nArg:
anatofuz
parents:
diff changeset
374 switch (LM.getKind()) {
anatofuz
parents:
diff changeset
375 case LengthModifier::None:
anatofuz
parents:
diff changeset
376 return ArgType::PtrTo(Ctx.IntTy);
anatofuz
parents:
diff changeset
377 case LengthModifier::AsChar:
anatofuz
parents:
diff changeset
378 return ArgType::PtrTo(Ctx.SignedCharTy);
anatofuz
parents:
diff changeset
379 case LengthModifier::AsShort:
anatofuz
parents:
diff changeset
380 return ArgType::PtrTo(Ctx.ShortTy);
anatofuz
parents:
diff changeset
381 case LengthModifier::AsLong:
anatofuz
parents:
diff changeset
382 return ArgType::PtrTo(Ctx.LongTy);
anatofuz
parents:
diff changeset
383 case LengthModifier::AsLongLong:
anatofuz
parents:
diff changeset
384 case LengthModifier::AsQuad:
anatofuz
parents:
diff changeset
385 return ArgType::PtrTo(Ctx.LongLongTy);
anatofuz
parents:
diff changeset
386 case LengthModifier::AsInt64:
anatofuz
parents:
diff changeset
387 return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));
anatofuz
parents:
diff changeset
388 case LengthModifier::AsIntMax:
anatofuz
parents:
diff changeset
389 return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
anatofuz
parents:
diff changeset
390 case LengthModifier::AsSizeT:
anatofuz
parents:
diff changeset
391 return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
anatofuz
parents:
diff changeset
392 case LengthModifier::AsPtrDiff:
anatofuz
parents:
diff changeset
393 return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
anatofuz
parents:
diff changeset
394 case LengthModifier::AsLongDouble:
anatofuz
parents:
diff changeset
395 return ArgType(); // FIXME: Is this a known extension?
anatofuz
parents:
diff changeset
396 case LengthModifier::AsAllocate:
anatofuz
parents:
diff changeset
397 case LengthModifier::AsMAllocate:
anatofuz
parents:
diff changeset
398 case LengthModifier::AsInt32:
anatofuz
parents:
diff changeset
399 case LengthModifier::AsInt3264:
anatofuz
parents:
diff changeset
400 case LengthModifier::AsWide:
anatofuz
parents:
diff changeset
401 case LengthModifier::AsShortLong:
anatofuz
parents:
diff changeset
402 return ArgType::Invalid();
anatofuz
parents:
diff changeset
403 }
anatofuz
parents:
diff changeset
404
anatofuz
parents:
diff changeset
405 default:
anatofuz
parents:
diff changeset
406 break;
anatofuz
parents:
diff changeset
407 }
anatofuz
parents:
diff changeset
408
anatofuz
parents:
diff changeset
409 return ArgType();
anatofuz
parents:
diff changeset
410 }
anatofuz
parents:
diff changeset
411
anatofuz
parents:
diff changeset
412 bool ScanfSpecifier::fixType(QualType QT, QualType RawQT,
anatofuz
parents:
diff changeset
413 const LangOptions &LangOpt,
anatofuz
parents:
diff changeset
414 ASTContext &Ctx) {
anatofuz
parents:
diff changeset
415
anatofuz
parents:
diff changeset
416 // %n is different from other conversion specifiers; don't try to fix it.
anatofuz
parents:
diff changeset
417 if (CS.getKind() == ConversionSpecifier::nArg)
anatofuz
parents:
diff changeset
418 return false;
anatofuz
parents:
diff changeset
419
anatofuz
parents:
diff changeset
420 if (!QT->isPointerType())
anatofuz
parents:
diff changeset
421 return false;
anatofuz
parents:
diff changeset
422
anatofuz
parents:
diff changeset
423 QualType PT = QT->getPointeeType();
anatofuz
parents:
diff changeset
424
anatofuz
parents:
diff changeset
425 // If it's an enum, get its underlying type.
anatofuz
parents:
diff changeset
426 if (const EnumType *ETy = PT->getAs<EnumType>()) {
anatofuz
parents:
diff changeset
427 // Don't try to fix incomplete enums.
anatofuz
parents:
diff changeset
428 if (!ETy->getDecl()->isComplete())
anatofuz
parents:
diff changeset
429 return false;
anatofuz
parents:
diff changeset
430 PT = ETy->getDecl()->getIntegerType();
anatofuz
parents:
diff changeset
431 }
anatofuz
parents:
diff changeset
432
anatofuz
parents:
diff changeset
433 const BuiltinType *BT = PT->getAs<BuiltinType>();
anatofuz
parents:
diff changeset
434 if (!BT)
anatofuz
parents:
diff changeset
435 return false;
anatofuz
parents:
diff changeset
436
anatofuz
parents:
diff changeset
437 // Pointer to a character.
anatofuz
parents:
diff changeset
438 if (PT->isAnyCharacterType()) {
anatofuz
parents:
diff changeset
439 CS.setKind(ConversionSpecifier::sArg);
anatofuz
parents:
diff changeset
440 if (PT->isWideCharType())
anatofuz
parents:
diff changeset
441 LM.setKind(LengthModifier::AsWideChar);
anatofuz
parents:
diff changeset
442 else
anatofuz
parents:
diff changeset
443 LM.setKind(LengthModifier::None);
anatofuz
parents:
diff changeset
444
anatofuz
parents:
diff changeset
445 // If we know the target array length, we can use it as a field width.
anatofuz
parents:
diff changeset
446 if (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(RawQT)) {
anatofuz
parents:
diff changeset
447 if (CAT->getSizeModifier() == ArrayType::Normal)
anatofuz
parents:
diff changeset
448 FieldWidth = OptionalAmount(OptionalAmount::Constant,
anatofuz
parents:
diff changeset
449 CAT->getSize().getZExtValue() - 1,
anatofuz
parents:
diff changeset
450 "", 0, false);
anatofuz
parents:
diff changeset
451
anatofuz
parents:
diff changeset
452 }
anatofuz
parents:
diff changeset
453 return true;
anatofuz
parents:
diff changeset
454 }
anatofuz
parents:
diff changeset
455
anatofuz
parents:
diff changeset
456 // Figure out the length modifier.
anatofuz
parents:
diff changeset
457 switch (BT->getKind()) {
anatofuz
parents:
diff changeset
458 // no modifier
anatofuz
parents:
diff changeset
459 case BuiltinType::UInt:
anatofuz
parents:
diff changeset
460 case BuiltinType::Int:
anatofuz
parents:
diff changeset
461 case BuiltinType::Float:
anatofuz
parents:
diff changeset
462 LM.setKind(LengthModifier::None);
anatofuz
parents:
diff changeset
463 break;
anatofuz
parents:
diff changeset
464
anatofuz
parents:
diff changeset
465 // hh
anatofuz
parents:
diff changeset
466 case BuiltinType::Char_U:
anatofuz
parents:
diff changeset
467 case BuiltinType::UChar:
anatofuz
parents:
diff changeset
468 case BuiltinType::Char_S:
anatofuz
parents:
diff changeset
469 case BuiltinType::SChar:
anatofuz
parents:
diff changeset
470 LM.setKind(LengthModifier::AsChar);
anatofuz
parents:
diff changeset
471 break;
anatofuz
parents:
diff changeset
472
anatofuz
parents:
diff changeset
473 // h
anatofuz
parents:
diff changeset
474 case BuiltinType::Short:
anatofuz
parents:
diff changeset
475 case BuiltinType::UShort:
anatofuz
parents:
diff changeset
476 LM.setKind(LengthModifier::AsShort);
anatofuz
parents:
diff changeset
477 break;
anatofuz
parents:
diff changeset
478
anatofuz
parents:
diff changeset
479 // l
anatofuz
parents:
diff changeset
480 case BuiltinType::Long:
anatofuz
parents:
diff changeset
481 case BuiltinType::ULong:
anatofuz
parents:
diff changeset
482 case BuiltinType::Double:
anatofuz
parents:
diff changeset
483 LM.setKind(LengthModifier::AsLong);
anatofuz
parents:
diff changeset
484 break;
anatofuz
parents:
diff changeset
485
anatofuz
parents:
diff changeset
486 // ll
anatofuz
parents:
diff changeset
487 case BuiltinType::LongLong:
anatofuz
parents:
diff changeset
488 case BuiltinType::ULongLong:
anatofuz
parents:
diff changeset
489 LM.setKind(LengthModifier::AsLongLong);
anatofuz
parents:
diff changeset
490 break;
anatofuz
parents:
diff changeset
491
anatofuz
parents:
diff changeset
492 // L
anatofuz
parents:
diff changeset
493 case BuiltinType::LongDouble:
anatofuz
parents:
diff changeset
494 LM.setKind(LengthModifier::AsLongDouble);
anatofuz
parents:
diff changeset
495 break;
anatofuz
parents:
diff changeset
496
anatofuz
parents:
diff changeset
497 // Don't know.
anatofuz
parents:
diff changeset
498 default:
anatofuz
parents:
diff changeset
499 return false;
anatofuz
parents:
diff changeset
500 }
anatofuz
parents:
diff changeset
501
anatofuz
parents:
diff changeset
502 // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
anatofuz
parents:
diff changeset
503 if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
anatofuz
parents:
diff changeset
504 namedTypeToLengthModifier(PT, LM);
anatofuz
parents:
diff changeset
505
anatofuz
parents:
diff changeset
506 // If fixing the length modifier was enough, we are done.
anatofuz
parents:
diff changeset
507 if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) {
anatofuz
parents:
diff changeset
508 const analyze_scanf::ArgType &AT = getArgType(Ctx);
anatofuz
parents:
diff changeset
509 if (AT.isValid() && AT.matchesType(Ctx, QT))
anatofuz
parents:
diff changeset
510 return true;
anatofuz
parents:
diff changeset
511 }
anatofuz
parents:
diff changeset
512
anatofuz
parents:
diff changeset
513 // Figure out the conversion specifier.
anatofuz
parents:
diff changeset
514 if (PT->isRealFloatingType())
anatofuz
parents:
diff changeset
515 CS.setKind(ConversionSpecifier::fArg);
anatofuz
parents:
diff changeset
516 else if (PT->isSignedIntegerType())
anatofuz
parents:
diff changeset
517 CS.setKind(ConversionSpecifier::dArg);
anatofuz
parents:
diff changeset
518 else if (PT->isUnsignedIntegerType())
anatofuz
parents:
diff changeset
519 CS.setKind(ConversionSpecifier::uArg);
anatofuz
parents:
diff changeset
520 else
anatofuz
parents:
diff changeset
521 llvm_unreachable("Unexpected type");
anatofuz
parents:
diff changeset
522
anatofuz
parents:
diff changeset
523 return true;
anatofuz
parents:
diff changeset
524 }
anatofuz
parents:
diff changeset
525
anatofuz
parents:
diff changeset
526 void ScanfSpecifier::toString(raw_ostream &os) const {
anatofuz
parents:
diff changeset
527 os << "%";
anatofuz
parents:
diff changeset
528
anatofuz
parents:
diff changeset
529 if (usesPositionalArg())
anatofuz
parents:
diff changeset
530 os << getPositionalArgIndex() << "$";
anatofuz
parents:
diff changeset
531 if (SuppressAssignment)
anatofuz
parents:
diff changeset
532 os << "*";
anatofuz
parents:
diff changeset
533
anatofuz
parents:
diff changeset
534 FieldWidth.toString(os);
anatofuz
parents:
diff changeset
535 os << LM.toString();
anatofuz
parents:
diff changeset
536 os << CS.toString();
anatofuz
parents:
diff changeset
537 }
anatofuz
parents:
diff changeset
538
anatofuz
parents:
diff changeset
539 bool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H,
anatofuz
parents:
diff changeset
540 const char *I,
anatofuz
parents:
diff changeset
541 const char *E,
anatofuz
parents:
diff changeset
542 const LangOptions &LO,
anatofuz
parents:
diff changeset
543 const TargetInfo &Target) {
anatofuz
parents:
diff changeset
544
anatofuz
parents:
diff changeset
545 unsigned argIndex = 0;
anatofuz
parents:
diff changeset
546
anatofuz
parents:
diff changeset
547 // Keep looking for a format specifier until we have exhausted the string.
anatofuz
parents:
diff changeset
548 while (I != E) {
anatofuz
parents:
diff changeset
549 const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E, argIndex,
anatofuz
parents:
diff changeset
550 LO, Target);
anatofuz
parents:
diff changeset
551 // Did a fail-stop error of any kind occur when parsing the specifier?
anatofuz
parents:
diff changeset
552 // If so, don't do any more processing.
anatofuz
parents:
diff changeset
553 if (FSR.shouldStop())
anatofuz
parents:
diff changeset
554 return true;
anatofuz
parents:
diff changeset
555 // Did we exhaust the string or encounter an error that
anatofuz
parents:
diff changeset
556 // we can recover from?
anatofuz
parents:
diff changeset
557 if (!FSR.hasValue())
anatofuz
parents:
diff changeset
558 continue;
anatofuz
parents:
diff changeset
559 // We have a format specifier. Pass it to the callback.
anatofuz
parents:
diff changeset
560 if (!H.HandleScanfSpecifier(FSR.getValue(), FSR.getStart(),
anatofuz
parents:
diff changeset
561 I - FSR.getStart())) {
anatofuz
parents:
diff changeset
562 return true;
anatofuz
parents:
diff changeset
563 }
anatofuz
parents:
diff changeset
564 }
anatofuz
parents:
diff changeset
565 assert(I == E && "Format string not exhausted");
anatofuz
parents:
diff changeset
566 return false;
anatofuz
parents:
diff changeset
567 }