xref: /src/contrib/llvm-project/clang/lib/AST/ScanfFormatString.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
13d1dcd9bSDimitry Andric //= ScanfFormatString.cpp - Analysis of printf format strings --*- C++ -*-===//
23d1dcd9bSDimitry Andric //
322989816SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
422989816SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
522989816SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63d1dcd9bSDimitry Andric //
73d1dcd9bSDimitry Andric //===----------------------------------------------------------------------===//
83d1dcd9bSDimitry Andric //
93d1dcd9bSDimitry Andric // Handling of format string in scanf and friends.  The structure of format
103d1dcd9bSDimitry Andric // strings for fscanf() are described in C99 7.19.6.2.
113d1dcd9bSDimitry Andric //
123d1dcd9bSDimitry Andric //===----------------------------------------------------------------------===//
133d1dcd9bSDimitry Andric 
14676fbe81SDimitry Andric #include "clang/AST/FormatString.h"
153d1dcd9bSDimitry Andric #include "FormatStringParsing.h"
16809500fcSDimitry Andric #include "clang/Basic/TargetInfo.h"
173d1dcd9bSDimitry Andric 
1856d91b49SDimitry Andric using clang::analyze_format_string::ArgType;
193d1dcd9bSDimitry Andric using clang::analyze_format_string::FormatStringHandler;
203d1dcd9bSDimitry Andric using clang::analyze_format_string::LengthModifier;
213d1dcd9bSDimitry Andric using clang::analyze_format_string::OptionalAmount;
223d1dcd9bSDimitry Andric using clang::analyze_format_string::ConversionSpecifier;
233d1dcd9bSDimitry Andric using clang::analyze_scanf::ScanfConversionSpecifier;
243d1dcd9bSDimitry Andric using clang::analyze_scanf::ScanfSpecifier;
253d1dcd9bSDimitry Andric using clang::UpdateOnReturn;
26dbe13110SDimitry Andric using namespace clang;
273d1dcd9bSDimitry Andric 
283d1dcd9bSDimitry Andric typedef clang::analyze_format_string::SpecifierResult<ScanfSpecifier>
293d1dcd9bSDimitry Andric         ScanfSpecifierResult;
303d1dcd9bSDimitry Andric 
ParseScanList(FormatStringHandler & H,ScanfConversionSpecifier & CS,const char * & Beg,const char * E)313d1dcd9bSDimitry Andric static bool ParseScanList(FormatStringHandler &H,
323d1dcd9bSDimitry Andric                           ScanfConversionSpecifier &CS,
333d1dcd9bSDimitry Andric                           const char *&Beg, const char *E) {
343d1dcd9bSDimitry Andric   const char *I = Beg;
353d1dcd9bSDimitry Andric   const char *start = I - 1;
363d1dcd9bSDimitry Andric   UpdateOnReturn <const char*> UpdateBeg(Beg, I);
373d1dcd9bSDimitry Andric 
383d1dcd9bSDimitry Andric   // No more characters?
393d1dcd9bSDimitry Andric   if (I == E) {
403d1dcd9bSDimitry Andric     H.HandleIncompleteScanList(start, I);
413d1dcd9bSDimitry Andric     return true;
423d1dcd9bSDimitry Andric   }
433d1dcd9bSDimitry Andric 
443d1dcd9bSDimitry Andric   // Special case: ']' is the first character.
453d1dcd9bSDimitry Andric   if (*I == ']') {
463d1dcd9bSDimitry Andric     if (++I == E) {
473d1dcd9bSDimitry Andric       H.HandleIncompleteScanList(start, I - 1);
483d1dcd9bSDimitry Andric       return true;
493d1dcd9bSDimitry Andric     }
503d1dcd9bSDimitry Andric   }
513d1dcd9bSDimitry Andric 
529f4dbff6SDimitry Andric   // Special case: "^]" are the first characters.
539f4dbff6SDimitry Andric   if (I + 1 != E && I[0] == '^' && I[1] == ']') {
549f4dbff6SDimitry Andric     I += 2;
559f4dbff6SDimitry Andric     if (I == E) {
569f4dbff6SDimitry Andric       H.HandleIncompleteScanList(start, I - 1);
579f4dbff6SDimitry Andric       return true;
589f4dbff6SDimitry Andric     }
599f4dbff6SDimitry Andric   }
609f4dbff6SDimitry Andric 
613d1dcd9bSDimitry Andric   // Look for a ']' character which denotes the end of the scan list.
623d1dcd9bSDimitry Andric   while (*I != ']') {
633d1dcd9bSDimitry Andric     if (++I == E) {
643d1dcd9bSDimitry Andric       H.HandleIncompleteScanList(start, I - 1);
653d1dcd9bSDimitry Andric       return true;
663d1dcd9bSDimitry Andric     }
673d1dcd9bSDimitry Andric   }
683d1dcd9bSDimitry Andric 
693d1dcd9bSDimitry Andric   CS.setEndScanList(I);
703d1dcd9bSDimitry Andric   return false;
713d1dcd9bSDimitry Andric }
723d1dcd9bSDimitry Andric 
733d1dcd9bSDimitry Andric // FIXME: Much of this is copy-paste from ParsePrintfSpecifier.
743d1dcd9bSDimitry Andric // We can possibly refactor.
ParseScanfSpecifier(FormatStringHandler & H,const char * & Beg,const char * E,unsigned & argIndex,const LangOptions & LO,const TargetInfo & Target)753d1dcd9bSDimitry Andric static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
763d1dcd9bSDimitry Andric                                                 const char *&Beg,
773d1dcd9bSDimitry Andric                                                 const char *E,
78dbe13110SDimitry Andric                                                 unsigned &argIndex,
7913cc256eSDimitry Andric                                                 const LangOptions &LO,
8013cc256eSDimitry Andric                                                 const TargetInfo &Target) {
812b6b257fSDimitry Andric   using namespace clang::analyze_format_string;
823d1dcd9bSDimitry Andric   using namespace clang::analyze_scanf;
833d1dcd9bSDimitry Andric   const char *I = Beg;
849f4dbff6SDimitry Andric   const char *Start = nullptr;
853d1dcd9bSDimitry Andric   UpdateOnReturn <const char*> UpdateBeg(Beg, I);
863d1dcd9bSDimitry Andric 
873d1dcd9bSDimitry Andric     // Look for a '%' character that indicates the start of a format specifier.
883d1dcd9bSDimitry Andric   for ( ; I != E ; ++I) {
893d1dcd9bSDimitry Andric     char c = *I;
903d1dcd9bSDimitry Andric     if (c == '\0') {
913d1dcd9bSDimitry Andric         // Detect spurious null characters, which are likely errors.
923d1dcd9bSDimitry Andric       H.HandleNullChar(I);
933d1dcd9bSDimitry Andric       return true;
943d1dcd9bSDimitry Andric     }
953d1dcd9bSDimitry Andric     if (c == '%') {
963d1dcd9bSDimitry Andric       Start = I++;  // Record the start of the format specifier.
973d1dcd9bSDimitry Andric       break;
983d1dcd9bSDimitry Andric     }
993d1dcd9bSDimitry Andric   }
1003d1dcd9bSDimitry Andric 
1013d1dcd9bSDimitry Andric     // No format specifier found?
1023d1dcd9bSDimitry Andric   if (!Start)
1033d1dcd9bSDimitry Andric     return false;
1043d1dcd9bSDimitry Andric 
1053d1dcd9bSDimitry Andric   if (I == E) {
1063d1dcd9bSDimitry Andric       // No more characters left?
1073d1dcd9bSDimitry Andric     H.HandleIncompleteSpecifier(Start, E - Start);
1083d1dcd9bSDimitry Andric     return true;
1093d1dcd9bSDimitry Andric   }
1103d1dcd9bSDimitry Andric 
1113d1dcd9bSDimitry Andric   ScanfSpecifier FS;
1123d1dcd9bSDimitry Andric   if (ParseArgPosition(H, FS, Start, I, E))
1133d1dcd9bSDimitry Andric     return true;
1143d1dcd9bSDimitry Andric 
1153d1dcd9bSDimitry Andric   if (I == E) {
1163d1dcd9bSDimitry Andric       // No more characters left?
1173d1dcd9bSDimitry Andric     H.HandleIncompleteSpecifier(Start, E - Start);
1183d1dcd9bSDimitry Andric     return true;
1193d1dcd9bSDimitry Andric   }
1203d1dcd9bSDimitry Andric 
1213d1dcd9bSDimitry Andric   // Look for '*' flag if it is present.
1223d1dcd9bSDimitry Andric   if (*I == '*') {
1233d1dcd9bSDimitry Andric     FS.setSuppressAssignment(I);
1243d1dcd9bSDimitry Andric     if (++I == E) {
1253d1dcd9bSDimitry Andric       H.HandleIncompleteSpecifier(Start, E - Start);
1263d1dcd9bSDimitry Andric       return true;
1273d1dcd9bSDimitry Andric     }
1283d1dcd9bSDimitry Andric   }
1293d1dcd9bSDimitry Andric 
1303d1dcd9bSDimitry Andric   // Look for the field width (if any).  Unlike printf, this is either
1313d1dcd9bSDimitry Andric   // a fixed integer or isn't present.
1323d1dcd9bSDimitry Andric   const OptionalAmount &Amt = clang::analyze_format_string::ParseAmount(I, E);
1333d1dcd9bSDimitry Andric   if (Amt.getHowSpecified() != OptionalAmount::NotSpecified) {
1343d1dcd9bSDimitry Andric     assert(Amt.getHowSpecified() == OptionalAmount::Constant);
1353d1dcd9bSDimitry Andric     FS.setFieldWidth(Amt);
1363d1dcd9bSDimitry Andric 
1373d1dcd9bSDimitry Andric     if (I == E) {
1383d1dcd9bSDimitry Andric       // No more characters left?
1393d1dcd9bSDimitry Andric       H.HandleIncompleteSpecifier(Start, E - Start);
1403d1dcd9bSDimitry Andric       return true;
1413d1dcd9bSDimitry Andric     }
1423d1dcd9bSDimitry Andric   }
1433d1dcd9bSDimitry Andric 
1443d1dcd9bSDimitry Andric   // Look for the length modifier.
14522989816SDimitry Andric   if (ParseLengthModifier(FS, I, E, LO, /*IsScanf=*/true) && I == E) {
1463d1dcd9bSDimitry Andric       // No more characters left?
1473d1dcd9bSDimitry Andric     H.HandleIncompleteSpecifier(Start, E - Start);
1483d1dcd9bSDimitry Andric     return true;
1493d1dcd9bSDimitry Andric   }
1503d1dcd9bSDimitry Andric 
1513d1dcd9bSDimitry Andric   // Detect spurious null characters, which are likely errors.
1523d1dcd9bSDimitry Andric   if (*I == '\0') {
1533d1dcd9bSDimitry Andric     H.HandleNullChar(I);
1543d1dcd9bSDimitry Andric     return true;
1553d1dcd9bSDimitry Andric   }
1563d1dcd9bSDimitry Andric 
1573d1dcd9bSDimitry Andric   // Finally, look for the conversion specifier.
1583d1dcd9bSDimitry Andric   const char *conversionPosition = I++;
1593d1dcd9bSDimitry Andric   ScanfConversionSpecifier::Kind k = ScanfConversionSpecifier::InvalidSpecifier;
1603d1dcd9bSDimitry Andric   switch (*conversionPosition) {
1613d1dcd9bSDimitry Andric     default:
1623d1dcd9bSDimitry Andric       break;
1633d1dcd9bSDimitry Andric     case '%': k = ConversionSpecifier::PercentArg;   break;
164e3b55780SDimitry Andric     case 'b': k = ConversionSpecifier::bArg; break;
1653d1dcd9bSDimitry Andric     case 'A': k = ConversionSpecifier::AArg; break;
1663d1dcd9bSDimitry Andric     case 'E': k = ConversionSpecifier::EArg; break;
1673d1dcd9bSDimitry Andric     case 'F': k = ConversionSpecifier::FArg; break;
1683d1dcd9bSDimitry Andric     case 'G': k = ConversionSpecifier::GArg; break;
1693d1dcd9bSDimitry Andric     case 'X': k = ConversionSpecifier::XArg; break;
1703d1dcd9bSDimitry Andric     case 'a': k = ConversionSpecifier::aArg; break;
1713d1dcd9bSDimitry Andric     case 'd': k = ConversionSpecifier::dArg; break;
1723d1dcd9bSDimitry Andric     case 'e': k = ConversionSpecifier::eArg; break;
1733d1dcd9bSDimitry Andric     case 'f': k = ConversionSpecifier::fArg; break;
1743d1dcd9bSDimitry Andric     case 'g': k = ConversionSpecifier::gArg; break;
1753d1dcd9bSDimitry Andric     case 'i': k = ConversionSpecifier::iArg; break;
1763d1dcd9bSDimitry Andric     case 'n': k = ConversionSpecifier::nArg; break;
1773d1dcd9bSDimitry Andric     case 'c': k = ConversionSpecifier::cArg; break;
1783d1dcd9bSDimitry Andric     case 'C': k = ConversionSpecifier::CArg; break;
1793d1dcd9bSDimitry Andric     case 'S': k = ConversionSpecifier::SArg; break;
1803d1dcd9bSDimitry Andric     case '[': k = ConversionSpecifier::ScanListArg; break;
1813d1dcd9bSDimitry Andric     case 'u': k = ConversionSpecifier::uArg; break;
1823d1dcd9bSDimitry Andric     case 'x': k = ConversionSpecifier::xArg; break;
1833d1dcd9bSDimitry Andric     case 'o': k = ConversionSpecifier::oArg; break;
1843d1dcd9bSDimitry Andric     case 's': k = ConversionSpecifier::sArg; break;
1853d1dcd9bSDimitry Andric     case 'p': k = ConversionSpecifier::pArg; break;
18613cc256eSDimitry Andric     // Apple extensions
18713cc256eSDimitry Andric       // Apple-specific
18813cc256eSDimitry Andric     case 'D':
18913cc256eSDimitry Andric       if (Target.getTriple().isOSDarwin())
19013cc256eSDimitry Andric         k = ConversionSpecifier::DArg;
19113cc256eSDimitry Andric       break;
19213cc256eSDimitry Andric     case 'O':
19313cc256eSDimitry Andric       if (Target.getTriple().isOSDarwin())
19413cc256eSDimitry Andric         k = ConversionSpecifier::OArg;
19513cc256eSDimitry Andric       break;
19613cc256eSDimitry Andric     case 'U':
19713cc256eSDimitry Andric       if (Target.getTriple().isOSDarwin())
19813cc256eSDimitry Andric         k = ConversionSpecifier::UArg;
19913cc256eSDimitry Andric       break;
2003d1dcd9bSDimitry Andric   }
2013d1dcd9bSDimitry Andric   ScanfConversionSpecifier CS(conversionPosition, k);
2023d1dcd9bSDimitry Andric   if (k == ScanfConversionSpecifier::ScanListArg) {
203dbe13110SDimitry Andric     if (ParseScanList(H, CS, I, E))
2043d1dcd9bSDimitry Andric       return true;
2053d1dcd9bSDimitry Andric   }
2063d1dcd9bSDimitry Andric   FS.setConversionSpecifier(CS);
2073d1dcd9bSDimitry Andric   if (CS.consumesDataArgument() && !FS.getSuppressAssignment()
2083d1dcd9bSDimitry Andric       && !FS.usesPositionalArg())
2093d1dcd9bSDimitry Andric     FS.setArgIndex(argIndex++);
2103d1dcd9bSDimitry Andric 
2113d1dcd9bSDimitry Andric   // FIXME: '%' and '*' doesn't make sense.  Issue a warning.
2123d1dcd9bSDimitry Andric   // FIXME: 'ConsumedSoFar' and '*' doesn't make sense.
2133d1dcd9bSDimitry Andric 
2143d1dcd9bSDimitry Andric   if (k == ScanfConversionSpecifier::InvalidSpecifier) {
2152b6b257fSDimitry Andric     unsigned Len = I - Beg;
2162b6b257fSDimitry Andric     if (ParseUTF8InvalidSpecifier(Beg, E, Len)) {
2172b6b257fSDimitry Andric       CS.setEndScanList(Beg + Len);
2182b6b257fSDimitry Andric       FS.setConversionSpecifier(CS);
2192b6b257fSDimitry Andric     }
2203d1dcd9bSDimitry Andric     // Assume the conversion takes one argument.
2212b6b257fSDimitry Andric     return !H.HandleInvalidScanfConversionSpecifier(FS, Beg, Len);
2223d1dcd9bSDimitry Andric   }
2233d1dcd9bSDimitry Andric   return ScanfSpecifierResult(Start, FS);
2243d1dcd9bSDimitry Andric }
2253d1dcd9bSDimitry Andric 
getArgType(ASTContext & Ctx) const22656d91b49SDimitry Andric ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
227dbe13110SDimitry Andric   const ScanfConversionSpecifier &CS = getConversionSpecifier();
228dbe13110SDimitry Andric 
229dbe13110SDimitry Andric   if (!CS.consumesDataArgument())
23056d91b49SDimitry Andric     return ArgType::Invalid();
231dbe13110SDimitry Andric 
232dbe13110SDimitry Andric   switch(CS.getKind()) {
233dbe13110SDimitry Andric     // Signed int.
234dbe13110SDimitry Andric     case ConversionSpecifier::dArg:
23513cc256eSDimitry Andric     case ConversionSpecifier::DArg:
236dbe13110SDimitry Andric     case ConversionSpecifier::iArg:
237dbe13110SDimitry Andric       switch (LM.getKind()) {
23856d91b49SDimitry Andric         case LengthModifier::None:
23956d91b49SDimitry Andric           return ArgType::PtrTo(Ctx.IntTy);
240dbe13110SDimitry Andric         case LengthModifier::AsChar:
24156d91b49SDimitry Andric           return ArgType::PtrTo(ArgType::AnyCharTy);
24256d91b49SDimitry Andric         case LengthModifier::AsShort:
24356d91b49SDimitry Andric           return ArgType::PtrTo(Ctx.ShortTy);
24456d91b49SDimitry Andric         case LengthModifier::AsLong:
24556d91b49SDimitry Andric           return ArgType::PtrTo(Ctx.LongTy);
246dbe13110SDimitry Andric         case LengthModifier::AsLongLong:
247dbe13110SDimitry Andric         case LengthModifier::AsQuad:
24856d91b49SDimitry Andric           return ArgType::PtrTo(Ctx.LongLongTy);
249bfef3995SDimitry Andric         case LengthModifier::AsInt64:
250bfef3995SDimitry Andric           return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));
251dbe13110SDimitry Andric         case LengthModifier::AsIntMax:
25256d91b49SDimitry Andric           return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
253dbe13110SDimitry Andric         case LengthModifier::AsSizeT:
254461a67faSDimitry Andric           return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
255dbe13110SDimitry Andric         case LengthModifier::AsPtrDiff:
25656d91b49SDimitry Andric           return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
257dbe13110SDimitry Andric         case LengthModifier::AsLongDouble:
258dbe13110SDimitry Andric           // GNU extension.
25956d91b49SDimitry Andric           return ArgType::PtrTo(Ctx.LongLongTy);
26056d91b49SDimitry Andric         case LengthModifier::AsAllocate:
26156d91b49SDimitry Andric         case LengthModifier::AsMAllocate:
262bfef3995SDimitry Andric         case LengthModifier::AsInt32:
263bfef3995SDimitry Andric         case LengthModifier::AsInt3264:
26406d4ba38SDimitry Andric         case LengthModifier::AsWide:
26522989816SDimitry Andric         case LengthModifier::AsShortLong:
26656d91b49SDimitry Andric           return ArgType::Invalid();
267dbe13110SDimitry Andric       }
26822989816SDimitry Andric       llvm_unreachable("Unsupported LengthModifier Type");
269dbe13110SDimitry Andric 
270dbe13110SDimitry Andric     // Unsigned int.
271e3b55780SDimitry Andric     case ConversionSpecifier::bArg:
272dbe13110SDimitry Andric     case ConversionSpecifier::oArg:
27313cc256eSDimitry Andric     case ConversionSpecifier::OArg:
274dbe13110SDimitry Andric     case ConversionSpecifier::uArg:
27513cc256eSDimitry Andric     case ConversionSpecifier::UArg:
276dbe13110SDimitry Andric     case ConversionSpecifier::xArg:
277dbe13110SDimitry Andric     case ConversionSpecifier::XArg:
278dbe13110SDimitry Andric       switch (LM.getKind()) {
27956d91b49SDimitry Andric         case LengthModifier::None:
28056d91b49SDimitry Andric           return ArgType::PtrTo(Ctx.UnsignedIntTy);
28156d91b49SDimitry Andric         case LengthModifier::AsChar:
28256d91b49SDimitry Andric           return ArgType::PtrTo(Ctx.UnsignedCharTy);
28356d91b49SDimitry Andric         case LengthModifier::AsShort:
28456d91b49SDimitry Andric           return ArgType::PtrTo(Ctx.UnsignedShortTy);
28556d91b49SDimitry Andric         case LengthModifier::AsLong:
28656d91b49SDimitry Andric           return ArgType::PtrTo(Ctx.UnsignedLongTy);
287dbe13110SDimitry Andric         case LengthModifier::AsLongLong:
288dbe13110SDimitry Andric         case LengthModifier::AsQuad:
28956d91b49SDimitry Andric           return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
290bfef3995SDimitry Andric         case LengthModifier::AsInt64:
291bfef3995SDimitry Andric           return ArgType::PtrTo(ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64"));
292dbe13110SDimitry Andric         case LengthModifier::AsIntMax:
29356d91b49SDimitry Andric           return ArgType::PtrTo(ArgType(Ctx.getUIntMaxType(), "uintmax_t"));
294dbe13110SDimitry Andric         case LengthModifier::AsSizeT:
29556d91b49SDimitry Andric           return ArgType::PtrTo(ArgType(Ctx.getSizeType(), "size_t"));
296dbe13110SDimitry Andric         case LengthModifier::AsPtrDiff:
297461a67faSDimitry Andric           return ArgType::PtrTo(
298461a67faSDimitry Andric               ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));
299dbe13110SDimitry Andric         case LengthModifier::AsLongDouble:
300dbe13110SDimitry Andric           // GNU extension.
30156d91b49SDimitry Andric           return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
30256d91b49SDimitry Andric         case LengthModifier::AsAllocate:
30356d91b49SDimitry Andric         case LengthModifier::AsMAllocate:
304bfef3995SDimitry Andric         case LengthModifier::AsInt32:
305bfef3995SDimitry Andric         case LengthModifier::AsInt3264:
30606d4ba38SDimitry Andric         case LengthModifier::AsWide:
30722989816SDimitry Andric         case LengthModifier::AsShortLong:
30856d91b49SDimitry Andric           return ArgType::Invalid();
309dbe13110SDimitry Andric       }
31022989816SDimitry Andric       llvm_unreachable("Unsupported LengthModifier Type");
311dbe13110SDimitry Andric 
312dbe13110SDimitry Andric     // Float.
313dbe13110SDimitry Andric     case ConversionSpecifier::aArg:
314dbe13110SDimitry Andric     case ConversionSpecifier::AArg:
315dbe13110SDimitry Andric     case ConversionSpecifier::eArg:
316dbe13110SDimitry Andric     case ConversionSpecifier::EArg:
317dbe13110SDimitry Andric     case ConversionSpecifier::fArg:
318dbe13110SDimitry Andric     case ConversionSpecifier::FArg:
319dbe13110SDimitry Andric     case ConversionSpecifier::gArg:
320dbe13110SDimitry Andric     case ConversionSpecifier::GArg:
321dbe13110SDimitry Andric       switch (LM.getKind()) {
32256d91b49SDimitry Andric         case LengthModifier::None:
32356d91b49SDimitry Andric           return ArgType::PtrTo(Ctx.FloatTy);
32456d91b49SDimitry Andric         case LengthModifier::AsLong:
32556d91b49SDimitry Andric           return ArgType::PtrTo(Ctx.DoubleTy);
326dbe13110SDimitry Andric         case LengthModifier::AsLongDouble:
32756d91b49SDimitry Andric           return ArgType::PtrTo(Ctx.LongDoubleTy);
328dbe13110SDimitry Andric         default:
32956d91b49SDimitry Andric           return ArgType::Invalid();
330dbe13110SDimitry Andric       }
331dbe13110SDimitry Andric 
332dbe13110SDimitry Andric     // Char, string and scanlist.
333dbe13110SDimitry Andric     case ConversionSpecifier::cArg:
334dbe13110SDimitry Andric     case ConversionSpecifier::sArg:
335dbe13110SDimitry Andric     case ConversionSpecifier::ScanListArg:
336dbe13110SDimitry Andric       switch (LM.getKind()) {
33756d91b49SDimitry Andric         case LengthModifier::None:
33856d91b49SDimitry Andric           return ArgType::PtrTo(ArgType::AnyCharTy);
339dbe13110SDimitry Andric         case LengthModifier::AsLong:
34006d4ba38SDimitry Andric         case LengthModifier::AsWide:
341bfef3995SDimitry Andric           return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));
342dbe13110SDimitry Andric         case LengthModifier::AsAllocate:
343dbe13110SDimitry Andric         case LengthModifier::AsMAllocate:
34456d91b49SDimitry Andric           return ArgType::PtrTo(ArgType::CStrTy);
34506d4ba38SDimitry Andric         case LengthModifier::AsShort:
34606d4ba38SDimitry Andric           if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
34706d4ba38SDimitry Andric             return ArgType::PtrTo(ArgType::AnyCharTy);
348e3b55780SDimitry Andric           [[fallthrough]];
349dbe13110SDimitry Andric         default:
35056d91b49SDimitry Andric           return ArgType::Invalid();
351dbe13110SDimitry Andric       }
352dbe13110SDimitry Andric     case ConversionSpecifier::CArg:
353dbe13110SDimitry Andric     case ConversionSpecifier::SArg:
354dbe13110SDimitry Andric       // FIXME: Mac OS X specific?
355dbe13110SDimitry Andric       switch (LM.getKind()) {
356dbe13110SDimitry Andric         case LengthModifier::None:
35706d4ba38SDimitry Andric         case LengthModifier::AsWide:
358bfef3995SDimitry Andric           return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));
359dbe13110SDimitry Andric         case LengthModifier::AsAllocate:
360dbe13110SDimitry Andric         case LengthModifier::AsMAllocate:
36156d91b49SDimitry Andric           return ArgType::PtrTo(ArgType(ArgType::WCStrTy, "wchar_t *"));
36206d4ba38SDimitry Andric         case LengthModifier::AsShort:
36306d4ba38SDimitry Andric           if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
36406d4ba38SDimitry Andric             return ArgType::PtrTo(ArgType::AnyCharTy);
365e3b55780SDimitry Andric           [[fallthrough]];
366dbe13110SDimitry Andric         default:
36756d91b49SDimitry Andric           return ArgType::Invalid();
368dbe13110SDimitry Andric       }
369dbe13110SDimitry Andric 
370dbe13110SDimitry Andric     // Pointer.
371dbe13110SDimitry Andric     case ConversionSpecifier::pArg:
37256d91b49SDimitry Andric       return ArgType::PtrTo(ArgType::CPointerTy);
37356d91b49SDimitry Andric 
37456d91b49SDimitry Andric     // Write-back.
37556d91b49SDimitry Andric     case ConversionSpecifier::nArg:
37656d91b49SDimitry Andric       switch (LM.getKind()) {
37756d91b49SDimitry Andric         case LengthModifier::None:
37856d91b49SDimitry Andric           return ArgType::PtrTo(Ctx.IntTy);
37956d91b49SDimitry Andric         case LengthModifier::AsChar:
38056d91b49SDimitry Andric           return ArgType::PtrTo(Ctx.SignedCharTy);
38156d91b49SDimitry Andric         case LengthModifier::AsShort:
38256d91b49SDimitry Andric           return ArgType::PtrTo(Ctx.ShortTy);
38356d91b49SDimitry Andric         case LengthModifier::AsLong:
38456d91b49SDimitry Andric           return ArgType::PtrTo(Ctx.LongTy);
38556d91b49SDimitry Andric         case LengthModifier::AsLongLong:
38656d91b49SDimitry Andric         case LengthModifier::AsQuad:
38756d91b49SDimitry Andric           return ArgType::PtrTo(Ctx.LongLongTy);
388bfef3995SDimitry Andric         case LengthModifier::AsInt64:
389bfef3995SDimitry Andric           return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));
39056d91b49SDimitry Andric         case LengthModifier::AsIntMax:
39156d91b49SDimitry Andric           return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
39256d91b49SDimitry Andric         case LengthModifier::AsSizeT:
393461a67faSDimitry Andric           return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
39456d91b49SDimitry Andric         case LengthModifier::AsPtrDiff:
39556d91b49SDimitry Andric           return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
39656d91b49SDimitry Andric         case LengthModifier::AsLongDouble:
39756d91b49SDimitry Andric           return ArgType(); // FIXME: Is this a known extension?
39856d91b49SDimitry Andric         case LengthModifier::AsAllocate:
39956d91b49SDimitry Andric         case LengthModifier::AsMAllocate:
400bfef3995SDimitry Andric         case LengthModifier::AsInt32:
401bfef3995SDimitry Andric         case LengthModifier::AsInt3264:
40206d4ba38SDimitry Andric         case LengthModifier::AsWide:
40322989816SDimitry Andric         case LengthModifier::AsShortLong:
40456d91b49SDimitry Andric           return ArgType::Invalid();
40556d91b49SDimitry Andric         }
406dbe13110SDimitry Andric 
407dbe13110SDimitry Andric     default:
408dbe13110SDimitry Andric       break;
409dbe13110SDimitry Andric   }
410dbe13110SDimitry Andric 
41156d91b49SDimitry Andric   return ArgType();
412dbe13110SDimitry Andric }
413dbe13110SDimitry Andric 
fixType(QualType QT,QualType RawQT,const LangOptions & LangOpt,ASTContext & Ctx)4149f4dbff6SDimitry Andric bool ScanfSpecifier::fixType(QualType QT, QualType RawQT,
4159f4dbff6SDimitry Andric                              const LangOptions &LangOpt,
416dbe13110SDimitry Andric                              ASTContext &Ctx) {
417dbe13110SDimitry Andric 
41856d91b49SDimitry Andric   // %n is different from other conversion specifiers; don't try to fix it.
41956d91b49SDimitry Andric   if (CS.getKind() == ConversionSpecifier::nArg)
42056d91b49SDimitry Andric     return false;
42156d91b49SDimitry Andric 
4229f4dbff6SDimitry Andric   if (!QT->isPointerType())
4239f4dbff6SDimitry Andric     return false;
4249f4dbff6SDimitry Andric 
425dbe13110SDimitry Andric   QualType PT = QT->getPointeeType();
42656d91b49SDimitry Andric 
42756d91b49SDimitry Andric   // If it's an enum, get its underlying type.
428bab175ecSDimitry Andric   if (const EnumType *ETy = PT->getAs<EnumType>()) {
429bab175ecSDimitry Andric     // Don't try to fix incomplete enums.
430bab175ecSDimitry Andric     if (!ETy->getDecl()->isComplete())
431bab175ecSDimitry Andric       return false;
4329f4dbff6SDimitry Andric     PT = ETy->getDecl()->getIntegerType();
433bab175ecSDimitry Andric   }
43456d91b49SDimitry Andric 
435dbe13110SDimitry Andric   const BuiltinType *BT = PT->getAs<BuiltinType>();
436dbe13110SDimitry Andric   if (!BT)
437dbe13110SDimitry Andric     return false;
438dbe13110SDimitry Andric 
439dbe13110SDimitry Andric   // Pointer to a character.
440dbe13110SDimitry Andric   if (PT->isAnyCharacterType()) {
441dbe13110SDimitry Andric     CS.setKind(ConversionSpecifier::sArg);
442dbe13110SDimitry Andric     if (PT->isWideCharType())
443dbe13110SDimitry Andric       LM.setKind(LengthModifier::AsWideChar);
444dbe13110SDimitry Andric     else
445dbe13110SDimitry Andric       LM.setKind(LengthModifier::None);
4469f4dbff6SDimitry Andric 
4479f4dbff6SDimitry Andric     // If we know the target array length, we can use it as a field width.
4489f4dbff6SDimitry Andric     if (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(RawQT)) {
449b1c73532SDimitry Andric       if (CAT->getSizeModifier() == ArraySizeModifier::Normal)
4509f4dbff6SDimitry Andric         FieldWidth = OptionalAmount(OptionalAmount::Constant,
451ac9a064cSDimitry Andric                                     CAT->getZExtSize() - 1, "", 0, false);
4529f4dbff6SDimitry Andric     }
453dbe13110SDimitry Andric     return true;
454dbe13110SDimitry Andric   }
455dbe13110SDimitry Andric 
456dbe13110SDimitry Andric   // Figure out the length modifier.
457dbe13110SDimitry Andric   switch (BT->getKind()) {
458dbe13110SDimitry Andric     // no modifier
459dbe13110SDimitry Andric     case BuiltinType::UInt:
460dbe13110SDimitry Andric     case BuiltinType::Int:
461dbe13110SDimitry Andric     case BuiltinType::Float:
462dbe13110SDimitry Andric       LM.setKind(LengthModifier::None);
463dbe13110SDimitry Andric       break;
464dbe13110SDimitry Andric 
465dbe13110SDimitry Andric     // hh
466dbe13110SDimitry Andric     case BuiltinType::Char_U:
467dbe13110SDimitry Andric     case BuiltinType::UChar:
468dbe13110SDimitry Andric     case BuiltinType::Char_S:
469dbe13110SDimitry Andric     case BuiltinType::SChar:
470dbe13110SDimitry Andric       LM.setKind(LengthModifier::AsChar);
471dbe13110SDimitry Andric       break;
472dbe13110SDimitry Andric 
473dbe13110SDimitry Andric     // h
474dbe13110SDimitry Andric     case BuiltinType::Short:
475dbe13110SDimitry Andric     case BuiltinType::UShort:
476dbe13110SDimitry Andric       LM.setKind(LengthModifier::AsShort);
477dbe13110SDimitry Andric       break;
478dbe13110SDimitry Andric 
479dbe13110SDimitry Andric     // l
480dbe13110SDimitry Andric     case BuiltinType::Long:
481dbe13110SDimitry Andric     case BuiltinType::ULong:
482dbe13110SDimitry Andric     case BuiltinType::Double:
483dbe13110SDimitry Andric       LM.setKind(LengthModifier::AsLong);
484dbe13110SDimitry Andric       break;
485dbe13110SDimitry Andric 
486dbe13110SDimitry Andric     // ll
487dbe13110SDimitry Andric     case BuiltinType::LongLong:
488dbe13110SDimitry Andric     case BuiltinType::ULongLong:
489dbe13110SDimitry Andric       LM.setKind(LengthModifier::AsLongLong);
490dbe13110SDimitry Andric       break;
491dbe13110SDimitry Andric 
492dbe13110SDimitry Andric     // L
493dbe13110SDimitry Andric     case BuiltinType::LongDouble:
494dbe13110SDimitry Andric       LM.setKind(LengthModifier::AsLongDouble);
495dbe13110SDimitry Andric       break;
496dbe13110SDimitry Andric 
497dbe13110SDimitry Andric     // Don't know.
498dbe13110SDimitry Andric     default:
499dbe13110SDimitry Andric       return false;
500dbe13110SDimitry Andric   }
501dbe13110SDimitry Andric 
502dbe13110SDimitry Andric   // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
503e3b55780SDimitry Andric   if (LangOpt.C99 || LangOpt.CPlusPlus11)
50456d91b49SDimitry Andric     namedTypeToLengthModifier(PT, LM);
505dbe13110SDimitry Andric 
506dbe13110SDimitry Andric   // If fixing the length modifier was enough, we are done.
50722989816SDimitry Andric   if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) {
50856d91b49SDimitry Andric     const analyze_scanf::ArgType &AT = getArgType(Ctx);
50913cc256eSDimitry Andric     if (AT.isValid() && AT.matchesType(Ctx, QT))
510dbe13110SDimitry Andric       return true;
51113cc256eSDimitry Andric   }
512dbe13110SDimitry Andric 
513dbe13110SDimitry Andric   // Figure out the conversion specifier.
514dbe13110SDimitry Andric   if (PT->isRealFloatingType())
515dbe13110SDimitry Andric     CS.setKind(ConversionSpecifier::fArg);
516dbe13110SDimitry Andric   else if (PT->isSignedIntegerType())
517dbe13110SDimitry Andric     CS.setKind(ConversionSpecifier::dArg);
518dbe13110SDimitry Andric   else if (PT->isUnsignedIntegerType())
519dbe13110SDimitry Andric     CS.setKind(ConversionSpecifier::uArg);
520dbe13110SDimitry Andric   else
521dbe13110SDimitry Andric     llvm_unreachable("Unexpected type");
522dbe13110SDimitry Andric 
523dbe13110SDimitry Andric   return true;
524dbe13110SDimitry Andric }
525dbe13110SDimitry Andric 
toString(raw_ostream & os) const526dbe13110SDimitry Andric void ScanfSpecifier::toString(raw_ostream &os) const {
527dbe13110SDimitry Andric   os << "%";
528dbe13110SDimitry Andric 
529dbe13110SDimitry Andric   if (usesPositionalArg())
530dbe13110SDimitry Andric     os << getPositionalArgIndex() << "$";
531dbe13110SDimitry Andric   if (SuppressAssignment)
532dbe13110SDimitry Andric     os << "*";
533dbe13110SDimitry Andric 
534dbe13110SDimitry Andric   FieldWidth.toString(os);
535dbe13110SDimitry Andric   os << LM.toString();
536dbe13110SDimitry Andric   os << CS.toString();
537dbe13110SDimitry Andric }
538dbe13110SDimitry Andric 
ParseScanfString(FormatStringHandler & H,const char * I,const char * E,const LangOptions & LO,const TargetInfo & Target)5393d1dcd9bSDimitry Andric bool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H,
5403d1dcd9bSDimitry Andric                                                     const char *I,
541dbe13110SDimitry Andric                                                     const char *E,
54213cc256eSDimitry Andric                                                     const LangOptions &LO,
54313cc256eSDimitry Andric                                                     const TargetInfo &Target) {
5443d1dcd9bSDimitry Andric 
5453d1dcd9bSDimitry Andric   unsigned argIndex = 0;
5463d1dcd9bSDimitry Andric 
5473d1dcd9bSDimitry Andric   // Keep looking for a format specifier until we have exhausted the string.
5483d1dcd9bSDimitry Andric   while (I != E) {
549dbe13110SDimitry Andric     const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E, argIndex,
55013cc256eSDimitry Andric                                                           LO, Target);
5513d1dcd9bSDimitry Andric     // Did a fail-stop error of any kind occur when parsing the specifier?
5523d1dcd9bSDimitry Andric     // If so, don't do any more processing.
5533d1dcd9bSDimitry Andric     if (FSR.shouldStop())
55413cc256eSDimitry Andric       return true;
5553d1dcd9bSDimitry Andric       // Did we exhaust the string or encounter an error that
5563d1dcd9bSDimitry Andric       // we can recover from?
5573d1dcd9bSDimitry Andric     if (!FSR.hasValue())
5583d1dcd9bSDimitry Andric       continue;
5593d1dcd9bSDimitry Andric       // We have a format specifier.  Pass it to the callback.
5603d1dcd9bSDimitry Andric     if (!H.HandleScanfSpecifier(FSR.getValue(), FSR.getStart(),
5613d1dcd9bSDimitry Andric                                 I - FSR.getStart())) {
5623d1dcd9bSDimitry Andric       return true;
5633d1dcd9bSDimitry Andric     }
5643d1dcd9bSDimitry Andric   }
5653d1dcd9bSDimitry Andric   assert(I == E && "Format string not exhausted");
5663d1dcd9bSDimitry Andric   return false;
5673d1dcd9bSDimitry Andric }
568