static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, unsigned &argIndex, bool FormatExtensions) { using namespace clang::analyze_format_string; using namespace clang::analyze_printf; const char *I = Beg; const char *Start = 0; UpdateOnReturn <const char*> UpdateBeg(Beg, I); // Look for a '%' character that indicates the start of a format specifier. for ( ; I != E ; ++I) { char c = *I; if (c == '\0') { // Detect spurious null characters, which are likely errors. H.HandleNullChar(I); return true; } if (c == '%') { Start = I++; // Record the start of the format specifier. break; } } // No format specifier found? if (!Start) return false; if (I == E) { // No more characters left? H.HandleIncompleteSpecifier(Start, E - Start); return true; } PrintfSpecifier FS; if (ParseArgPosition(H, FS, Start, I, E)) return true; if (I == E) { // No more characters left? H.HandleIncompleteSpecifier(Start, E - Start); return true; } // Look for flags (if any). bool hasMore = true; for ( ; I != E; ++I) { switch (*I) { default: hasMore = false; break; case '-': FS.setIsLeftJustified(I); break; case '+': FS.setHasPlusPrefix(I); break; case ' ': FS.setHasSpacePrefix(I); break; case '#': FS.setHasAlternativeForm(I); break; case '0': FS.setHasLeadingZeros(I); break; } if (!hasMore) break; } if (I == E) { // No more characters left? H.HandleIncompleteSpecifier(Start, E - Start); return true; } // Look for the field width (if any). if (ParseFieldWidth(H, FS, Start, I, E, FS.usesPositionalArg() ? 0 : &argIndex)) return true; if (I == E) { // No more characters left? H.HandleIncompleteSpecifier(Start, E - Start); return true; } // Look for the precision (if any). if (*I == '.') { ++I; if (I == E) { H.HandleIncompleteSpecifier(Start, E - Start); return true; } if (ParsePrecision(H, FS, Start, I, E, FS.usesPositionalArg() ? 0 : &argIndex)) return true; if (I == E) { // No more characters left? H.HandleIncompleteSpecifier(Start, E - Start); return true; } } // Look for the length modifier. if (ParseLengthModifier(FS, I, E) && I == E) { // No more characters left? H.HandleIncompleteSpecifier(Start, E - Start); return true; } if (*I == '\0') { // Detect spurious null characters, which are likely errors. H.HandleNullChar(I); return true; } // Finally, look for the conversion specifier. const char *conversionPosition = I++; ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier; switch (*conversionPosition) { default: break; // C99: 7.19.6.1 (section 8). case '%': k = ConversionSpecifier::PercentArg; break; case 'A': k = ConversionSpecifier::AArg; break; case 'E': k = ConversionSpecifier::EArg; break; case 'F': k = ConversionSpecifier::FArg; break; case 'G': k = ConversionSpecifier::GArg; break; case 'X': k = ConversionSpecifier::XArg; break; case 'a': k = ConversionSpecifier::aArg; break; case 'c': k = ConversionSpecifier::cArg; break; case 'd': k = ConversionSpecifier::dArg; break; case 'e': k = ConversionSpecifier::eArg; break; case 'f': k = ConversionSpecifier::fArg; break; case 'g': k = ConversionSpecifier::gArg; break; case 'i': k = ConversionSpecifier::iArg; break; case 'n': k = ConversionSpecifier::nArg; break; case 'o': k = ConversionSpecifier::oArg; break; case 'p': k = ConversionSpecifier::pArg; break; case 's': k = ConversionSpecifier::sArg; break; case 'u': k = ConversionSpecifier::uArg; break; case 'x': k = ConversionSpecifier::xArg; break; // Mac OS X (unicode) specific case 'C': k = ConversionSpecifier::CArg; break; case 'S': k = ConversionSpecifier::SArg; break; // Objective-C. case '@': k = ConversionSpecifier::ObjCObjArg; break; // Glibc specific. case 'm': k = ConversionSpecifier::PrintErrno; break; // FreeBSD format extensions case 'b': if (FormatExtensions) k = ConversionSpecifier::bArg; break; /* check for int and then char * */ case 'r': if (FormatExtensions) k = ConversionSpecifier::rArg; break; case 'y': if (FormatExtensions) k = ConversionSpecifier::iArg; break; case 'D': if (FormatExtensions) k = ConversionSpecifier::DArg; break; /* check for u_char * pointer and a char * string */ } PrintfConversionSpecifier CS(conversionPosition, k); FS.setConversionSpecifier(CS); if (CS.consumesDataArgument() && !FS.usesPositionalArg()) FS.setArgIndex(argIndex++); // FreeBSD extension if (k == ConversionSpecifier::bArg || k == ConversionSpecifier::DArg) argIndex++; if (k == ConversionSpecifier::InvalidSpecifier) { // Assume the conversion takes one argument. return !H.HandleInvalidPrintfConversionSpecifier(FS, Beg, I - Beg); } return PrintfSpecifierResult(Start, FS); }
static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, unsigned &argIndex, const LangOptions &LO, const TargetInfo &Target, bool Warn, bool isFreeBSDKPrintf) { using namespace clang::analyze_format_string; using namespace clang::analyze_printf; const char *I = Beg; const char *Start = nullptr; UpdateOnReturn <const char*> UpdateBeg(Beg, I); // Look for a '%' character that indicates the start of a format specifier. for ( ; I != E ; ++I) { char c = *I; if (c == '\0') { // Detect spurious null characters, which are likely errors. H.HandleNullChar(I); return true; } if (c == '%') { Start = I++; // Record the start of the format specifier. break; } } // No format specifier found? if (!Start) return false; if (I == E) { // No more characters left? if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } PrintfSpecifier FS; if (ParseArgPosition(H, FS, Start, I, E)) return true; if (I == E) { // No more characters left? if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } const char *OSLogVisibilityFlagsStart = nullptr, *OSLogVisibilityFlagsEnd = nullptr; if (*I == '{') { OSLogVisibilityFlagsStart = I++; // Find the end of the modifier. while (I != E && *I != '}') { I++; } if (I == E) { if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } assert(*I == '}'); OSLogVisibilityFlagsEnd = I++; // Just see if 'private' or 'public' is the first word. os_log itself will // do any further parsing. const char *P = OSLogVisibilityFlagsStart + 1; while (P < OSLogVisibilityFlagsEnd && isspace(*P)) P++; const char *WordStart = P; while (P < OSLogVisibilityFlagsEnd && (isalnum(*P) || *P == '_')) P++; const char *WordEnd = P; StringRef Word(WordStart, WordEnd - WordStart); if (Word == "private") { FS.setIsPrivate(WordStart); } else if (Word == "public") { FS.setIsPublic(WordStart); } } // Look for flags (if any). bool hasMore = true; for ( ; I != E; ++I) { switch (*I) { default: hasMore = false; break; case '\'': // FIXME: POSIX specific. Always accept? FS.setHasThousandsGrouping(I); break; case '-': FS.setIsLeftJustified(I); break; case '+': FS.setHasPlusPrefix(I); break; case ' ': FS.setHasSpacePrefix(I); break; case '#': FS.setHasAlternativeForm(I); break; case '0': FS.setHasLeadingZeros(I); break; } if (!hasMore) break; } if (I == E) { // No more characters left? if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } // Look for the field width (if any). if (ParseFieldWidth(H, FS, Start, I, E, FS.usesPositionalArg() ? nullptr : &argIndex)) return true; if (I == E) { // No more characters left? if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } // Look for the precision (if any). if (*I == '.') { ++I; if (I == E) { if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } if (ParsePrecision(H, FS, Start, I, E, FS.usesPositionalArg() ? nullptr : &argIndex)) return true; if (I == E) { // No more characters left? if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } } // Look for the length modifier. if (ParseLengthModifier(FS, I, E, LO) && I == E) { // No more characters left? if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } // Look for the Objective-C modifier flags, if any. // We parse these here, even if they don't apply to // the conversion specifier, and then emit an error // later if the conversion specifier isn't '@'. This // enables better recovery, and we don't know if // these flags are applicable until later. const char *ObjCModifierFlagsStart = nullptr, *ObjCModifierFlagsEnd = nullptr; if (*I == '[') { ObjCModifierFlagsStart = I; ++I; auto flagStart = I; for (;; ++I) { ObjCModifierFlagsEnd = I; if (I == E) { if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } // Did we find the closing ']'? if (*I == ']') { if (ParseObjCFlags(H, FS, flagStart, I, Warn)) return true; ++I; break; } // There are no separators defined yet for multiple // Objective-C modifier flags. When those are // defined, this is the place to check. } } if (*I == '\0') { // Detect spurious null characters, which are likely errors. H.HandleNullChar(I); return true; } // Finally, look for the conversion specifier. const char *conversionPosition = I++; ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier; switch (*conversionPosition) { default: break; // C99: 7.19.6.1 (section 8). case '%': k = ConversionSpecifier::PercentArg; break; case 'A': k = ConversionSpecifier::AArg; break; case 'E': k = ConversionSpecifier::EArg; break; case 'F': k = ConversionSpecifier::FArg; break; case 'G': k = ConversionSpecifier::GArg; break; case 'X': k = ConversionSpecifier::XArg; break; case 'a': k = ConversionSpecifier::aArg; break; case 'c': k = ConversionSpecifier::cArg; break; case 'd': k = ConversionSpecifier::dArg; break; case 'e': k = ConversionSpecifier::eArg; break; case 'f': k = ConversionSpecifier::fArg; break; case 'g': k = ConversionSpecifier::gArg; break; case 'i': k = ConversionSpecifier::iArg; break; case 'n': k = ConversionSpecifier::nArg; break; case 'o': k = ConversionSpecifier::oArg; break; case 'p': k = ConversionSpecifier::pArg; break; case 's': k = ConversionSpecifier::sArg; break; case 'u': k = ConversionSpecifier::uArg; break; case 'x': k = ConversionSpecifier::xArg; break; // POSIX specific. case 'C': k = ConversionSpecifier::CArg; break; case 'S': k = ConversionSpecifier::SArg; break; // Apple extension for os_log case 'P': k = ConversionSpecifier::PArg; break; // Objective-C. case '@': k = ConversionSpecifier::ObjCObjArg; break; // Glibc specific. case 'm': k = ConversionSpecifier::PrintErrno; break; // FreeBSD kernel specific. case 'b': if (isFreeBSDKPrintf) k = ConversionSpecifier::FreeBSDbArg; // int followed by char * break; case 'r': if (isFreeBSDKPrintf) k = ConversionSpecifier::FreeBSDrArg; // int break; case 'y': if (isFreeBSDKPrintf) k = ConversionSpecifier::FreeBSDyArg; // int break; // Apple-specific. case 'D': if (isFreeBSDKPrintf) k = ConversionSpecifier::FreeBSDDArg; // void * followed by char * else if (Target.getTriple().isOSDarwin()) k = ConversionSpecifier::DArg; break; case 'O': if (Target.getTriple().isOSDarwin()) k = ConversionSpecifier::OArg; break; case 'U': if (Target.getTriple().isOSDarwin()) k = ConversionSpecifier::UArg; break; // MS specific. case 'Z': if (Target.getTriple().isOSMSVCRT()) k = ConversionSpecifier::ZArg; } // Check to see if we used the Objective-C modifier flags with // a conversion specifier other than '@'. if (k != ConversionSpecifier::ObjCObjArg && k != ConversionSpecifier::InvalidSpecifier && ObjCModifierFlagsStart) { H.HandleObjCFlagsWithNonObjCConversion(ObjCModifierFlagsStart, ObjCModifierFlagsEnd + 1, conversionPosition); return true; } PrintfConversionSpecifier CS(conversionPosition, k); FS.setConversionSpecifier(CS); if (CS.consumesDataArgument() && !FS.usesPositionalArg()) FS.setArgIndex(argIndex++); // FreeBSD kernel specific. if (k == ConversionSpecifier::FreeBSDbArg || k == ConversionSpecifier::FreeBSDDArg) argIndex++; if (k == ConversionSpecifier::InvalidSpecifier) { unsigned Len = I - Start; if (ParseUTF8InvalidSpecifier(Start, E, Len)) { CS.setEndScanList(Start + Len); FS.setConversionSpecifier(CS); } // Assume the conversion takes one argument. return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len); } return PrintfSpecifierResult(Start, FS); }
static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, unsigned &argIndex, const LangOptions &LO, const TargetInfo &Target, bool Warn, bool isFreeBSDKPrintf) { using namespace clang::analyze_format_string; using namespace clang::analyze_printf; const char *I = Beg; const char *Start = nullptr; UpdateOnReturn <const char*> UpdateBeg(Beg, I); // Look for a '%' character that indicates the start of a format specifier. for ( ; I != E ; ++I) { char c = *I; if (c == '\0') { // Detect spurious null characters, which are likely errors. H.HandleNullChar(I); return true; } if (c == '%') { Start = I++; // Record the start of the format specifier. break; } } // No format specifier found? if (!Start) return false; if (I == E) { // No more characters left? if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } PrintfSpecifier FS; if (ParseArgPosition(H, FS, Start, I, E)) return true; if (I == E) { // No more characters left? if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } if (*I == '{') { ++I; unsigned char PrivacyFlags = 0; StringRef MatchedStr; do { StringRef Str(I, E - I); std::string Match = "^[\t\n\v\f\r ]*(private|public)[\t\n\v\f\r ]*(,|})"; llvm::Regex R(Match); SmallVector<StringRef, 2> Matches; if (R.match(Str, &Matches)) { MatchedStr = Matches[1]; I += Matches[0].size(); // Set the privacy flag if the privacy annotation in the // comma-delimited segment is at least as strict as the privacy // annotations in previous comma-delimited segments. if (MatchedStr.equals("private")) PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPrivate; else if (PrivacyFlags == 0 && MatchedStr.equals("public")) PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPublic; } else { size_t CommaOrBracePos = Str.find_if([](char c) { return c == ',' || c == '}'; }); if (CommaOrBracePos == StringRef::npos) { // Neither a comma nor the closing brace was found. if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } I += CommaOrBracePos + 1; } // Continue until the closing brace is found. } while (*(I - 1) == ','); // Set the privacy flag. switch (PrivacyFlags) { case 0: break; case clang::analyze_os_log::OSLogBufferItem::IsPrivate: FS.setIsPrivate(MatchedStr.data()); break; case clang::analyze_os_log::OSLogBufferItem::IsPublic: FS.setIsPublic(MatchedStr.data()); break; default: llvm_unreachable("Unexpected privacy flag value"); } } // Look for flags (if any). bool hasMore = true; for ( ; I != E; ++I) { switch (*I) { default: hasMore = false; break; case '\'': // FIXME: POSIX specific. Always accept? FS.setHasThousandsGrouping(I); break; case '-': FS.setIsLeftJustified(I); break; case '+': FS.setHasPlusPrefix(I); break; case ' ': FS.setHasSpacePrefix(I); break; case '#': FS.setHasAlternativeForm(I); break; case '0': FS.setHasLeadingZeros(I); break; } if (!hasMore) break; } if (I == E) { // No more characters left? if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } // Look for the field width (if any). if (ParseFieldWidth(H, FS, Start, I, E, FS.usesPositionalArg() ? nullptr : &argIndex)) return true; if (I == E) { // No more characters left? if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } // Look for the precision (if any). if (*I == '.') { ++I; if (I == E) { if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } if (ParsePrecision(H, FS, Start, I, E, FS.usesPositionalArg() ? nullptr : &argIndex)) return true; if (I == E) { // No more characters left? if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } } // Look for the length modifier. if (ParseLengthModifier(FS, I, E, LO) && I == E) { // No more characters left? if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } // Look for the Objective-C modifier flags, if any. // We parse these here, even if they don't apply to // the conversion specifier, and then emit an error // later if the conversion specifier isn't '@'. This // enables better recovery, and we don't know if // these flags are applicable until later. const char *ObjCModifierFlagsStart = nullptr, *ObjCModifierFlagsEnd = nullptr; if (*I == '[') { ObjCModifierFlagsStart = I; ++I; auto flagStart = I; for (;; ++I) { ObjCModifierFlagsEnd = I; if (I == E) { if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } // Did we find the closing ']'? if (*I == ']') { if (ParseObjCFlags(H, FS, flagStart, I, Warn)) return true; ++I; break; } // There are no separators defined yet for multiple // Objective-C modifier flags. When those are // defined, this is the place to check. } } if (*I == '\0') { // Detect spurious null characters, which are likely errors. H.HandleNullChar(I); return true; } // Finally, look for the conversion specifier. const char *conversionPosition = I++; ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier; switch (*conversionPosition) { default: break; // C99: 7.19.6.1 (section 8). case '%': k = ConversionSpecifier::PercentArg; break; case 'A': k = ConversionSpecifier::AArg; break; case 'E': k = ConversionSpecifier::EArg; break; case 'F': k = ConversionSpecifier::FArg; break; case 'G': k = ConversionSpecifier::GArg; break; case 'X': k = ConversionSpecifier::XArg; break; case 'a': k = ConversionSpecifier::aArg; break; case 'c': k = ConversionSpecifier::cArg; break; case 'd': k = ConversionSpecifier::dArg; break; case 'e': k = ConversionSpecifier::eArg; break; case 'f': k = ConversionSpecifier::fArg; break; case 'g': k = ConversionSpecifier::gArg; break; case 'i': k = ConversionSpecifier::iArg; break; case 'n': k = ConversionSpecifier::nArg; break; case 'o': k = ConversionSpecifier::oArg; break; case 'p': k = ConversionSpecifier::pArg; break; case 's': k = ConversionSpecifier::sArg; break; case 'u': k = ConversionSpecifier::uArg; break; case 'x': k = ConversionSpecifier::xArg; break; // POSIX specific. case 'C': k = ConversionSpecifier::CArg; break; case 'S': k = ConversionSpecifier::SArg; break; // Apple extension for os_log case 'P': k = ConversionSpecifier::PArg; break; // Objective-C. case '@': k = ConversionSpecifier::ObjCObjArg; break; // Glibc specific. case 'm': k = ConversionSpecifier::PrintErrno; break; // FreeBSD kernel specific. case 'b': if (isFreeBSDKPrintf) k = ConversionSpecifier::FreeBSDbArg; // int followed by char * break; case 'r': if (isFreeBSDKPrintf) k = ConversionSpecifier::FreeBSDrArg; // int break; case 'y': if (isFreeBSDKPrintf) k = ConversionSpecifier::FreeBSDyArg; // int break; // Apple-specific. case 'D': if (isFreeBSDKPrintf) k = ConversionSpecifier::FreeBSDDArg; // void * followed by char * else if (Target.getTriple().isOSDarwin()) k = ConversionSpecifier::DArg; break; case 'O': if (Target.getTriple().isOSDarwin()) k = ConversionSpecifier::OArg; break; case 'U': if (Target.getTriple().isOSDarwin()) k = ConversionSpecifier::UArg; break; // MS specific. case 'Z': if (Target.getTriple().isOSMSVCRT()) k = ConversionSpecifier::ZArg; } // Check to see if we used the Objective-C modifier flags with // a conversion specifier other than '@'. if (k != ConversionSpecifier::ObjCObjArg && k != ConversionSpecifier::InvalidSpecifier && ObjCModifierFlagsStart) { H.HandleObjCFlagsWithNonObjCConversion(ObjCModifierFlagsStart, ObjCModifierFlagsEnd + 1, conversionPosition); return true; } PrintfConversionSpecifier CS(conversionPosition, k); FS.setConversionSpecifier(CS); if (CS.consumesDataArgument() && !FS.usesPositionalArg()) FS.setArgIndex(argIndex++); // FreeBSD kernel specific. if (k == ConversionSpecifier::FreeBSDbArg || k == ConversionSpecifier::FreeBSDDArg) argIndex++; if (k == ConversionSpecifier::InvalidSpecifier) { unsigned Len = I - Start; if (ParseUTF8InvalidSpecifier(Start, E, Len)) { CS.setEndScanList(Start + Len); FS.setConversionSpecifier(CS); } // Assume the conversion takes one argument. return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len); } return PrintfSpecifierResult(Start, FS); }