1 //= ScanfFormatString.cpp - Analysis of printf format strings --*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // Handling of format string in scanf and friends. The structure of format
11 // strings for fscanf() are described in C99 7.19.6.2.
13 //===----------------------------------------------------------------------===//
15 #include "clang/Analysis/Analyses/FormatString.h"
16 #include "FormatStringParsing.h"
18 using clang::analyze_format_string::ArgTypeResult;
19 using clang::analyze_format_string::FormatStringHandler;
20 using clang::analyze_format_string::LengthModifier;
21 using clang::analyze_format_string::OptionalAmount;
22 using clang::analyze_format_string::ConversionSpecifier;
23 using clang::analyze_scanf::ScanfConversionSpecifier;
24 using clang::analyze_scanf::ScanfSpecifier;
25 using clang::UpdateOnReturn;
27 typedef clang::analyze_format_string::SpecifierResult<ScanfSpecifier>
30 static bool ParseScanList(FormatStringHandler &H,
31 ScanfConversionSpecifier &CS,
32 const char *&Beg, const char *E) {
34 const char *start = I - 1;
35 UpdateOnReturn <const char*> UpdateBeg(Beg, I);
37 // No more characters?
39 H.HandleIncompleteScanList(start, I);
43 // Special case: ']' is the first character.
46 H.HandleIncompleteScanList(start, I - 1);
51 // Look for a ']' character which denotes the end of the scan list.
54 H.HandleIncompleteScanList(start, I - 1);
63 // FIXME: Much of this is copy-paste from ParsePrintfSpecifier.
64 // We can possibly refactor.
65 static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
70 using namespace clang::analyze_scanf;
72 const char *Start = 0;
73 UpdateOnReturn <const char*> UpdateBeg(Beg, I);
75 // Look for a '%' character that indicates the start of a format specifier.
76 for ( ; I != E ; ++I) {
79 // Detect spurious null characters, which are likely errors.
84 Start = I++; // Record the start of the format specifier.
89 // No format specifier found?
94 // No more characters left?
95 H.HandleIncompleteSpecifier(Start, E - Start);
100 if (ParseArgPosition(H, FS, Start, I, E))
104 // No more characters left?
105 H.HandleIncompleteSpecifier(Start, E - Start);
109 // Look for '*' flag if it is present.
111 FS.setSuppressAssignment(I);
113 H.HandleIncompleteSpecifier(Start, E - Start);
118 // Look for the field width (if any). Unlike printf, this is either
119 // a fixed integer or isn't present.
120 const OptionalAmount &Amt = clang::analyze_format_string::ParseAmount(I, E);
121 if (Amt.getHowSpecified() != OptionalAmount::NotSpecified) {
122 assert(Amt.getHowSpecified() == OptionalAmount::Constant);
123 FS.setFieldWidth(Amt);
126 // No more characters left?
127 H.HandleIncompleteSpecifier(Start, E - Start);
132 // Look for the length modifier.
133 if (ParseLengthModifier(FS, I, E) && I == E) {
134 // No more characters left?
135 H.HandleIncompleteSpecifier(Start, E - Start);
139 // Detect spurious null characters, which are likely errors.
145 // Finally, look for the conversion specifier.
146 const char *conversionPosition = I++;
147 ScanfConversionSpecifier::Kind k = ScanfConversionSpecifier::InvalidSpecifier;
148 switch (*conversionPosition) {
151 case '%': k = ConversionSpecifier::PercentArg; break;
152 case 'A': k = ConversionSpecifier::AArg; break;
153 case 'E': k = ConversionSpecifier::EArg; break;
154 case 'F': k = ConversionSpecifier::FArg; break;
155 case 'G': k = ConversionSpecifier::GArg; break;
156 case 'X': k = ConversionSpecifier::XArg; break;
157 case 'a': k = ConversionSpecifier::aArg; break;
158 case 'd': k = ConversionSpecifier::dArg; break;
159 case 'e': k = ConversionSpecifier::eArg; break;
160 case 'f': k = ConversionSpecifier::fArg; break;
161 case 'g': k = ConversionSpecifier::gArg; break;
162 case 'i': k = ConversionSpecifier::iArg; break;
163 case 'n': k = ConversionSpecifier::nArg; break;
164 case 'c': k = ConversionSpecifier::cArg; break;
165 case 'C': k = ConversionSpecifier::CArg; break;
166 case 'S': k = ConversionSpecifier::SArg; break;
167 case '[': k = ConversionSpecifier::ScanListArg; break;
168 case 'u': k = ConversionSpecifier::uArg; break;
169 case 'x': k = ConversionSpecifier::xArg; break;
170 case 'o': k = ConversionSpecifier::oArg; break;
171 case 's': k = ConversionSpecifier::sArg; break;
172 case 'p': k = ConversionSpecifier::pArg; break;
174 ScanfConversionSpecifier CS(conversionPosition, k);
175 if (k == ScanfConversionSpecifier::ScanListArg) {
176 if (!ParseScanList(H, CS, I, E))
179 FS.setConversionSpecifier(CS);
180 if (CS.consumesDataArgument() && !FS.getSuppressAssignment()
181 && !FS.usesPositionalArg())
182 FS.setArgIndex(argIndex++);
184 // FIXME: '%' and '*' doesn't make sense. Issue a warning.
185 // FIXME: 'ConsumedSoFar' and '*' doesn't make sense.
187 if (k == ScanfConversionSpecifier::InvalidSpecifier) {
188 // Assume the conversion takes one argument.
189 return !H.HandleInvalidScanfConversionSpecifier(FS, Beg, I - Beg);
191 return ScanfSpecifierResult(Start, FS);
194 bool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H,
198 unsigned argIndex = 0;
200 // Keep looking for a format specifier until we have exhausted the string.
202 const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E, argIndex);
203 // Did a fail-stop error of any kind occur when parsing the specifier?
204 // If so, don't do any more processing.
205 if (FSR.shouldStop())
207 // Did we exhaust the string or encounter an error that
208 // we can recover from?
211 // We have a format specifier. Pass it to the callback.
212 if (!H.HandleScanfSpecifier(FSR.getValue(), FSR.getStart(),
213 I - FSR.getStart())) {
217 assert(I == E && "Format string not exhausted");