 |
|
 |
|
| Files: |
1 |
|
Branches Taken: |
66.7% |
88 / 132 |
| Generated: |
2010-02-10 01:31 |
|
Branches Executed: |
97.0% |
128 / 132 |
| |
|
Line Coverage: |
79.4% |
135 / 170 |
| |
 |
|
 |
1 : //= PrintfFormatStrings.cpp - Analysis of printf format strings --*- C++ -*-==//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 : //
10 : // Handling of format string in printf and friends. The structure of format
11 : // strings for fprintf() are described in C99 7.19.6.1.
12 : //
13 : //===----------------------------------------------------------------------===//
14 :
15 : #include "clang/Analysis/Analyses/PrintfFormatString.h"
16 : #include "clang/AST/ASTContext.h"
17 :
18 : using clang::analyze_printf::FormatSpecifier;
19 : using clang::analyze_printf::OptionalAmount;
20 : using clang::analyze_printf::ArgTypeResult;
21 : using clang::analyze_printf::FormatStringHandler;
22 : using namespace clang;
23 :
24 : namespace {
25 : class FormatSpecifierResult {
26 : FormatSpecifier FS;
27 : const char *Start;
28 : bool Stop;
29 : public:
30 418: FormatSpecifierResult(bool stop = false)
31 418: : Start(0), Stop(stop) {}
32 : FormatSpecifierResult(const char *start,
33 544: const FormatSpecifier &fs)
34 544: : FS(fs), Start(start), Stop(false) {}
35 :
36 :
37 1088: const char *getStart() const { return Start; }
38 962: bool shouldStop() const { return Stop; }
39 1498: bool hasValue() const { return Start != 0; }
40 544: const FormatSpecifier &getValue() const {
0: branch 1 not taken
544: branch 2 taken
41 544: assert(hasValue());
42 544: return FS;
43 : }
44 : const FormatSpecifier &getValue() { return FS; }
45 : };
46 : } // end anonymous namespace
47 :
48 : template <typename T>
49 : class UpdateOnReturn {
50 : T &ValueToUpdate;
51 : const T &ValueToCopy;
52 : public:
53 1575: UpdateOnReturn(T &valueToUpdate, const T &valueToCopy)
54 1575: : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {}
55 :
56 1575: ~UpdateOnReturn() {
57 1575: ValueToUpdate = ValueToCopy;
58 1575: }
59 : };
60 :
61 613: static OptionalAmount ParseAmount(const char *&Beg, const char *E) {
62 613: const char *I = Beg;
63 613: UpdateOnReturn <const char*> UpdateBeg(Beg, I);
64 :
65 613: bool foundDigits = false;
66 613: unsigned accumulator = 0;
67 :
665: branch 0 taken
0: branch 1 not taken
68 1330: for ( ; I != E; ++I) {
69 665: char c = *I;
580: branch 0 taken
85: branch 1 taken
52: branch 2 taken
528: branch 3 taken
70 665: if (c >= '0' && c <= '9') {
71 52: foundDigits = true;
72 52: accumulator += (accumulator * 10) + (c - '0');
73 : continue;
74 : }
75 :
52: branch 0 taken
561: branch 1 taken
76 613: if (foundDigits)
77 52: return OptionalAmount(accumulator, Beg);
78 :
18: branch 0 taken
543: branch 1 taken
79 561: if (c == '*') {
80 18: ++I;
81 18: return OptionalAmount(OptionalAmount::Arg, Beg);
82 : }
83 :
84 543: break;
85 : }
86 :
87 543: return OptionalAmount();
88 : }
89 :
90 : static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
91 : const char *&Beg,
92 962: const char *E) {
93 :
94 : using namespace clang::analyze_printf;
95 :
96 962: const char *I = Beg;
97 962: const char *Start = 0;
98 962: UpdateOnReturn <const char*> UpdateBeg(Beg, I);
99 :
100 : // Look for a '%' character that indicates the start of a format specifier.
5108: branch 0 taken
403: branch 1 taken
101 5511: for ( ; I != E ; ++I) {
102 5108: char c = *I;
4: branch 0 taken
5104: branch 1 taken
103 5108: if (c == '\0') {
104 : // Detect spurious null characters, which are likely errors.
105 4: H.HandleNullChar(I);
106 4: return true;
107 : }
555: branch 0 taken
4549: branch 1 taken
108 5104: if (c == '%') {
109 555: Start = I++; // Record the start of the format specifier.
110 555: break;
111 : }
112 : }
113 :
114 : // No format specifier found?
403: branch 0 taken
555: branch 1 taken
115 958: if (!Start)
116 403: return false;
117 :
1: branch 0 taken
554: branch 1 taken
118 555: if (I == E) {
119 : // No more characters left?
120 1: H.HandleIncompleteFormatSpecifier(Start, E - Start);
121 1: return true;
122 : }
123 :
124 554: FormatSpecifier FS;
125 :
126 : // Look for flags (if any).
127 554: bool hasMore = true;
554: branch 0 taken
0: branch 1 not taken
128 554: for ( ; I != E; ++I) {
554: branch 0 taken
0: branch 1 not taken
0: branch 2 not taken
0: branch 3 not taken
0: branch 4 not taken
0: branch 5 not taken
129 554: switch (*I) {
130 554: default: hasMore = false; break;
131 0: case '-': FS.setIsLeftJustified(); break;
132 0: case '+': FS.setHasPlusPrefix(); break;
133 0: case ' ': FS.setHasSpacePrefix(); break;
134 0: case '#': FS.setHasAlternativeForm(); break;
135 0: case '0': FS.setHasLeadingZeros(); break;
136 : }
554: branch 0 taken
0: branch 1 not taken
137 554: if (!hasMore)
138 554: break;
139 : }
140 :
0: branch 0 not taken
554: branch 1 taken
141 554: if (I == E) {
142 : // No more characters left?
143 0: H.HandleIncompleteFormatSpecifier(Start, E - Start);
144 0: return true;
145 : }
146 :
147 : // Look for the field width (if any).
148 554: FS.setFieldWidth(ParseAmount(I, E));
149 :
0: branch 0 not taken
554: branch 1 taken
150 554: if (I == E) {
151 : // No more characters left?
152 0: H.HandleIncompleteFormatSpecifier(Start, E - Start);
153 0: return true;
154 : }
155 :
156 : // Look for the precision (if any).
60: branch 0 taken
494: branch 1 taken
157 554: if (*I == '.') {
158 60: ++I;
1: branch 0 taken
59: branch 1 taken
159 60: if (I == E) {
160 1: H.HandleIncompleteFormatSpecifier(Start, E - Start);
161 1: return true;
162 : }
163 :
164 59: FS.setPrecision(ParseAmount(I, E));
165 :
0: branch 0 not taken
59: branch 1 taken
166 59: if (I == E) {
167 : // No more characters left?
168 0: H.HandleIncompleteFormatSpecifier(Start, E - Start);
169 0: return true;
170 : }
171 : }
172 :
173 : // Look for the length modifier.
174 553: LengthModifier lm = None;
542: branch 0 taken
1: branch 1 taken
6: branch 2 taken
0: branch 3 not taken
2: branch 4 taken
0: branch 5 not taken
1: branch 6 taken
1: branch 7 taken
175 553: switch (*I) {
176 : default:
177 542: break;
178 : case 'h':
179 1: ++I;
1: branch 0 taken
0: branch 1 not taken
1: branch 2 taken
0: branch 3 not taken
180 1: lm = (I != E && *I == 'h') ? ++I, AsChar : AsShort;
181 1: break;
182 : case 'l':
183 6: ++I;
5: branch 0 taken
1: branch 1 taken
1: branch 2 taken
4: branch 3 taken
184 6: lm = (I != E && *I == 'l') ? ++I, AsLongLong : AsLong;
185 6: break;
186 0: case 'j': lm = AsIntMax; ++I; break;
187 2: case 'z': lm = AsSizeT; ++I; break;
188 0: case 't': lm = AsPtrDiff; ++I; break;
189 1: case 'L': lm = AsLongDouble; ++I; break;
190 1: case 'q': lm = AsLongLong; ++I; break;
191 : }
192 553: FS.setLengthModifier(lm);
193 :
1: branch 0 taken
552: branch 1 taken
194 553: if (I == E) {
195 : // No more characters left?
196 1: H.HandleIncompleteFormatSpecifier(Start, E - Start);
197 1: return true;
198 : }
199 :
1: branch 0 taken
551: branch 1 taken
200 552: if (*I == '\0') {
201 : // Detect spurious null characters, which are likely errors.
202 1: H.HandleNullChar(I);
203 1: return true;
204 : }
205 :
206 : // Finally, look for the conversion specifier.
207 551: const char *conversionPosition = I++;
208 551: ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
7: branch 0 taken
298: branch 1 taken
2: branch 2 taken
0: branch 3 not taken
0: branch 4 not taken
6: branch 5 taken
2: branch 6 taken
130: branch 7 taken
0: branch 8 not taken
0: branch 9 not taken
0: branch 10 not taken
0: branch 11 not taken
0: branch 12 not taken
0: branch 13 not taken
0: branch 14 not taken
0: branch 15 not taken
72: branch 16 taken
4: branch 17 taken
4: branch 18 taken
9: branch 19 taken
15: branch 20 taken
2: branch 21 taken
209 551: switch (*conversionPosition) {
210 : default:
211 7: break;
212 : // C99: 7.19.6.1 (section 8).
213 298: case 'd': k = ConversionSpecifier::dArg; break;
214 2: case 'i': k = ConversionSpecifier::iArg; break;
215 0: case 'o': k = ConversionSpecifier::oArg; break;
216 0: case 'u': k = ConversionSpecifier::uArg; break;
217 6: case 'x': k = ConversionSpecifier::xArg; break;
218 2: case 'X': k = ConversionSpecifier::XArg; break;
219 130: case 'f': k = ConversionSpecifier::fArg; break;
220 0: case 'F': k = ConversionSpecifier::FArg; break;
221 0: case 'e': k = ConversionSpecifier::eArg; break;
222 0: case 'E': k = ConversionSpecifier::EArg; break;
223 0: case 'g': k = ConversionSpecifier::gArg; break;
224 0: case 'G': k = ConversionSpecifier::GArg; break;
225 0: case 'a': k = ConversionSpecifier::aArg; break;
226 0: case 'A': k = ConversionSpecifier::AArg; break;
227 0: case 'c': k = ConversionSpecifier::IntAsCharArg; break;
228 72: case 's': k = ConversionSpecifier::CStrArg; break;
229 4: case 'p': k = ConversionSpecifier::VoidPtrArg; break;
230 4: case 'n': k = ConversionSpecifier::OutIntPtrArg; break;
231 9: case '%': k = ConversionSpecifier::PercentArg; break;
232 : // Objective-C.
233 15: case '@': k = ConversionSpecifier::ObjCObjArg; break;
234 : // Glibc specific.
235 2: case 'm': k = ConversionSpecifier::PrintErrno; break;
236 : }
237 551: FS.setConversionSpecifier(ConversionSpecifier(conversionPosition, k));
238 :
7: branch 0 taken
544: branch 1 taken
239 551: if (k == ConversionSpecifier::InvalidSpecifier) {
240 7: H.HandleInvalidConversionSpecifier(FS, Beg, I - Beg);
241 7: return false; // Keep processing format specifiers.
242 : }
243 544: return FormatSpecifierResult(Start, FS);
244 : }
245 :
246 : bool clang::analyze_printf::ParseFormatString(FormatStringHandler &H,
247 473: const char *I, const char *E) {
248 : // Keep looking for a format specifier until we have exhausted the string.
962: branch 0 taken
454: branch 1 taken
249 1889: while (I != E) {
250 962: const FormatSpecifierResult &FSR = ParseFormatSpecifier(H, I, E);
251 : // Did a fail-stop error of any kind occur when parsing the specifier?
252 : // If so, don't do any more processing.
8: branch 1 taken
954: branch 2 taken
253 962: if (FSR.shouldStop())
254 8: return true;;
255 : // Did we exhaust the string or encounter an error that
256 : // we can recover from?
544: branch 1 taken
410: branch 2 taken
257 954: if (!FSR.hasValue())
258 410: continue;
259 : // We have a format specifier. Pass it to the callback.
11: branch 4 taken
533: branch 5 taken
260 544: if (!H.HandleFormatSpecifier(FSR.getValue(), FSR.getStart(),
261 : I - FSR.getStart()))
262 11: return true;
263 : }
0: branch 0 not taken
454: branch 1 taken
264 454: assert(I == E && "Format string not exhausted");
265 454: return false;
266 : }
267 :
473: branch 0 taken
473: branch 1 taken
0: branch 3 not taken
0: branch 4 not taken
0: branch 6 not taken
473: branch 7 taken
268 473: FormatStringHandler::~FormatStringHandler() {}
269 :
270 : //===----------------------------------------------------------------------===//
271 : // Methods on FormatSpecifier.
272 : //===----------------------------------------------------------------------===//
273 :
274 515: ArgTypeResult FormatSpecifier::getArgType(ASTContext &Ctx) const {
0: branch 1 not taken
515: branch 2 taken
275 515: if (!CS.consumesDataArgument())
276 0: return ArgTypeResult::Invalid();
277 :
288: branch 1 taken
227: branch 2 taken
278 515: if (CS.isIntArg())
0: branch 0 not taken
283: branch 1 taken
0: branch 2 not taken
0: branch 3 not taken
2: branch 4 taken
1: branch 5 taken
0: branch 6 not taken
2: branch 7 taken
0: branch 8 not taken
0: branch 9 not taken
279 288: switch (LM) {
280 : case AsLongDouble:
281 0: return ArgTypeResult::Invalid();
282 283: case None: return Ctx.IntTy;
283 0: case AsChar: return Ctx.SignedCharTy;
284 0: case AsShort: return Ctx.ShortTy;
285 2: case AsLong: return Ctx.LongTy;
286 1: case AsLongLong: return Ctx.LongLongTy;
287 : case AsIntMax:
288 : // FIXME: Return unknown for now.
289 0: return ArgTypeResult();
290 2: case AsSizeT: return Ctx.getSizeType();
291 0: case AsPtrDiff: return Ctx.getPointerDiffType();
292 : }
293 :
8: branch 1 taken
219: branch 2 taken
294 227: if (CS.isUIntArg())
0: branch 0 not taken
6: branch 1 taken
1: branch 2 taken
0: branch 3 not taken
0: branch 4 not taken
1: branch 5 taken
0: branch 6 not taken
0: branch 7 not taken
0: branch 8 not taken
0: branch 9 not taken
295 8: switch (LM) {
296 : case AsLongDouble:
297 0: return ArgTypeResult::Invalid();
298 6: case None: return Ctx.UnsignedIntTy;
299 1: case AsChar: return Ctx.UnsignedCharTy;
300 0: case AsShort: return Ctx.UnsignedShortTy;
301 0: case AsLong: return Ctx.UnsignedLongTy;
302 1: case AsLongLong: return Ctx.UnsignedLongLongTy;
303 : case AsIntMax:
304 : // FIXME: Return unknown for now.
305 0: return ArgTypeResult();
306 : case AsSizeT:
307 : // FIXME: How to get the corresponding unsigned
308 : // version of size_t?
309 0: return ArgTypeResult();
310 : case AsPtrDiff:
311 : // FIXME: How to get the corresponding unsigned
312 : // version of ptrdiff_t?
313 0: return ArgTypeResult();
314 : }
315 :
130: branch 1 taken
89: branch 2 taken
316 219: if (CS.isDoubleArg()) {
1: branch 0 taken
129: branch 1 taken
317 130: if (LM == AsLongDouble)
318 1: return Ctx.LongDoubleTy;
319 129: return Ctx.DoubleTy;
320 : }
321 :
322 : // FIXME: Handle other cases.
323 89: return ArgTypeResult();
324 : }
325 :
Generated: 2010-02-10 01:31 by zcov