r345971 - Reapply Logging: make os_log buffer size an integer constant expression.
Sam McCall via cfe-commits
cfe-commits at lists.llvm.org
Fri Nov 2 06:31:38 PDT 2018
The move of OSLog.h and FormatString.h to AST doesn't look obviously
correct.
Do these really belong in this layer? I think this patch needs review from
someone who knows AST/ better than myself... was there a review?
(If the do belong here: the namespaces and comments don't seem to have been
updated)
On Fri, Nov 2, 2018 at 2:16 PM Tim Northover via cfe-commits <
cfe-commits at lists.llvm.org> wrote:
> Author: tnorthover
> Date: Fri Nov 2 06:14:11 2018
> New Revision: 345971
>
> URL: http://llvm.org/viewvc/llvm-project?rev=345971&view=rev
> Log:
> Reapply Logging: make os_log buffer size an integer constant expression.
>
> The size of an os_log buffer is known at any stage of compilation, so
> making it
> a constant expression means that the common idiom of declaring a buffer
> for it
> won't result in a VLA. That allows the compiler to skip saving and
> restoring
> the stack pointer around such buffers.
>
> This also moves the OSLog and other FormatString helpers from
> libclangAnalysis to libclangAST to avoid a circular dependency.
>
> Added:
> cfe/trunk/include/clang/AST/FormatString.h
> cfe/trunk/include/clang/AST/OSLog.h
> cfe/trunk/lib/AST/FormatString.cpp
> cfe/trunk/lib/AST/FormatStringParsing.h
> cfe/trunk/lib/AST/OSLog.cpp
> cfe/trunk/lib/AST/PrintfFormatString.cpp
> cfe/trunk/lib/AST/ScanfFormatString.cpp
> Removed:
> cfe/trunk/include/clang/Analysis/Analyses/FormatString.h
> cfe/trunk/include/clang/Analysis/Analyses/OSLog.h
> cfe/trunk/lib/Analysis/FormatString.cpp
> cfe/trunk/lib/Analysis/FormatStringParsing.h
> cfe/trunk/lib/Analysis/OSLog.cpp
> cfe/trunk/lib/Analysis/PrintfFormatString.cpp
> cfe/trunk/lib/Analysis/ScanfFormatString.cpp
> Modified:
> cfe/trunk/lib/AST/CMakeLists.txt
> cfe/trunk/lib/AST/ExprConstant.cpp
> cfe/trunk/lib/Analysis/CMakeLists.txt
> cfe/trunk/lib/CodeGen/CGBuiltin.cpp
> cfe/trunk/lib/Sema/SemaChecking.cpp
> cfe/trunk/test/CodeGen/builtins.c
>
> Added: cfe/trunk/include/clang/AST/FormatString.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/FormatString.h?rev=345971&view=auto
>
> ==============================================================================
> --- cfe/trunk/include/clang/AST/FormatString.h (added)
> +++ cfe/trunk/include/clang/AST/FormatString.h Fri Nov 2 06:14:11 2018
> @@ -0,0 +1,719 @@
> +//= FormatString.h - Analysis of printf/fprintf format strings --*- C++
> -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// This file defines APIs for analyzing the format strings of printf,
> fscanf,
> +// and friends.
> +//
> +// The structure of format strings for fprintf are described in C99
> 7.19.6.1.
> +//
> +// The structure of format strings for fscanf are described in C99
> 7.19.6.2.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H
> +#define LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H
> +
> +#include "clang/AST/CanonicalType.h"
> +
> +namespace clang {
> +
> +class TargetInfo;
> +
>
> +//===----------------------------------------------------------------------===//
> +/// Common components of both fprintf and fscanf format strings.
> +namespace analyze_format_string {
> +
> +/// Class representing optional flags with location and representation
> +/// information.
> +class OptionalFlag {
> +public:
> + OptionalFlag(const char *Representation)
> + : representation(Representation), flag(false) {}
> + bool isSet() const { return flag; }
> + void set() { flag = true; }
> + void clear() { flag = false; }
> + void setPosition(const char *position) {
> + assert(position);
> + flag = true;
> + this->position = position;
> + }
> + const char *getPosition() const {
> + assert(position);
> + return position;
> + }
> + const char *toString() const { return representation; }
> +
> + // Overloaded operators for bool like qualities
> + explicit operator bool() const { return flag; }
> + OptionalFlag& operator=(const bool &rhs) {
> + flag = rhs;
> + return *this; // Return a reference to myself.
> + }
> +private:
> + const char *representation;
> + const char *position;
> + bool flag;
> +};
> +
> +/// Represents the length modifier in a format string in scanf/printf.
> +class LengthModifier {
> +public:
> + enum Kind {
> + None,
> + AsChar, // 'hh'
> + AsShort, // 'h'
> + AsLong, // 'l'
> + AsLongLong, // 'll'
> + AsQuad, // 'q' (BSD, deprecated, for 64-bit integer types)
> + AsIntMax, // 'j'
> + AsSizeT, // 'z'
> + AsPtrDiff, // 't'
> + AsInt32, // 'I32' (MSVCRT, like __int32)
> + AsInt3264, // 'I' (MSVCRT, like __int3264 from MIDL)
> + AsInt64, // 'I64' (MSVCRT, like __int64)
> + AsLongDouble, // 'L'
> + AsAllocate, // for '%as', GNU extension to C90 scanf
> + AsMAllocate, // for '%ms', GNU extension to scanf
> + AsWide, // 'w' (MSVCRT, like l but only for c, C, s, S, or Z
> + AsWideChar = AsLong // for '%ls', only makes sense for printf
> + };
> +
> + LengthModifier()
> + : Position(nullptr), kind(None) {}
> + LengthModifier(const char *pos, Kind k)
> + : Position(pos), kind(k) {}
> +
> + const char *getStart() const {
> + return Position;
> + }
> +
> + unsigned getLength() const {
> + switch (kind) {
> + default:
> + return 1;
> + case AsLongLong:
> + case AsChar:
> + return 2;
> + case AsInt32:
> + case AsInt64:
> + return 3;
> + case None:
> + return 0;
> + }
> + }
> +
> + Kind getKind() const { return kind; }
> + void setKind(Kind k) { kind = k; }
> +
> + const char *toString() const;
> +
> +private:
> + const char *Position;
> + Kind kind;
> +};
> +
> +class ConversionSpecifier {
> +public:
> + enum Kind {
> + InvalidSpecifier = 0,
> + // C99 conversion specifiers.
> + cArg,
> + dArg,
> + DArg, // Apple extension
> + iArg,
> + IntArgBeg = dArg,
> + IntArgEnd = iArg,
> +
> + oArg,
> + OArg, // Apple extension
> + uArg,
> + UArg, // Apple extension
> + xArg,
> + XArg,
> + UIntArgBeg = oArg,
> + UIntArgEnd = XArg,
> +
> + fArg,
> + FArg,
> + eArg,
> + EArg,
> + gArg,
> + GArg,
> + aArg,
> + AArg,
> + DoubleArgBeg = fArg,
> + DoubleArgEnd = AArg,
> +
> + sArg,
> + pArg,
> + nArg,
> + PercentArg,
> + CArg,
> + SArg,
> +
> + // Apple extension: P specifies to os_log that the data being pointed
> to is
> + // to be copied by os_log. The precision indicates the number of
> bytes to
> + // copy.
> + PArg,
> +
> + // ** Printf-specific **
> +
> + ZArg, // MS extension
> +
> + // Objective-C specific specifiers.
> + ObjCObjArg, // '@'
> + ObjCBeg = ObjCObjArg,
> + ObjCEnd = ObjCObjArg,
> +
> + // FreeBSD kernel specific specifiers.
> + FreeBSDbArg,
> + FreeBSDDArg,
> + FreeBSDrArg,
> + FreeBSDyArg,
> +
> + // GlibC specific specifiers.
> + PrintErrno, // 'm'
> +
> + PrintfConvBeg = ObjCObjArg,
> + PrintfConvEnd = PrintErrno,
> +
> + // ** Scanf-specific **
> + ScanListArg, // '['
> + ScanfConvBeg = ScanListArg,
> + ScanfConvEnd = ScanListArg
> + };
> +
> + ConversionSpecifier(bool isPrintf = true)
> + : IsPrintf(isPrintf), Position(nullptr), EndScanList(nullptr),
> + kind(InvalidSpecifier) {}
> +
> + ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
> + : IsPrintf(isPrintf), Position(pos), EndScanList(nullptr), kind(k) {}
> +
> + const char *getStart() const {
> + return Position;
> + }
> +
> + StringRef getCharacters() const {
> + return StringRef(getStart(), getLength());
> + }
> +
> + bool consumesDataArgument() const {
> + switch (kind) {
> + case PrintErrno:
> + assert(IsPrintf);
> + return false;
> + case PercentArg:
> + return false;
> + case InvalidSpecifier:
> + return false;
> + default:
> + return true;
> + }
> + }
> +
> + Kind getKind() const { return kind; }
> + void setKind(Kind k) { kind = k; }
> + unsigned getLength() const {
> + return EndScanList ? EndScanList - Position : 1;
> + }
> + void setEndScanList(const char *pos) { EndScanList = pos; }
> +
> + bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd)
> ||
> + kind == FreeBSDrArg || kind == FreeBSDyArg; }
> + bool isUIntArg() const { return kind >= UIntArgBeg && kind <=
> UIntArgEnd; }
> + bool isAnyIntArg() const { return kind >= IntArgBeg && kind <=
> UIntArgEnd; }
> + bool isDoubleArg() const {
> + return kind >= DoubleArgBeg && kind <= DoubleArgEnd;
> + }
> +
> + const char *toString() const;
> +
> + bool isPrintfKind() const { return IsPrintf; }
> +
> + Optional<ConversionSpecifier> getStandardSpecifier() const;
> +
> +protected:
> + bool IsPrintf;
> + const char *Position;
> + const char *EndScanList;
> + Kind kind;
> +};
> +
> +class ArgType {
> +public:
> + enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
> + AnyCharTy, CStrTy, WCStrTy, WIntTy };
> +
> + enum MatchKind { NoMatch = 0, Match = 1, NoMatchPedantic };
> +
> +private:
> + const Kind K;
> + QualType T;
> + const char *Name = nullptr;
> + bool Ptr = false;
> +
> + /// The TypeKind identifies certain well-known types like size_t and
> + /// ptrdiff_t.
> + enum class TypeKind { DontCare, SizeT, PtrdiffT };
> + TypeKind TK = TypeKind::DontCare;
> +
> +public:
> + ArgType(Kind K = UnknownTy, const char *N = nullptr) : K(K), Name(N) {}
> + ArgType(QualType T, const char *N = nullptr) : K(SpecificTy), T(T),
> Name(N) {}
> + ArgType(CanQualType T) : K(SpecificTy), T(T) {}
> +
> + static ArgType Invalid() { return ArgType(InvalidTy); }
> + bool isValid() const { return K != InvalidTy; }
> +
> + bool isSizeT() const { return TK == TypeKind::SizeT; }
> +
> + bool isPtrdiffT() const { return TK == TypeKind::PtrdiffT; }
> +
> + /// Create an ArgType which corresponds to the type pointer to A.
> + static ArgType PtrTo(const ArgType& A) {
> + assert(A.K >= InvalidTy && "ArgType cannot be pointer to
> invalid/unknown");
> + ArgType Res = A;
> + Res.Ptr = true;
> + return Res;
> + }
> +
> + /// Create an ArgType which corresponds to the size_t/ssize_t type.
> + static ArgType makeSizeT(const ArgType &A) {
> + ArgType Res = A;
> + Res.TK = TypeKind::SizeT;
> + return Res;
> + }
> +
> + /// Create an ArgType which corresponds to the ptrdiff_t/unsigned
> ptrdiff_t
> + /// type.
> + static ArgType makePtrdiffT(const ArgType &A) {
> + ArgType Res = A;
> + Res.TK = TypeKind::PtrdiffT;
> + return Res;
> + }
> +
> + MatchKind matchesType(ASTContext &C, QualType argTy) const;
> +
> + QualType getRepresentativeType(ASTContext &C) const;
> +
> + std::string getRepresentativeTypeName(ASTContext &C) const;
> +};
> +
> +class OptionalAmount {
> +public:
> + enum HowSpecified { NotSpecified, Constant, Arg, Invalid };
> +
> + OptionalAmount(HowSpecified howSpecified,
> + unsigned amount,
> + const char *amountStart,
> + unsigned amountLength,
> + bool usesPositionalArg)
> + : start(amountStart), length(amountLength), hs(howSpecified),
> amt(amount),
> + UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {}
> +
> + OptionalAmount(bool valid = true)
> + : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
> + UsesPositionalArg(0), UsesDotPrefix(0) {}
> +
> + bool isInvalid() const {
> + return hs == Invalid;
> + }
> +
> + HowSpecified getHowSpecified() const { return hs; }
> + void setHowSpecified(HowSpecified h) { hs = h; }
> +
> + bool hasDataArgument() const { return hs == Arg; }
> +
> + unsigned getArgIndex() const {
> + assert(hasDataArgument());
> + return amt;
> + }
> +
> + unsigned getConstantAmount() const {
> + assert(hs == Constant);
> + return amt;
> + }
> +
> + const char *getStart() const {
> + // We include the . character if it is given.
> + return start - UsesDotPrefix;
> + }
> +
> + unsigned getConstantLength() const {
> + assert(hs == Constant);
> + return length + UsesDotPrefix;
> + }
> +
> + ArgType getArgType(ASTContext &Ctx) const;
> +
> + void toString(raw_ostream &os) const;
> +
> + bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
> + unsigned getPositionalArgIndex() const {
> + assert(hasDataArgument());
> + return amt + 1;
> + }
> +
> + bool usesDotPrefix() const { return UsesDotPrefix; }
> + void setUsesDotPrefix() { UsesDotPrefix = true; }
> +
> +private:
> + const char *start;
> + unsigned length;
> + HowSpecified hs;
> + unsigned amt;
> + bool UsesPositionalArg : 1;
> + bool UsesDotPrefix;
> +};
> +
> +
> +class FormatSpecifier {
> +protected:
> + LengthModifier LM;
> + OptionalAmount FieldWidth;
> + ConversionSpecifier CS;
> + /// Positional arguments, an IEEE extension:
> + /// IEEE Std 1003.1, 2004 Edition
> + ///
> http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
> + bool UsesPositionalArg;
> + unsigned argIndex;
> +public:
> + FormatSpecifier(bool isPrintf)
> + : CS(isPrintf), UsesPositionalArg(false), argIndex(0) {}
> +
> + void setLengthModifier(LengthModifier lm) {
> + LM = lm;
> + }
> +
> + void setUsesPositionalArg() { UsesPositionalArg = true; }
> +
> + void setArgIndex(unsigned i) {
> + argIndex = i;
> + }
> +
> + unsigned getArgIndex() const {
> + return argIndex;
> + }
> +
> + unsigned getPositionalArgIndex() const {
> + return argIndex + 1;
> + }
> +
> + const LengthModifier &getLengthModifier() const {
> + return LM;
> + }
> +
> + const OptionalAmount &getFieldWidth() const {
> + return FieldWidth;
> + }
> +
> + void setFieldWidth(const OptionalAmount &Amt) {
> + FieldWidth = Amt;
> + }
> +
> + bool usesPositionalArg() const { return UsesPositionalArg; }
> +
> + bool hasValidLengthModifier(const TargetInfo &Target) const;
> +
> + bool hasStandardLengthModifier() const;
> +
> + Optional<LengthModifier> getCorrectedLengthModifier() const;
> +
> + bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
> +
> + bool hasStandardLengthConversionCombination() const;
> +
> + /// For a TypedefType QT, if it is a named integer type such as size_t,
> + /// assign the appropriate value to LM and return true.
> + static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM);
> +};
> +
> +} // end analyze_format_string namespace
> +
>
> +//===----------------------------------------------------------------------===//
> +/// Pieces specific to fprintf format strings.
> +
> +namespace analyze_printf {
> +
> +class PrintfConversionSpecifier :
> + public analyze_format_string::ConversionSpecifier {
> +public:
> + PrintfConversionSpecifier()
> + : ConversionSpecifier(true, nullptr, InvalidSpecifier) {}
> +
> + PrintfConversionSpecifier(const char *pos, Kind k)
> + : ConversionSpecifier(true, pos, k) {}
> +
> + bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
> + bool isDoubleArg() const { return kind >= DoubleArgBeg &&
> + kind <= DoubleArgEnd; }
> +
> + static bool classof(const analyze_format_string::ConversionSpecifier
> *CS) {
> + return CS->isPrintfKind();
> + }
> +};
> +
> +using analyze_format_string::ArgType;
> +using analyze_format_string::LengthModifier;
> +using analyze_format_string::OptionalAmount;
> +using analyze_format_string::OptionalFlag;
> +
> +class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
> + OptionalFlag HasThousandsGrouping; // ''', POSIX extension.
> + OptionalFlag IsLeftJustified; // '-'
> + OptionalFlag HasPlusPrefix; // '+'
> + OptionalFlag HasSpacePrefix; // ' '
> + OptionalFlag HasAlternativeForm; // '#'
> + OptionalFlag HasLeadingZeroes; // '0'
> + OptionalFlag HasObjCTechnicalTerm; // '[tt]'
> + OptionalFlag IsPrivate; // '{private}'
> + OptionalFlag IsPublic; // '{public}'
> + OptionalAmount Precision;
> +public:
> + PrintfSpecifier()
> + : FormatSpecifier(/* isPrintf = */ true), HasThousandsGrouping("'"),
> + IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "),
> + HasAlternativeForm("#"), HasLeadingZeroes("0"),
> + HasObjCTechnicalTerm("tt"), IsPrivate("private"),
> IsPublic("public") {}
> +
> + static PrintfSpecifier Parse(const char *beg, const char *end);
> +
> + // Methods for incrementally constructing the PrintfSpecifier.
> + void setConversionSpecifier(const PrintfConversionSpecifier &cs) {
> + CS = cs;
> + }
> + void setHasThousandsGrouping(const char *position) {
> + HasThousandsGrouping.setPosition(position);
> + }
> + void setIsLeftJustified(const char *position) {
> + IsLeftJustified.setPosition(position);
> + }
> + void setHasPlusPrefix(const char *position) {
> + HasPlusPrefix.setPosition(position);
> + }
> + void setHasSpacePrefix(const char *position) {
> + HasSpacePrefix.setPosition(position);
> + }
> + void setHasAlternativeForm(const char *position) {
> + HasAlternativeForm.setPosition(position);
> + }
> + void setHasLeadingZeros(const char *position) {
> + HasLeadingZeroes.setPosition(position);
> + }
> + void setHasObjCTechnicalTerm(const char *position) {
> + HasObjCTechnicalTerm.setPosition(position);
> + }
> + void setIsPrivate(const char *position) {
> IsPrivate.setPosition(position); }
> + void setIsPublic(const char *position) {
> IsPublic.setPosition(position); }
> + void setUsesPositionalArg() { UsesPositionalArg = true; }
> +
> + // Methods for querying the format specifier.
> +
> + const PrintfConversionSpecifier &getConversionSpecifier() const {
> + return cast<PrintfConversionSpecifier>(CS);
> + }
> +
> + void setPrecision(const OptionalAmount &Amt) {
> + Precision = Amt;
> + Precision.setUsesDotPrefix();
> + }
> +
> + const OptionalAmount &getPrecision() const {
> + return Precision;
> + }
> +
> + bool consumesDataArgument() const {
> + return getConversionSpecifier().consumesDataArgument();
> + }
> +
> + /// Returns the builtin type that a data argument
> + /// paired with this format specifier should have. This method
> + /// will return null if the format specifier does not have
> + /// a matching data argument or the matching argument matches
> + /// more than one type.
> + ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
> +
> + const OptionalFlag &hasThousandsGrouping() const {
> + return HasThousandsGrouping;
> + }
> + const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
> + const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }
> + const OptionalFlag &hasAlternativeForm() const { return
> HasAlternativeForm; }
> + const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; }
> + const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }
> + const OptionalFlag &hasObjCTechnicalTerm() const { return
> HasObjCTechnicalTerm; }
> + const OptionalFlag &isPrivate() const { return IsPrivate; }
> + const OptionalFlag &isPublic() const { return IsPublic; }
> + bool usesPositionalArg() const { return UsesPositionalArg; }
> +
> + /// Changes the specifier and length according to a QualType, retaining
> any
> + /// flags or options. Returns true on success, or false when a
> conversion
> + /// was not successful.
> + bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx,
> + bool IsObjCLiteral);
> +
> + void toString(raw_ostream &os) const;
> +
> + // Validation methods - to check if any element results in undefined
> behavior
> + bool hasValidPlusPrefix() const;
> + bool hasValidAlternativeForm() const;
> + bool hasValidLeadingZeros() const;
> + bool hasValidSpacePrefix() const;
> + bool hasValidLeftJustified() const;
> + bool hasValidThousandsGroupingPrefix() const;
> +
> + bool hasValidPrecision() const;
> + bool hasValidFieldWidth() const;
> +};
> +} // end analyze_printf namespace
> +
>
> +//===----------------------------------------------------------------------===//
> +/// Pieces specific to fscanf format strings.
> +
> +namespace analyze_scanf {
> +
> +class ScanfConversionSpecifier :
> + public analyze_format_string::ConversionSpecifier {
> +public:
> + ScanfConversionSpecifier()
> + : ConversionSpecifier(false, nullptr, InvalidSpecifier) {}
> +
> + ScanfConversionSpecifier(const char *pos, Kind k)
> + : ConversionSpecifier(false, pos, k) {}
> +
> + static bool classof(const analyze_format_string::ConversionSpecifier
> *CS) {
> + return !CS->isPrintfKind();
> + }
> +};
> +
> +using analyze_format_string::ArgType;
> +using analyze_format_string::LengthModifier;
> +using analyze_format_string::OptionalAmount;
> +using analyze_format_string::OptionalFlag;
> +
> +class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
> + OptionalFlag SuppressAssignment; // '*'
> +public:
> + ScanfSpecifier() :
> + FormatSpecifier(/* isPrintf = */ false),
> + SuppressAssignment("*") {}
> +
> + void setSuppressAssignment(const char *position) {
> + SuppressAssignment.setPosition(position);
> + }
> +
> + const OptionalFlag &getSuppressAssignment() const {
> + return SuppressAssignment;
> + }
> +
> + void setConversionSpecifier(const ScanfConversionSpecifier &cs) {
> + CS = cs;
> + }
> +
> + const ScanfConversionSpecifier &getConversionSpecifier() const {
> + return cast<ScanfConversionSpecifier>(CS);
> + }
> +
> + bool consumesDataArgument() const {
> + return CS.consumesDataArgument() && !SuppressAssignment;
> + }
> +
> + ArgType getArgType(ASTContext &Ctx) const;
> +
> + bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt,
> + ASTContext &Ctx);
> +
> + void toString(raw_ostream &os) const;
> +
> + static ScanfSpecifier Parse(const char *beg, const char *end);
> +};
> +
> +} // end analyze_scanf namespace
> +
>
> +//===----------------------------------------------------------------------===//
> +// Parsing and processing of format strings (both fprintf and fscanf).
> +
> +namespace analyze_format_string {
> +
> +enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 };
> +
> +class FormatStringHandler {
> +public:
> + FormatStringHandler() {}
> + virtual ~FormatStringHandler();
> +
> + virtual void HandleNullChar(const char *nullCharacter) {}
> +
> + virtual void HandlePosition(const char *startPos, unsigned posLen) {}
> +
> + virtual void HandleInvalidPosition(const char *startPos, unsigned
> posLen,
> + PositionContext p) {}
> +
> + virtual void HandleZeroPosition(const char *startPos, unsigned posLen)
> {}
> +
> + virtual void HandleIncompleteSpecifier(const char *startSpecifier,
> + unsigned specifierLen) {}
> +
> + virtual void HandleEmptyObjCModifierFlag(const char *startFlags,
> + unsigned flagsLen) {}
> +
> + virtual void HandleInvalidObjCModifierFlag(const char *startFlag,
> + unsigned flagLen) {}
> +
> + virtual void HandleObjCFlagsWithNonObjCConversion(const char
> *flagsStart,
> + const char *flagsEnd,
> + const char
> *conversionPosition) {}
> + // Printf-specific handlers.
> +
> + virtual bool HandleInvalidPrintfConversionSpecifier(
> + const
> analyze_printf::PrintfSpecifier &FS,
> + const char *startSpecifier,
> + unsigned specifierLen) {
> + return true;
> + }
> +
> + virtual bool HandlePrintfSpecifier(const
> analyze_printf::PrintfSpecifier &FS,
> + const char *startSpecifier,
> + unsigned specifierLen) {
> + return true;
> + }
> +
> + // Scanf-specific handlers.
> +
> + virtual bool HandleInvalidScanfConversionSpecifier(
> + const
> analyze_scanf::ScanfSpecifier &FS,
> + const char *startSpecifier,
> + unsigned specifierLen) {
> + return true;
> + }
> +
> + virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier
> &FS,
> + const char *startSpecifier,
> + unsigned specifierLen) {
> + return true;
> + }
> +
> + virtual void HandleIncompleteScanList(const char *start, const char
> *end) {}
> +};
> +
> +bool ParsePrintfString(FormatStringHandler &H,
> + const char *beg, const char *end, const
> LangOptions &LO,
> + const TargetInfo &Target, bool isFreeBSDKPrintf);
> +
> +bool ParseFormatStringHasSArg(const char *beg, const char *end,
> + const LangOptions &LO, const TargetInfo
> &Target);
> +
> +bool ParseScanfString(FormatStringHandler &H,
> + const char *beg, const char *end, const LangOptions
> &LO,
> + const TargetInfo &Target);
> +
> +} // end analyze_format_string namespace
> +} // end clang namespace
> +#endif
>
> Added: cfe/trunk/include/clang/AST/OSLog.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/OSLog.h?rev=345971&view=auto
>
> ==============================================================================
> --- cfe/trunk/include/clang/AST/OSLog.h (added)
> +++ cfe/trunk/include/clang/AST/OSLog.h Fri Nov 2 06:14:11 2018
> @@ -0,0 +1,155 @@
> +//= OSLog.h - Analysis of calls to os_log builtins --*- C++
> -*-===============//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// This file defines APIs for determining the layout of the data buffer
> for
> +// os_log() and os_trace().
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H
> +#define LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H
> +
> +#include "clang/AST/ASTContext.h"
> +#include "clang/AST/Expr.h"
> +
> +namespace clang {
> +namespace analyze_os_log {
> +
> +/// An OSLogBufferItem represents a single item in the data written by a
> call
> +/// to os_log() or os_trace().
> +class OSLogBufferItem {
> +public:
> + enum Kind {
> + // The item is a scalar (int, float, raw pointer, etc.). No further
> copying
> + // is required. This is the only kind allowed by os_trace().
> + ScalarKind = 0,
> +
> + // The item is a count, which describes the length of the following
> item to
> + // be copied. A count may only be followed by an item of kind
> StringKind,
> + // WideStringKind, or PointerKind.
> + CountKind,
> +
> + // The item is a pointer to a C string. If preceded by a count 'n',
> + // os_log() will copy at most 'n' bytes from the pointer.
> + StringKind,
> +
> + // The item is a pointer to a block of raw data. This item must be
> preceded
> + // by a count 'n'. os_log() will copy exactly 'n' bytes from the
> pointer.
> + PointerKind,
> +
> + // The item is a pointer to an Objective-C object. os_log() may
> retain the
> + // object for later processing.
> + ObjCObjKind,
> +
> + // The item is a pointer to wide-char string.
> + WideStringKind,
> +
> + // The item is corresponding to the '%m' format specifier, no value is
> + // populated in the buffer and the runtime is loading the errno value.
> + ErrnoKind
> + };
> +
> + enum {
> + // The item is marked "private" in the format string.
> + IsPrivate = 0x1,
> +
> + // The item is marked "public" in the format string.
> + IsPublic = 0x2
> + };
> +
> +private:
> + Kind TheKind = ScalarKind;
> + const Expr *TheExpr = nullptr;
> + CharUnits ConstValue;
> + CharUnits Size; // size of the data, not including the header bytes
> + unsigned Flags = 0;
> +
> +public:
> + OSLogBufferItem(Kind kind, const Expr *expr, CharUnits size, unsigned
> flags)
> + : TheKind(kind), TheExpr(expr), Size(size), Flags(flags) {}
> +
> + OSLogBufferItem(ASTContext &Ctx, CharUnits value, unsigned flags)
> + : TheKind(CountKind), ConstValue(value),
> + Size(Ctx.getTypeSizeInChars(Ctx.IntTy)), Flags(flags) {}
> +
> + unsigned char getDescriptorByte() const {
> + unsigned char result = 0;
> + if (getIsPrivate())
> + result |= IsPrivate;
> + if (getIsPublic())
> + result |= IsPublic;
> + result |= ((unsigned)getKind()) << 4;
> + return result;
> + }
> +
> + unsigned char getSizeByte() const { return size().getQuantity(); }
> +
> + Kind getKind() const { return TheKind; }
> + bool getIsPrivate() const { return (Flags & IsPrivate) != 0; }
> + bool getIsPublic() const { return (Flags & IsPublic) != 0; }
> +
> + const Expr *getExpr() const { return TheExpr; }
> + CharUnits getConstValue() const { return ConstValue; }
> + CharUnits size() const { return Size; }
> +};
> +
> +class OSLogBufferLayout {
> +public:
> + SmallVector<OSLogBufferItem, 4> Items;
> +
> + enum Flags { HasPrivateItems = 1, HasNonScalarItems = 1 << 1 };
> +
> + CharUnits size() const {
> + CharUnits result;
> + result += CharUnits::fromQuantity(2); // summary byte, num-args byte
> + for (auto &item : Items) {
> + // descriptor byte, size byte
> + result += item.size() + CharUnits::fromQuantity(2);
> + }
> + return result;
> + }
> +
> + bool hasPrivateItems() const {
> + return llvm::any_of(
> + Items, [](const OSLogBufferItem &Item) { return
> Item.getIsPrivate(); });
> + }
> +
> + bool hasPublicItems() const {
> + return llvm::any_of(
> + Items, [](const OSLogBufferItem &Item) { return
> Item.getIsPublic(); });
> + }
> +
> + bool hasNonScalar() const {
> + return llvm::any_of(Items, [](const OSLogBufferItem &Item) {
> + return Item.getKind() != OSLogBufferItem::ScalarKind;
> + });
> + }
> +
> + unsigned char getSummaryByte() const {
> + unsigned char result = 0;
> + if (hasPrivateItems())
> + result |= HasPrivateItems;
> + if (hasNonScalar())
> + result |= HasNonScalarItems;
> + return result;
> + }
> +
> + unsigned char getNumArgsByte() const { return Items.size(); }
> +};
> +
> +// Given a call 'E' to one of the builtins __builtin_os_log_format() or
> +// __builtin_os_log_format_buffer_size(), compute the layout of the
> buffer that
> +// the call will write into and store it in 'layout'. Returns 'false' if
> there
> +// was some error encountered while computing the layout, and 'true'
> otherwise.
> +bool computeOSLogBufferLayout(clang::ASTContext &Ctx, const
> clang::CallExpr *E,
> + OSLogBufferLayout &layout);
> +
> +} // namespace analyze_os_log
> +} // namespace clang
> +#endif
>
> Removed: cfe/trunk/include/clang/Analysis/Analyses/FormatString.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/FormatString.h?rev=345970&view=auto
>
> ==============================================================================
> --- cfe/trunk/include/clang/Analysis/Analyses/FormatString.h (original)
> +++ cfe/trunk/include/clang/Analysis/Analyses/FormatString.h (removed)
> @@ -1,719 +0,0 @@
> -//= FormatString.h - Analysis of printf/fprintf format strings --*- C++
> -*-===//
> -//
> -// The LLVM Compiler Infrastructure
> -//
> -// This file is distributed under the University of Illinois Open Source
> -// License. See LICENSE.TXT for details.
> -//
>
> -//===----------------------------------------------------------------------===//
> -//
> -// This file defines APIs for analyzing the format strings of printf,
> fscanf,
> -// and friends.
> -//
> -// The structure of format strings for fprintf are described in C99
> 7.19.6.1.
> -//
> -// The structure of format strings for fscanf are described in C99
> 7.19.6.2.
> -//
>
> -//===----------------------------------------------------------------------===//
> -
> -#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H
> -#define LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H
> -
> -#include "clang/AST/CanonicalType.h"
> -
> -namespace clang {
> -
> -class TargetInfo;
> -
>
> -//===----------------------------------------------------------------------===//
> -/// Common components of both fprintf and fscanf format strings.
> -namespace analyze_format_string {
> -
> -/// Class representing optional flags with location and representation
> -/// information.
> -class OptionalFlag {
> -public:
> - OptionalFlag(const char *Representation)
> - : representation(Representation), flag(false) {}
> - bool isSet() const { return flag; }
> - void set() { flag = true; }
> - void clear() { flag = false; }
> - void setPosition(const char *position) {
> - assert(position);
> - flag = true;
> - this->position = position;
> - }
> - const char *getPosition() const {
> - assert(position);
> - return position;
> - }
> - const char *toString() const { return representation; }
> -
> - // Overloaded operators for bool like qualities
> - explicit operator bool() const { return flag; }
> - OptionalFlag& operator=(const bool &rhs) {
> - flag = rhs;
> - return *this; // Return a reference to myself.
> - }
> -private:
> - const char *representation;
> - const char *position;
> - bool flag;
> -};
> -
> -/// Represents the length modifier in a format string in scanf/printf.
> -class LengthModifier {
> -public:
> - enum Kind {
> - None,
> - AsChar, // 'hh'
> - AsShort, // 'h'
> - AsLong, // 'l'
> - AsLongLong, // 'll'
> - AsQuad, // 'q' (BSD, deprecated, for 64-bit integer types)
> - AsIntMax, // 'j'
> - AsSizeT, // 'z'
> - AsPtrDiff, // 't'
> - AsInt32, // 'I32' (MSVCRT, like __int32)
> - AsInt3264, // 'I' (MSVCRT, like __int3264 from MIDL)
> - AsInt64, // 'I64' (MSVCRT, like __int64)
> - AsLongDouble, // 'L'
> - AsAllocate, // for '%as', GNU extension to C90 scanf
> - AsMAllocate, // for '%ms', GNU extension to scanf
> - AsWide, // 'w' (MSVCRT, like l but only for c, C, s, S, or Z
> - AsWideChar = AsLong // for '%ls', only makes sense for printf
> - };
> -
> - LengthModifier()
> - : Position(nullptr), kind(None) {}
> - LengthModifier(const char *pos, Kind k)
> - : Position(pos), kind(k) {}
> -
> - const char *getStart() const {
> - return Position;
> - }
> -
> - unsigned getLength() const {
> - switch (kind) {
> - default:
> - return 1;
> - case AsLongLong:
> - case AsChar:
> - return 2;
> - case AsInt32:
> - case AsInt64:
> - return 3;
> - case None:
> - return 0;
> - }
> - }
> -
> - Kind getKind() const { return kind; }
> - void setKind(Kind k) { kind = k; }
> -
> - const char *toString() const;
> -
> -private:
> - const char *Position;
> - Kind kind;
> -};
> -
> -class ConversionSpecifier {
> -public:
> - enum Kind {
> - InvalidSpecifier = 0,
> - // C99 conversion specifiers.
> - cArg,
> - dArg,
> - DArg, // Apple extension
> - iArg,
> - IntArgBeg = dArg,
> - IntArgEnd = iArg,
> -
> - oArg,
> - OArg, // Apple extension
> - uArg,
> - UArg, // Apple extension
> - xArg,
> - XArg,
> - UIntArgBeg = oArg,
> - UIntArgEnd = XArg,
> -
> - fArg,
> - FArg,
> - eArg,
> - EArg,
> - gArg,
> - GArg,
> - aArg,
> - AArg,
> - DoubleArgBeg = fArg,
> - DoubleArgEnd = AArg,
> -
> - sArg,
> - pArg,
> - nArg,
> - PercentArg,
> - CArg,
> - SArg,
> -
> - // Apple extension: P specifies to os_log that the data being pointed
> to is
> - // to be copied by os_log. The precision indicates the number of
> bytes to
> - // copy.
> - PArg,
> -
> - // ** Printf-specific **
> -
> - ZArg, // MS extension
> -
> - // Objective-C specific specifiers.
> - ObjCObjArg, // '@'
> - ObjCBeg = ObjCObjArg,
> - ObjCEnd = ObjCObjArg,
> -
> - // FreeBSD kernel specific specifiers.
> - FreeBSDbArg,
> - FreeBSDDArg,
> - FreeBSDrArg,
> - FreeBSDyArg,
> -
> - // GlibC specific specifiers.
> - PrintErrno, // 'm'
> -
> - PrintfConvBeg = ObjCObjArg,
> - PrintfConvEnd = PrintErrno,
> -
> - // ** Scanf-specific **
> - ScanListArg, // '['
> - ScanfConvBeg = ScanListArg,
> - ScanfConvEnd = ScanListArg
> - };
> -
> - ConversionSpecifier(bool isPrintf = true)
> - : IsPrintf(isPrintf), Position(nullptr), EndScanList(nullptr),
> - kind(InvalidSpecifier) {}
> -
> - ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
> - : IsPrintf(isPrintf), Position(pos), EndScanList(nullptr), kind(k) {}
> -
> - const char *getStart() const {
> - return Position;
> - }
> -
> - StringRef getCharacters() const {
> - return StringRef(getStart(), getLength());
> - }
> -
> - bool consumesDataArgument() const {
> - switch (kind) {
> - case PrintErrno:
> - assert(IsPrintf);
> - return false;
> - case PercentArg:
> - return false;
> - case InvalidSpecifier:
> - return false;
> - default:
> - return true;
> - }
> - }
> -
> - Kind getKind() const { return kind; }
> - void setKind(Kind k) { kind = k; }
> - unsigned getLength() const {
> - return EndScanList ? EndScanList - Position : 1;
> - }
> - void setEndScanList(const char *pos) { EndScanList = pos; }
> -
> - bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd)
> ||
> - kind == FreeBSDrArg || kind == FreeBSDyArg; }
> - bool isUIntArg() const { return kind >= UIntArgBeg && kind <=
> UIntArgEnd; }
> - bool isAnyIntArg() const { return kind >= IntArgBeg && kind <=
> UIntArgEnd; }
> - bool isDoubleArg() const {
> - return kind >= DoubleArgBeg && kind <= DoubleArgEnd;
> - }
> -
> - const char *toString() const;
> -
> - bool isPrintfKind() const { return IsPrintf; }
> -
> - Optional<ConversionSpecifier> getStandardSpecifier() const;
> -
> -protected:
> - bool IsPrintf;
> - const char *Position;
> - const char *EndScanList;
> - Kind kind;
> -};
> -
> -class ArgType {
> -public:
> - enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
> - AnyCharTy, CStrTy, WCStrTy, WIntTy };
> -
> - enum MatchKind { NoMatch = 0, Match = 1, NoMatchPedantic };
> -
> -private:
> - const Kind K;
> - QualType T;
> - const char *Name = nullptr;
> - bool Ptr = false;
> -
> - /// The TypeKind identifies certain well-known types like size_t and
> - /// ptrdiff_t.
> - enum class TypeKind { DontCare, SizeT, PtrdiffT };
> - TypeKind TK = TypeKind::DontCare;
> -
> -public:
> - ArgType(Kind K = UnknownTy, const char *N = nullptr) : K(K), Name(N) {}
> - ArgType(QualType T, const char *N = nullptr) : K(SpecificTy), T(T),
> Name(N) {}
> - ArgType(CanQualType T) : K(SpecificTy), T(T) {}
> -
> - static ArgType Invalid() { return ArgType(InvalidTy); }
> - bool isValid() const { return K != InvalidTy; }
> -
> - bool isSizeT() const { return TK == TypeKind::SizeT; }
> -
> - bool isPtrdiffT() const { return TK == TypeKind::PtrdiffT; }
> -
> - /// Create an ArgType which corresponds to the type pointer to A.
> - static ArgType PtrTo(const ArgType& A) {
> - assert(A.K >= InvalidTy && "ArgType cannot be pointer to
> invalid/unknown");
> - ArgType Res = A;
> - Res.Ptr = true;
> - return Res;
> - }
> -
> - /// Create an ArgType which corresponds to the size_t/ssize_t type.
> - static ArgType makeSizeT(const ArgType &A) {
> - ArgType Res = A;
> - Res.TK = TypeKind::SizeT;
> - return Res;
> - }
> -
> - /// Create an ArgType which corresponds to the ptrdiff_t/unsigned
> ptrdiff_t
> - /// type.
> - static ArgType makePtrdiffT(const ArgType &A) {
> - ArgType Res = A;
> - Res.TK = TypeKind::PtrdiffT;
> - return Res;
> - }
> -
> - MatchKind matchesType(ASTContext &C, QualType argTy) const;
> -
> - QualType getRepresentativeType(ASTContext &C) const;
> -
> - std::string getRepresentativeTypeName(ASTContext &C) const;
> -};
> -
> -class OptionalAmount {
> -public:
> - enum HowSpecified { NotSpecified, Constant, Arg, Invalid };
> -
> - OptionalAmount(HowSpecified howSpecified,
> - unsigned amount,
> - const char *amountStart,
> - unsigned amountLength,
> - bool usesPositionalArg)
> - : start(amountStart), length(amountLength), hs(howSpecified),
> amt(amount),
> - UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {}
> -
> - OptionalAmount(bool valid = true)
> - : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
> - UsesPositionalArg(0), UsesDotPrefix(0) {}
> -
> - bool isInvalid() const {
> - return hs == Invalid;
> - }
> -
> - HowSpecified getHowSpecified() const { return hs; }
> - void setHowSpecified(HowSpecified h) { hs = h; }
> -
> - bool hasDataArgument() const { return hs == Arg; }
> -
> - unsigned getArgIndex() const {
> - assert(hasDataArgument());
> - return amt;
> - }
> -
> - unsigned getConstantAmount() const {
> - assert(hs == Constant);
> - return amt;
> - }
> -
> - const char *getStart() const {
> - // We include the . character if it is given.
> - return start - UsesDotPrefix;
> - }
> -
> - unsigned getConstantLength() const {
> - assert(hs == Constant);
> - return length + UsesDotPrefix;
> - }
> -
> - ArgType getArgType(ASTContext &Ctx) const;
> -
> - void toString(raw_ostream &os) const;
> -
> - bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
> - unsigned getPositionalArgIndex() const {
> - assert(hasDataArgument());
> - return amt + 1;
> - }
> -
> - bool usesDotPrefix() const { return UsesDotPrefix; }
> - void setUsesDotPrefix() { UsesDotPrefix = true; }
> -
> -private:
> - const char *start;
> - unsigned length;
> - HowSpecified hs;
> - unsigned amt;
> - bool UsesPositionalArg : 1;
> - bool UsesDotPrefix;
> -};
> -
> -
> -class FormatSpecifier {
> -protected:
> - LengthModifier LM;
> - OptionalAmount FieldWidth;
> - ConversionSpecifier CS;
> - /// Positional arguments, an IEEE extension:
> - /// IEEE Std 1003.1, 2004 Edition
> - ///
> http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
> - bool UsesPositionalArg;
> - unsigned argIndex;
> -public:
> - FormatSpecifier(bool isPrintf)
> - : CS(isPrintf), UsesPositionalArg(false), argIndex(0) {}
> -
> - void setLengthModifier(LengthModifier lm) {
> - LM = lm;
> - }
> -
> - void setUsesPositionalArg() { UsesPositionalArg = true; }
> -
> - void setArgIndex(unsigned i) {
> - argIndex = i;
> - }
> -
> - unsigned getArgIndex() const {
> - return argIndex;
> - }
> -
> - unsigned getPositionalArgIndex() const {
> - return argIndex + 1;
> - }
> -
> - const LengthModifier &getLengthModifier() const {
> - return LM;
> - }
> -
> - const OptionalAmount &getFieldWidth() const {
> - return FieldWidth;
> - }
> -
> - void setFieldWidth(const OptionalAmount &Amt) {
> - FieldWidth = Amt;
> - }
> -
> - bool usesPositionalArg() const { return UsesPositionalArg; }
> -
> - bool hasValidLengthModifier(const TargetInfo &Target) const;
> -
> - bool hasStandardLengthModifier() const;
> -
> - Optional<LengthModifier> getCorrectedLengthModifier() const;
> -
> - bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
> -
> - bool hasStandardLengthConversionCombination() const;
> -
> - /// For a TypedefType QT, if it is a named integer type such as size_t,
> - /// assign the appropriate value to LM and return true.
> - static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM);
> -};
> -
> -} // end analyze_format_string namespace
> -
>
> -//===----------------------------------------------------------------------===//
> -/// Pieces specific to fprintf format strings.
> -
> -namespace analyze_printf {
> -
> -class PrintfConversionSpecifier :
> - public analyze_format_string::ConversionSpecifier {
> -public:
> - PrintfConversionSpecifier()
> - : ConversionSpecifier(true, nullptr, InvalidSpecifier) {}
> -
> - PrintfConversionSpecifier(const char *pos, Kind k)
> - : ConversionSpecifier(true, pos, k) {}
> -
> - bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
> - bool isDoubleArg() const { return kind >= DoubleArgBeg &&
> - kind <= DoubleArgEnd; }
> -
> - static bool classof(const analyze_format_string::ConversionSpecifier
> *CS) {
> - return CS->isPrintfKind();
> - }
> -};
> -
> -using analyze_format_string::ArgType;
> -using analyze_format_string::LengthModifier;
> -using analyze_format_string::OptionalAmount;
> -using analyze_format_string::OptionalFlag;
> -
> -class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
> - OptionalFlag HasThousandsGrouping; // ''', POSIX extension.
> - OptionalFlag IsLeftJustified; // '-'
> - OptionalFlag HasPlusPrefix; // '+'
> - OptionalFlag HasSpacePrefix; // ' '
> - OptionalFlag HasAlternativeForm; // '#'
> - OptionalFlag HasLeadingZeroes; // '0'
> - OptionalFlag HasObjCTechnicalTerm; // '[tt]'
> - OptionalFlag IsPrivate; // '{private}'
> - OptionalFlag IsPublic; // '{public}'
> - OptionalAmount Precision;
> -public:
> - PrintfSpecifier()
> - : FormatSpecifier(/* isPrintf = */ true), HasThousandsGrouping("'"),
> - IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "),
> - HasAlternativeForm("#"), HasLeadingZeroes("0"),
> - HasObjCTechnicalTerm("tt"), IsPrivate("private"),
> IsPublic("public") {}
> -
> - static PrintfSpecifier Parse(const char *beg, const char *end);
> -
> - // Methods for incrementally constructing the PrintfSpecifier.
> - void setConversionSpecifier(const PrintfConversionSpecifier &cs) {
> - CS = cs;
> - }
> - void setHasThousandsGrouping(const char *position) {
> - HasThousandsGrouping.setPosition(position);
> - }
> - void setIsLeftJustified(const char *position) {
> - IsLeftJustified.setPosition(position);
> - }
> - void setHasPlusPrefix(const char *position) {
> - HasPlusPrefix.setPosition(position);
> - }
> - void setHasSpacePrefix(const char *position) {
> - HasSpacePrefix.setPosition(position);
> - }
> - void setHasAlternativeForm(const char *position) {
> - HasAlternativeForm.setPosition(position);
> - }
> - void setHasLeadingZeros(const char *position) {
> - HasLeadingZeroes.setPosition(position);
> - }
> - void setHasObjCTechnicalTerm(const char *position) {
> - HasObjCTechnicalTerm.setPosition(position);
> - }
> - void setIsPrivate(const char *position) {
> IsPrivate.setPosition(position); }
> - void setIsPublic(const char *position) {
> IsPublic.setPosition(position); }
> - void setUsesPositionalArg() { UsesPositionalArg = true; }
> -
> - // Methods for querying the format specifier.
> -
> - const PrintfConversionSpecifier &getConversionSpecifier() const {
> - return cast<PrintfConversionSpecifier>(CS);
> - }
> -
> - void setPrecision(const OptionalAmount &Amt) {
> - Precision = Amt;
> - Precision.setUsesDotPrefix();
> - }
> -
> - const OptionalAmount &getPrecision() const {
> - return Precision;
> - }
> -
> - bool consumesDataArgument() const {
> - return getConversionSpecifier().consumesDataArgument();
> - }
> -
> - /// Returns the builtin type that a data argument
> - /// paired with this format specifier should have. This method
> - /// will return null if the format specifier does not have
> - /// a matching data argument or the matching argument matches
> - /// more than one type.
> - ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
> -
> - const OptionalFlag &hasThousandsGrouping() const {
> - return HasThousandsGrouping;
> - }
> - const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
> - const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }
> - const OptionalFlag &hasAlternativeForm() const { return
> HasAlternativeForm; }
> - const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; }
> - const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }
> - const OptionalFlag &hasObjCTechnicalTerm() const { return
> HasObjCTechnicalTerm; }
> - const OptionalFlag &isPrivate() const { return IsPrivate; }
> - const OptionalFlag &isPublic() const { return IsPublic; }
> - bool usesPositionalArg() const { return UsesPositionalArg; }
> -
> - /// Changes the specifier and length according to a QualType, retaining
> any
> - /// flags or options. Returns true on success, or false when a
> conversion
> - /// was not successful.
> - bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx,
> - bool IsObjCLiteral);
> -
> - void toString(raw_ostream &os) const;
> -
> - // Validation methods - to check if any element results in undefined
> behavior
> - bool hasValidPlusPrefix() const;
> - bool hasValidAlternativeForm() const;
> - bool hasValidLeadingZeros() const;
> - bool hasValidSpacePrefix() const;
> - bool hasValidLeftJustified() const;
> - bool hasValidThousandsGroupingPrefix() const;
> -
> - bool hasValidPrecision() const;
> - bool hasValidFieldWidth() const;
> -};
> -} // end analyze_printf namespace
> -
>
> -//===----------------------------------------------------------------------===//
> -/// Pieces specific to fscanf format strings.
> -
> -namespace analyze_scanf {
> -
> -class ScanfConversionSpecifier :
> - public analyze_format_string::ConversionSpecifier {
> -public:
> - ScanfConversionSpecifier()
> - : ConversionSpecifier(false, nullptr, InvalidSpecifier) {}
> -
> - ScanfConversionSpecifier(const char *pos, Kind k)
> - : ConversionSpecifier(false, pos, k) {}
> -
> - static bool classof(const analyze_format_string::ConversionSpecifier
> *CS) {
> - return !CS->isPrintfKind();
> - }
> -};
> -
> -using analyze_format_string::ArgType;
> -using analyze_format_string::LengthModifier;
> -using analyze_format_string::OptionalAmount;
> -using analyze_format_string::OptionalFlag;
> -
> -class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
> - OptionalFlag SuppressAssignment; // '*'
> -public:
> - ScanfSpecifier() :
> - FormatSpecifier(/* isPrintf = */ false),
> - SuppressAssignment("*") {}
> -
> - void setSuppressAssignment(const char *position) {
> - SuppressAssignment.setPosition(position);
> - }
> -
> - const OptionalFlag &getSuppressAssignment() const {
> - return SuppressAssignment;
> - }
> -
> - void setConversionSpecifier(const ScanfConversionSpecifier &cs) {
> - CS = cs;
> - }
> -
> - const ScanfConversionSpecifier &getConversionSpecifier() const {
> - return cast<ScanfConversionSpecifier>(CS);
> - }
> -
> - bool consumesDataArgument() const {
> - return CS.consumesDataArgument() && !SuppressAssignment;
> - }
> -
> - ArgType getArgType(ASTContext &Ctx) const;
> -
> - bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt,
> - ASTContext &Ctx);
> -
> - void toString(raw_ostream &os) const;
> -
> - static ScanfSpecifier Parse(const char *beg, const char *end);
> -};
> -
> -} // end analyze_scanf namespace
> -
>
> -//===----------------------------------------------------------------------===//
> -// Parsing and processing of format strings (both fprintf and fscanf).
> -
> -namespace analyze_format_string {
> -
> -enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 };
> -
> -class FormatStringHandler {
> -public:
> - FormatStringHandler() {}
> - virtual ~FormatStringHandler();
> -
> - virtual void HandleNullChar(const char *nullCharacter) {}
> -
> - virtual void HandlePosition(const char *startPos, unsigned posLen) {}
> -
> - virtual void HandleInvalidPosition(const char *startPos, unsigned
> posLen,
> - PositionContext p) {}
> -
> - virtual void HandleZeroPosition(const char *startPos, unsigned posLen)
> {}
> -
> - virtual void HandleIncompleteSpecifier(const char *startSpecifier,
> - unsigned specifierLen) {}
> -
> - virtual void HandleEmptyObjCModifierFlag(const char *startFlags,
> - unsigned flagsLen) {}
> -
> - virtual void HandleInvalidObjCModifierFlag(const char *startFlag,
> - unsigned flagLen) {}
> -
> - virtual void HandleObjCFlagsWithNonObjCConversion(const char
> *flagsStart,
> - const char *flagsEnd,
> - const char
> *conversionPosition) {}
> - // Printf-specific handlers.
> -
> - virtual bool HandleInvalidPrintfConversionSpecifier(
> - const
> analyze_printf::PrintfSpecifier &FS,
> - const char *startSpecifier,
> - unsigned specifierLen) {
> - return true;
> - }
> -
> - virtual bool HandlePrintfSpecifier(const
> analyze_printf::PrintfSpecifier &FS,
> - const char *startSpecifier,
> - unsigned specifierLen) {
> - return true;
> - }
> -
> - // Scanf-specific handlers.
> -
> - virtual bool HandleInvalidScanfConversionSpecifier(
> - const
> analyze_scanf::ScanfSpecifier &FS,
> - const char *startSpecifier,
> - unsigned specifierLen) {
> - return true;
> - }
> -
> - virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier
> &FS,
> - const char *startSpecifier,
> - unsigned specifierLen) {
> - return true;
> - }
> -
> - virtual void HandleIncompleteScanList(const char *start, const char
> *end) {}
> -};
> -
> -bool ParsePrintfString(FormatStringHandler &H,
> - const char *beg, const char *end, const
> LangOptions &LO,
> - const TargetInfo &Target, bool isFreeBSDKPrintf);
> -
> -bool ParseFormatStringHasSArg(const char *beg, const char *end,
> - const LangOptions &LO, const TargetInfo
> &Target);
> -
> -bool ParseScanfString(FormatStringHandler &H,
> - const char *beg, const char *end, const LangOptions
> &LO,
> - const TargetInfo &Target);
> -
> -} // end analyze_format_string namespace
> -} // end clang namespace
> -#endif
>
> Removed: cfe/trunk/include/clang/Analysis/Analyses/OSLog.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/OSLog.h?rev=345970&view=auto
>
> ==============================================================================
> --- cfe/trunk/include/clang/Analysis/Analyses/OSLog.h (original)
> +++ cfe/trunk/include/clang/Analysis/Analyses/OSLog.h (removed)
> @@ -1,155 +0,0 @@
> -//= OSLog.h - Analysis of calls to os_log builtins --*- C++
> -*-===============//
> -//
> -// The LLVM Compiler Infrastructure
> -//
> -// This file is distributed under the University of Illinois Open Source
> -// License. See LICENSE.TXT for details.
> -//
>
> -//===----------------------------------------------------------------------===//
> -//
> -// This file defines APIs for determining the layout of the data buffer
> for
> -// os_log() and os_trace().
> -//
>
> -//===----------------------------------------------------------------------===//
> -
> -#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H
> -#define LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H
> -
> -#include "clang/AST/ASTContext.h"
> -#include "clang/AST/Expr.h"
> -
> -namespace clang {
> -namespace analyze_os_log {
> -
> -/// An OSLogBufferItem represents a single item in the data written by a
> call
> -/// to os_log() or os_trace().
> -class OSLogBufferItem {
> -public:
> - enum Kind {
> - // The item is a scalar (int, float, raw pointer, etc.). No further
> copying
> - // is required. This is the only kind allowed by os_trace().
> - ScalarKind = 0,
> -
> - // The item is a count, which describes the length of the following
> item to
> - // be copied. A count may only be followed by an item of kind
> StringKind,
> - // WideStringKind, or PointerKind.
> - CountKind,
> -
> - // The item is a pointer to a C string. If preceded by a count 'n',
> - // os_log() will copy at most 'n' bytes from the pointer.
> - StringKind,
> -
> - // The item is a pointer to a block of raw data. This item must be
> preceded
> - // by a count 'n'. os_log() will copy exactly 'n' bytes from the
> pointer.
> - PointerKind,
> -
> - // The item is a pointer to an Objective-C object. os_log() may
> retain the
> - // object for later processing.
> - ObjCObjKind,
> -
> - // The item is a pointer to wide-char string.
> - WideStringKind,
> -
> - // The item is corresponding to the '%m' format specifier, no value is
> - // populated in the buffer and the runtime is loading the errno value.
> - ErrnoKind
> - };
> -
> - enum {
> - // The item is marked "private" in the format string.
> - IsPrivate = 0x1,
> -
> - // The item is marked "public" in the format string.
> - IsPublic = 0x2
> - };
> -
> -private:
> - Kind TheKind = ScalarKind;
> - const Expr *TheExpr = nullptr;
> - CharUnits ConstValue;
> - CharUnits Size; // size of the data, not including the header bytes
> - unsigned Flags = 0;
> -
> -public:
> - OSLogBufferItem(Kind kind, const Expr *expr, CharUnits size, unsigned
> flags)
> - : TheKind(kind), TheExpr(expr), Size(size), Flags(flags) {}
> -
> - OSLogBufferItem(ASTContext &Ctx, CharUnits value, unsigned flags)
> - : TheKind(CountKind), ConstValue(value),
> - Size(Ctx.getTypeSizeInChars(Ctx.IntTy)), Flags(flags) {}
> -
> - unsigned char getDescriptorByte() const {
> - unsigned char result = 0;
> - if (getIsPrivate())
> - result |= IsPrivate;
> - if (getIsPublic())
> - result |= IsPublic;
> - result |= ((unsigned)getKind()) << 4;
> - return result;
> - }
> -
> - unsigned char getSizeByte() const { return size().getQuantity(); }
> -
> - Kind getKind() const { return TheKind; }
> - bool getIsPrivate() const { return (Flags & IsPrivate) != 0; }
> - bool getIsPublic() const { return (Flags & IsPublic) != 0; }
> -
> - const Expr *getExpr() const { return TheExpr; }
> - CharUnits getConstValue() const { return ConstValue; }
> - CharUnits size() const { return Size; }
> -};
> -
> -class OSLogBufferLayout {
> -public:
> - SmallVector<OSLogBufferItem, 4> Items;
> -
> - enum Flags { HasPrivateItems = 1, HasNonScalarItems = 1 << 1 };
> -
> - CharUnits size() const {
> - CharUnits result;
> - result += CharUnits::fromQuantity(2); // summary byte, num-args byte
> - for (auto &item : Items) {
> - // descriptor byte, size byte
> - result += item.size() + CharUnits::fromQuantity(2);
> - }
> - return result;
> - }
> -
> - bool hasPrivateItems() const {
> - return llvm::any_of(
> - Items, [](const OSLogBufferItem &Item) { return
> Item.getIsPrivate(); });
> - }
> -
> - bool hasPublicItems() const {
> - return llvm::any_of(
> - Items, [](const OSLogBufferItem &Item) { return
> Item.getIsPublic(); });
> - }
> -
> - bool hasNonScalar() const {
> - return llvm::any_of(Items, [](const OSLogBufferItem &Item) {
> - return Item.getKind() != OSLogBufferItem::ScalarKind;
> - });
> - }
> -
> - unsigned char getSummaryByte() const {
> - unsigned char result = 0;
> - if (hasPrivateItems())
> - result |= HasPrivateItems;
> - if (hasNonScalar())
> - result |= HasNonScalarItems;
> - return result;
> - }
> -
> - unsigned char getNumArgsByte() const { return Items.size(); }
> -};
> -
> -// Given a call 'E' to one of the builtins __builtin_os_log_format() or
> -// __builtin_os_log_format_buffer_size(), compute the layout of the
> buffer that
> -// the call will write into and store it in 'layout'. Returns 'false' if
> there
> -// was some error encountered while computing the layout, and 'true'
> otherwise.
> -bool computeOSLogBufferLayout(clang::ASTContext &Ctx, const
> clang::CallExpr *E,
> - OSLogBufferLayout &layout);
> -
> -} // namespace analyze_os_log
> -} // namespace clang
> -#endif
>
> Modified: cfe/trunk/lib/AST/CMakeLists.txt
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CMakeLists.txt?rev=345971&r1=345970&r2=345971&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/CMakeLists.txt (original)
> +++ cfe/trunk/lib/AST/CMakeLists.txt Fri Nov 2 06:14:11 2018
> @@ -39,6 +39,7 @@ add_clang_library(clangAST
> ExprObjC.cpp
> ExternalASTMerger.cpp
> ExternalASTSource.cpp
> + FormatString.cpp
> InheritViz.cpp
> ItaniumCXXABI.cpp
> ItaniumMangle.cpp
> @@ -48,12 +49,15 @@ add_clang_library(clangAST
> NestedNameSpecifier.cpp
> NSAPI.cpp
> ODRHash.cpp
> + OSLog.cpp
> OpenMPClause.cpp
> ParentMap.cpp
> + PrintfFormatString.cpp
> QualTypeNames.cpp
> RawCommentList.cpp
> RecordLayout.cpp
> RecordLayoutBuilder.cpp
> + ScanfFormatString.cpp
> SelectorLocationsKind.cpp
> Stmt.cpp
> StmtCXX.cpp
>
> Modified: cfe/trunk/lib/AST/ExprConstant.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=345971&r1=345970&r2=345971&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/ExprConstant.cpp (original)
> +++ cfe/trunk/lib/AST/ExprConstant.cpp Fri Nov 2 06:14:11 2018
> @@ -39,6 +39,7 @@
> #include "clang/AST/ASTLambda.h"
> #include "clang/AST/CharUnits.h"
> #include "clang/AST/Expr.h"
> +#include "clang/AST/OSLog.h"
> #include "clang/AST/RecordLayout.h"
> #include "clang/AST/StmtVisitor.h"
> #include "clang/AST/TypeLoc.h"
> @@ -8126,6 +8127,12 @@ bool IntExprEvaluator::VisitBuiltinCallE
> llvm_unreachable("unexpected EvalMode");
> }
>
> + case Builtin::BI__builtin_os_log_format_buffer_size: {
> + analyze_os_log::OSLogBufferLayout Layout;
> + analyze_os_log::computeOSLogBufferLayout(Info.Ctx, E, Layout);
> + return Success(Layout.size().getQuantity(), E);
> + }
> +
> case Builtin::BI__builtin_bswap16:
> case Builtin::BI__builtin_bswap32:
> case Builtin::BI__builtin_bswap64: {
>
> Added: cfe/trunk/lib/AST/FormatString.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/FormatString.cpp?rev=345971&view=auto
>
> ==============================================================================
> --- cfe/trunk/lib/AST/FormatString.cpp (added)
> +++ cfe/trunk/lib/AST/FormatString.cpp Fri Nov 2 06:14:11 2018
> @@ -0,0 +1,955 @@
> +// FormatString.cpp - Common stuff for handling printf/scanf formats -*-
> C++ -*-
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// Shared details for processing format strings of printf and scanf
> +// (and friends).
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "FormatStringParsing.h"
> +#include "clang/Basic/LangOptions.h"
> +#include "clang/Basic/TargetInfo.h"
> +#include "llvm/Support/ConvertUTF.h"
> +
> +using clang::analyze_format_string::ArgType;
> +using clang::analyze_format_string::FormatStringHandler;
> +using clang::analyze_format_string::FormatSpecifier;
> +using clang::analyze_format_string::LengthModifier;
> +using clang::analyze_format_string::OptionalAmount;
> +using clang::analyze_format_string::PositionContext;
> +using clang::analyze_format_string::ConversionSpecifier;
> +using namespace clang;
> +
> +// Key function to FormatStringHandler.
> +FormatStringHandler::~FormatStringHandler() {}
> +
>
> +//===----------------------------------------------------------------------===//
> +// Functions for parsing format strings components in both printf and
> +// scanf format strings.
>
> +//===----------------------------------------------------------------------===//
> +
> +OptionalAmount
> +clang::analyze_format_string::ParseAmount(const char *&Beg, const char
> *E) {
> + const char *I = Beg;
> + UpdateOnReturn <const char*> UpdateBeg(Beg, I);
> +
> + unsigned accumulator = 0;
> + bool hasDigits = false;
> +
> + for ( ; I != E; ++I) {
> + char c = *I;
> + if (c >= '0' && c <= '9') {
> + hasDigits = true;
> + accumulator = (accumulator * 10) + (c - '0');
> + continue;
> + }
> +
> + if (hasDigits)
> + return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, I
> - Beg,
> + false);
> +
> + break;
> + }
> +
> + return OptionalAmount();
> +}
> +
> +OptionalAmount
> +clang::analyze_format_string::ParseNonPositionAmount(const char *&Beg,
> + const char *E,
> + unsigned &argIndex) {
> + if (*Beg == '*') {
> + ++Beg;
> + return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false);
> + }
> +
> + return ParseAmount(Beg, E);
> +}
> +
> +OptionalAmount
> +clang::analyze_format_string::ParsePositionAmount(FormatStringHandler &H,
> + const char *Start,
> + const char *&Beg,
> + const char *E,
> + PositionContext p) {
> + if (*Beg == '*') {
> + const char *I = Beg + 1;
> + const OptionalAmount &Amt = ParseAmount(I, E);
> +
> + if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {
> + H.HandleInvalidPosition(Beg, I - Beg, p);
> + return OptionalAmount(false);
> + }
> +
> + if (I == E) {
> + // No more characters left?
> + H.HandleIncompleteSpecifier(Start, E - Start);
> + return OptionalAmount(false);
> + }
> +
> + assert(Amt.getHowSpecified() == OptionalAmount::Constant);
> +
> + if (*I == '$') {
> + // Handle positional arguments
> +
> + // Special case: '*0$', since this is an easy mistake.
> + if (Amt.getConstantAmount() == 0) {
> + H.HandleZeroPosition(Beg, I - Beg + 1);
> + return OptionalAmount(false);
> + }
> +
> + const char *Tmp = Beg;
> + Beg = ++I;
> +
> + return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount()
> - 1,
> + Tmp, 0, true);
> + }
> +
> + H.HandleInvalidPosition(Beg, I - Beg, p);
> + return OptionalAmount(false);
> + }
> +
> + return ParseAmount(Beg, E);
> +}
> +
> +
> +bool
> +clang::analyze_format_string::ParseFieldWidth(FormatStringHandler &H,
> + FormatSpecifier &CS,
> + const char *Start,
> + const char *&Beg, const
> char *E,
> + unsigned *argIndex) {
> + // FIXME: Support negative field widths.
> + if (argIndex) {
> + CS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex));
> + }
> + else {
> + const OptionalAmount Amt =
> + ParsePositionAmount(H, Start, Beg, E,
> + analyze_format_string::FieldWidthPos);
> +
> + if (Amt.isInvalid())
> + return true;
> + CS.setFieldWidth(Amt);
> + }
> + return false;
> +}
> +
> +bool
> +clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H,
> + FormatSpecifier &FS,
> + const char *Start,
> + const char *&Beg,
> + const char *E) {
> + const char *I = Beg;
> +
> + const OptionalAmount &Amt = ParseAmount(I, E);
> +
> + if (I == E) {
> + // No more characters left?
> + H.HandleIncompleteSpecifier(Start, E - Start);
> + return true;
> + }
> +
> + if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$')
> {
> + // Warn that positional arguments are non-standard.
> + H.HandlePosition(Start, I - Start);
> +
> + // Special case: '%0$', since this is an easy mistake.
> + if (Amt.getConstantAmount() == 0) {
> + H.HandleZeroPosition(Start, I - Start);
> + return true;
> + }
> +
> + FS.setArgIndex(Amt.getConstantAmount() - 1);
> + FS.setUsesPositionalArg();
> + // Update the caller's pointer if we decided to consume
> + // these characters.
> + Beg = I;
> + return false;
> + }
> +
> + return false;
> +}
> +
> +bool
> +clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
> + const char *&I,
> + const char *E,
> + const LangOptions &LO,
> + bool IsScanf) {
> + LengthModifier::Kind lmKind = LengthModifier::None;
> + const char *lmPosition = I;
> + switch (*I) {
> + default:
> + return false;
> + case 'h':
> + ++I;
> + if (I != E && *I == 'h') {
> + ++I;
> + lmKind = LengthModifier::AsChar;
> + } else {
> + lmKind = LengthModifier::AsShort;
> + }
> + break;
> + case 'l':
> + ++I;
> + if (I != E && *I == 'l') {
> + ++I;
> + lmKind = LengthModifier::AsLongLong;
> + } else {
> + lmKind = LengthModifier::AsLong;
> + }
> + break;
> + case 'j': lmKind = LengthModifier::AsIntMax; ++I; break;
> + case 'z': lmKind = LengthModifier::AsSizeT; ++I; break;
> + case 't': lmKind = LengthModifier::AsPtrDiff; ++I; break;
> + case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;
> + case 'q': lmKind = LengthModifier::AsQuad; ++I; break;
> + case 'a':
> + if (IsScanf && !LO.C99 && !LO.CPlusPlus11) {
> + // For scanf in C90, look at the next character to see if this
> should
> + // be parsed as the GNU extension 'a' length modifier. If not,
> this
> + // will be parsed as a conversion specifier.
> + ++I;
> + if (I != E && (*I == 's' || *I == 'S' || *I == '[')) {
> + lmKind = LengthModifier::AsAllocate;
> + break;
> + }
> + --I;
> + }
> + return false;
> + case 'm':
> + if (IsScanf) {
> + lmKind = LengthModifier::AsMAllocate;
> + ++I;
> + break;
> + }
> + return false;
> + // printf: AsInt64, AsInt32, AsInt3264
> + // scanf: AsInt64
> + case 'I':
> + if (I + 1 != E && I + 2 != E) {
> + if (I[1] == '6' && I[2] == '4') {
> + I += 3;
> + lmKind = LengthModifier::AsInt64;
> + break;
> + }
> + if (IsScanf)
> + return false;
> +
> + if (I[1] == '3' && I[2] == '2') {
> + I += 3;
> + lmKind = LengthModifier::AsInt32;
> + break;
> + }
> + }
> + ++I;
> + lmKind = LengthModifier::AsInt3264;
> + break;
> + case 'w':
> + lmKind = LengthModifier::AsWide; ++I; break;
> + }
> + LengthModifier lm(lmPosition, lmKind);
> + FS.setLengthModifier(lm);
> + return true;
> +}
> +
> +bool clang::analyze_format_string::ParseUTF8InvalidSpecifier(
> + const char *SpecifierBegin, const char *FmtStrEnd, unsigned &Len) {
> + if (SpecifierBegin + 1 >= FmtStrEnd)
> + return false;
> +
> + const llvm::UTF8 *SB =
> + reinterpret_cast<const llvm::UTF8 *>(SpecifierBegin + 1);
> + const llvm::UTF8 *SE = reinterpret_cast<const llvm::UTF8 *>(FmtStrEnd);
> + const char FirstByte = *SB;
> +
> + // If the invalid specifier is a multibyte UTF-8 string, return the
> + // total length accordingly so that the conversion specifier can be
> + // properly updated to reflect a complete UTF-8 specifier.
> + unsigned NumBytes = llvm::getNumBytesForUTF8(FirstByte);
> + if (NumBytes == 1)
> + return false;
> + if (SB + NumBytes > SE)
> + return false;
> +
> + Len = NumBytes + 1;
> + return true;
> +}
> +
>
> +//===----------------------------------------------------------------------===//
> +// Methods on ArgType.
>
> +//===----------------------------------------------------------------------===//
> +
> +clang::analyze_format_string::ArgType::MatchKind
> +ArgType::matchesType(ASTContext &C, QualType argTy) const {
> + if (Ptr) {
> + // It has to be a pointer.
> + const PointerType *PT = argTy->getAs<PointerType>();
> + if (!PT)
> + return NoMatch;
> +
> + // We cannot write through a const qualified pointer.
> + if (PT->getPointeeType().isConstQualified())
> + return NoMatch;
> +
> + argTy = PT->getPointeeType();
> + }
> +
> + switch (K) {
> + case InvalidTy:
> + llvm_unreachable("ArgType must be valid");
> +
> + case UnknownTy:
> + return Match;
> +
> + case AnyCharTy: {
> + if (const EnumType *ETy = argTy->getAs<EnumType>()) {
> + // If the enum is incomplete we know nothing about the underlying
> type.
> + // Assume that it's 'int'.
> + if (!ETy->getDecl()->isComplete())
> + return NoMatch;
> + argTy = ETy->getDecl()->getIntegerType();
> + }
> +
> + if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
> + switch (BT->getKind()) {
> + default:
> + break;
> + case BuiltinType::Char_S:
> + case BuiltinType::SChar:
> + case BuiltinType::UChar:
> + case BuiltinType::Char_U:
> + return Match;
> + }
> + return NoMatch;
> + }
> +
> + case SpecificTy: {
> + if (const EnumType *ETy = argTy->getAs<EnumType>()) {
> + // If the enum is incomplete we know nothing about the underlying
> type.
> + // Assume that it's 'int'.
> + if (!ETy->getDecl()->isComplete())
> + argTy = C.IntTy;
> + else
> + argTy = ETy->getDecl()->getIntegerType();
> + }
> + argTy = C.getCanonicalType(argTy).getUnqualifiedType();
> +
> + if (T == argTy)
> + return Match;
> + // Check for "compatible types".
> + if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
> + switch (BT->getKind()) {
> + default:
> + break;
> + case BuiltinType::Char_S:
> + case BuiltinType::SChar:
> + case BuiltinType::Char_U:
> + case BuiltinType::UChar:
> + return T == C.UnsignedCharTy || T == C.SignedCharTy ? Match
> + : NoMatch;
> + case BuiltinType::Short:
> + return T == C.UnsignedShortTy ? Match : NoMatch;
> + case BuiltinType::UShort:
> + return T == C.ShortTy ? Match : NoMatch;
> + case BuiltinType::Int:
> + return T == C.UnsignedIntTy ? Match : NoMatch;
> + case BuiltinType::UInt:
> + return T == C.IntTy ? Match : NoMatch;
> + case BuiltinType::Long:
> + return T == C.UnsignedLongTy ? Match : NoMatch;
> + case BuiltinType::ULong:
> + return T == C.LongTy ? Match : NoMatch;
> + case BuiltinType::LongLong:
> + return T == C.UnsignedLongLongTy ? Match : NoMatch;
> + case BuiltinType::ULongLong:
> + return T == C.LongLongTy ? Match : NoMatch;
> + }
> + return NoMatch;
> + }
> +
> + case CStrTy: {
> + const PointerType *PT = argTy->getAs<PointerType>();
> + if (!PT)
> + return NoMatch;
> + QualType pointeeTy = PT->getPointeeType();
> + if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>())
> + switch (BT->getKind()) {
> + case BuiltinType::Void:
> + case BuiltinType::Char_U:
> + case BuiltinType::UChar:
> + case BuiltinType::Char_S:
> + case BuiltinType::SChar:
> + return Match;
> + default:
> + break;
> + }
> +
> + return NoMatch;
> + }
> +
> + case WCStrTy: {
> + const PointerType *PT = argTy->getAs<PointerType>();
> + if (!PT)
> + return NoMatch;
> + QualType pointeeTy =
> + C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();
> + return pointeeTy == C.getWideCharType() ? Match : NoMatch;
> + }
> +
> + case WIntTy: {
> + QualType WInt =
> C.getCanonicalType(C.getWIntType()).getUnqualifiedType();
> +
> + if (C.getCanonicalType(argTy).getUnqualifiedType() == WInt)
> + return Match;
> +
> + QualType PromoArg = argTy->isPromotableIntegerType()
> + ? C.getPromotedIntegerType(argTy)
> + : argTy;
> + PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType();
> +
> + // If the promoted argument is the corresponding signed type of the
> + // wint_t type, then it should match.
> + if (PromoArg->hasSignedIntegerRepresentation() &&
> + C.getCorrespondingUnsignedType(PromoArg) == WInt)
> + return Match;
> +
> + return WInt == PromoArg ? Match : NoMatch;
> + }
> +
> + case CPointerTy:
> + if (argTy->isVoidPointerType()) {
> + return Match;
> + } if (argTy->isPointerType() || argTy->isObjCObjectPointerType() ||
> + argTy->isBlockPointerType() || argTy->isNullPtrType()) {
> + return NoMatchPedantic;
> + } else {
> + return NoMatch;
> + }
> +
> + case ObjCPointerTy: {
> + if (argTy->getAs<ObjCObjectPointerType>() ||
> + argTy->getAs<BlockPointerType>())
> + return Match;
> +
> + // Handle implicit toll-free bridging.
> + if (const PointerType *PT = argTy->getAs<PointerType>()) {
> + // Things such as CFTypeRef are really just opaque pointers
> + // to C structs representing CF types that can often be bridged
> + // to Objective-C objects. Since the compiler doesn't know which
> + // structs can be toll-free bridged, we just accept them all.
> + QualType pointee = PT->getPointeeType();
> + if (pointee->getAsStructureType() || pointee->isVoidType())
> + return Match;
> + }
> + return NoMatch;
> + }
> + }
> +
> + llvm_unreachable("Invalid ArgType Kind!");
> +}
> +
> +QualType ArgType::getRepresentativeType(ASTContext &C) const {
> + QualType Res;
> + switch (K) {
> + case InvalidTy:
> + llvm_unreachable("No representative type for Invalid ArgType");
> + case UnknownTy:
> + llvm_unreachable("No representative type for Unknown ArgType");
> + case AnyCharTy:
> + Res = C.CharTy;
> + break;
> + case SpecificTy:
> + Res = T;
> + break;
> + case CStrTy:
> + Res = C.getPointerType(C.CharTy);
> + break;
> + case WCStrTy:
> + Res = C.getPointerType(C.getWideCharType());
> + break;
> + case ObjCPointerTy:
> + Res = C.ObjCBuiltinIdTy;
> + break;
> + case CPointerTy:
> + Res = C.VoidPtrTy;
> + break;
> + case WIntTy: {
> + Res = C.getWIntType();
> + break;
> + }
> + }
> +
> + if (Ptr)
> + Res = C.getPointerType(Res);
> + return Res;
> +}
> +
> +std::string ArgType::getRepresentativeTypeName(ASTContext &C) const {
> + std::string S = getRepresentativeType(C).getAsString();
> +
> + std::string Alias;
> + if (Name) {
> + // Use a specific name for this type, e.g. "size_t".
> + Alias = Name;
> + if (Ptr) {
> + // If ArgType is actually a pointer to T, append an asterisk.
> + Alias += (Alias[Alias.size()-1] == '*') ? "*" : " *";
> + }
> + // If Alias is the same as the underlying type, e.g. wchar_t, then
> drop it.
> + if (S == Alias)
> + Alias.clear();
> + }
> +
> + if (!Alias.empty())
> + return std::string("'") + Alias + "' (aka '" + S + "')";
> + return std::string("'") + S + "'";
> +}
> +
> +
>
> +//===----------------------------------------------------------------------===//
> +// Methods on OptionalAmount.
>
> +//===----------------------------------------------------------------------===//
> +
> +ArgType
> +analyze_format_string::OptionalAmount::getArgType(ASTContext &Ctx) const {
> + return Ctx.IntTy;
> +}
> +
>
> +//===----------------------------------------------------------------------===//
> +// Methods on LengthModifier.
>
> +//===----------------------------------------------------------------------===//
> +
> +const char *
> +analyze_format_string::LengthModifier::toString() const {
> + switch (kind) {
> + case AsChar:
> + return "hh";
> + case AsShort:
> + return "h";
> + case AsLong: // or AsWideChar
> + return "l";
> + case AsLongLong:
> + return "ll";
> + case AsQuad:
> + return "q";
> + case AsIntMax:
> + return "j";
> + case AsSizeT:
> + return "z";
> + case AsPtrDiff:
> + return "t";
> + case AsInt32:
> + return "I32";
> + case AsInt3264:
> + return "I";
> + case AsInt64:
> + return "I64";
> + case AsLongDouble:
> + return "L";
> + case AsAllocate:
> + return "a";
> + case AsMAllocate:
> + return "m";
> + case AsWide:
> + return "w";
> + case None:
> + return "";
> + }
> + return nullptr;
> +}
> +
>
> +//===----------------------------------------------------------------------===//
> +// Methods on ConversionSpecifier.
>
> +//===----------------------------------------------------------------------===//
> +
> +const char *ConversionSpecifier::toString() const {
> + switch (kind) {
> + case dArg: return "d";
> + case DArg: return "D";
> + case iArg: return "i";
> + case oArg: return "o";
> + case OArg: return "O";
> + case uArg: return "u";
> + case UArg: return "U";
> + case xArg: return "x";
> + case XArg: return "X";
> + case fArg: return "f";
> + case FArg: return "F";
> + case eArg: return "e";
> + case EArg: return "E";
> + case gArg: return "g";
> + case GArg: return "G";
> + case aArg: return "a";
> + case AArg: return "A";
> + case cArg: return "c";
> + case sArg: return "s";
> + case pArg: return "p";
> + case PArg:
> + return "P";
> + case nArg: return "n";
> + case PercentArg: return "%";
> + case ScanListArg: return "[";
> + case InvalidSpecifier: return nullptr;
> +
> + // POSIX unicode extensions.
> + case CArg: return "C";
> + case SArg: return "S";
> +
> + // Objective-C specific specifiers.
> + case ObjCObjArg: return "@";
> +
> + // FreeBSD kernel specific specifiers.
> + case FreeBSDbArg: return "b";
> + case FreeBSDDArg: return "D";
> + case FreeBSDrArg: return "r";
> + case FreeBSDyArg: return "y";
> +
> + // GlibC specific specifiers.
> + case PrintErrno: return "m";
> +
> + // MS specific specifiers.
> + case ZArg: return "Z";
> + }
> + return nullptr;
> +}
> +
> +Optional<ConversionSpecifier>
> +ConversionSpecifier::getStandardSpecifier() const {
> + ConversionSpecifier::Kind NewKind;
> +
> + switch (getKind()) {
> + default:
> + return None;
> + case DArg:
> + NewKind = dArg;
> + break;
> + case UArg:
> + NewKind = uArg;
> + break;
> + case OArg:
> + NewKind = oArg;
> + break;
> + }
> +
> + ConversionSpecifier FixedCS(*this);
> + FixedCS.setKind(NewKind);
> + return FixedCS;
> +}
> +
>
> +//===----------------------------------------------------------------------===//
> +// Methods on OptionalAmount.
>
> +//===----------------------------------------------------------------------===//
> +
> +void OptionalAmount::toString(raw_ostream &os) const {
> + switch (hs) {
> + case Invalid:
> + case NotSpecified:
> + return;
> + case Arg:
> + if (UsesDotPrefix)
> + os << ".";
> + if (usesPositionalArg())
> + os << "*" << getPositionalArgIndex() << "$";
> + else
> + os << "*";
> + break;
> + case Constant:
> + if (UsesDotPrefix)
> + os << ".";
> + os << amt;
> + break;
> + }
> +}
> +
> +bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target)
> const {
> + switch (LM.getKind()) {
> + case LengthModifier::None:
> + return true;
> +
> + // Handle most integer flags
> + case LengthModifier::AsShort:
> + if (Target.getTriple().isOSMSVCRT()) {
> + switch (CS.getKind()) {
> + case ConversionSpecifier::cArg:
> + case ConversionSpecifier::CArg:
> + case ConversionSpecifier::sArg:
> + case ConversionSpecifier::SArg:
> + case ConversionSpecifier::ZArg:
> + return true;
> + default:
> + break;
> + }
> + }
> + LLVM_FALLTHROUGH;
> + case LengthModifier::AsChar:
> + case LengthModifier::AsLongLong:
> + case LengthModifier::AsQuad:
> + case LengthModifier::AsIntMax:
> + case LengthModifier::AsSizeT:
> + case LengthModifier::AsPtrDiff:
> + switch (CS.getKind()) {
> + case ConversionSpecifier::dArg:
> + case ConversionSpecifier::DArg:
> + case ConversionSpecifier::iArg:
> + case ConversionSpecifier::oArg:
> + case ConversionSpecifier::OArg:
> + case ConversionSpecifier::uArg:
> + case ConversionSpecifier::UArg:
> + case ConversionSpecifier::xArg:
> + case ConversionSpecifier::XArg:
> + case ConversionSpecifier::nArg:
> + return true;
> + case ConversionSpecifier::FreeBSDrArg:
> + case ConversionSpecifier::FreeBSDyArg:
> + return Target.getTriple().isOSFreeBSD() ||
> Target.getTriple().isPS4();
> + default:
> + return false;
> + }
> +
> + // Handle 'l' flag
> + case LengthModifier::AsLong: // or AsWideChar
> + switch (CS.getKind()) {
> + case ConversionSpecifier::dArg:
> + case ConversionSpecifier::DArg:
> + case ConversionSpecifier::iArg:
> + case ConversionSpecifier::oArg:
> + case ConversionSpecifier::OArg:
> + case ConversionSpecifier::uArg:
> + case ConversionSpecifier::UArg:
> + case ConversionSpecifier::xArg:
> + case ConversionSpecifier::XArg:
> + case ConversionSpecifier::aArg:
> + case ConversionSpecifier::AArg:
> + case ConversionSpecifier::fArg:
> + case ConversionSpecifier::FArg:
> + case ConversionSpecifier::eArg:
> + case ConversionSpecifier::EArg:
> + case ConversionSpecifier::gArg:
> + case ConversionSpecifier::GArg:
> + case ConversionSpecifier::nArg:
> + case ConversionSpecifier::cArg:
> + case ConversionSpecifier::sArg:
> + case ConversionSpecifier::ScanListArg:
> + case ConversionSpecifier::ZArg:
> + return true;
> + case ConversionSpecifier::FreeBSDrArg:
> + case ConversionSpecifier::FreeBSDyArg:
> + return Target.getTriple().isOSFreeBSD() ||
> Target.getTriple().isPS4();
> + default:
> + return false;
> + }
> +
> + case LengthModifier::AsLongDouble:
> + switch (CS.getKind()) {
> + case ConversionSpecifier::aArg:
> + case ConversionSpecifier::AArg:
> + case ConversionSpecifier::fArg:
> + case ConversionSpecifier::FArg:
> + case ConversionSpecifier::eArg:
> + case ConversionSpecifier::EArg:
> + case ConversionSpecifier::gArg:
> + case ConversionSpecifier::GArg:
> + return true;
> + // GNU libc extension.
> + case ConversionSpecifier::dArg:
> + case ConversionSpecifier::iArg:
> + case ConversionSpecifier::oArg:
> + case ConversionSpecifier::uArg:
> + case ConversionSpecifier::xArg:
> + case ConversionSpecifier::XArg:
> + return !Target.getTriple().isOSDarwin() &&
> + !Target.getTriple().isOSWindows();
> + default:
> + return false;
> + }
> +
> + case LengthModifier::AsAllocate:
> + switch (CS.getKind()) {
> + case ConversionSpecifier::sArg:
> + case ConversionSpecifier::SArg:
> + case ConversionSpecifier::ScanListArg:
> + return true;
> + default:
> + return false;
> + }
> +
> + case LengthModifier::AsMAllocate:
> + switch (CS.getKind()) {
> + case ConversionSpecifier::cArg:
> + case ConversionSpecifier::CArg:
> + case ConversionSpecifier::sArg:
> + case ConversionSpecifier::SArg:
> + case ConversionSpecifier::ScanListArg:
> + return true;
> + default:
> + return false;
> + }
> + case LengthModifier::AsInt32:
> + case LengthModifier::AsInt3264:
> + case LengthModifier::AsInt64:
> + switch (CS.getKind()) {
> + case ConversionSpecifier::dArg:
> + case ConversionSpecifier::iArg:
> + case ConversionSpecifier::oArg:
> + case ConversionSpecifier::uArg:
> + case ConversionSpecifier::xArg:
> + case ConversionSpecifier::XArg:
> + return Target.getTriple().isOSMSVCRT();
> + default:
> + return false;
> + }
> + case LengthModifier::AsWide:
> + switch (CS.getKind()) {
> + case ConversionSpecifier::cArg:
> + case ConversionSpecifier::CArg:
> + case ConversionSpecifier::sArg:
> + case ConversionSpecifier::SArg:
> + case ConversionSpecifier::ZArg:
> + return Target.getTriple().isOSMSVCRT();
> + default:
> + return false;
> + }
> + }
> + llvm_unreachable("Invalid LengthModifier Kind!");
> +}
> +
> +bool FormatSpecifier::hasStandardLengthModifier() const {
> + switch (LM.getKind()) {
> + case LengthModifier::None:
> + case LengthModifier::AsChar:
> + case LengthModifier::AsShort:
> + case LengthModifier::AsLong:
> + case LengthModifier::AsLongLong:
> + case LengthModifier::AsIntMax:
> + case LengthModifier::AsSizeT:
> + case LengthModifier::AsPtrDiff:
> + case LengthModifier::AsLongDouble:
> + return true;
> + case LengthModifier::AsAllocate:
> + case LengthModifier::AsMAllocate:
> + case LengthModifier::AsQuad:
> + case LengthModifier::AsInt32:
> + case LengthModifier::AsInt3264:
> + case LengthModifier::AsInt64:
> + case LengthModifier::AsWide:
> + return false;
> + }
> + llvm_unreachable("Invalid LengthModifier Kind!");
> +}
> +
> +bool FormatSpecifier::hasStandardConversionSpecifier(
> + const LangOptions &LangOpt) const {
> + switch (CS.getKind()) {
> + case ConversionSpecifier::cArg:
> + case ConversionSpecifier::dArg:
> + case ConversionSpecifier::iArg:
> + case ConversionSpecifier::oArg:
> + case ConversionSpecifier::uArg:
> + case ConversionSpecifier::xArg:
> + case ConversionSpecifier::XArg:
> + case ConversionSpecifier::fArg:
> + case ConversionSpecifier::FArg:
> + case ConversionSpecifier::eArg:
> + case ConversionSpecifier::EArg:
> + case ConversionSpecifier::gArg:
> + case ConversionSpecifier::GArg:
> + case ConversionSpecifier::aArg:
> + case ConversionSpecifier::AArg:
> + case ConversionSpecifier::sArg:
> + case ConversionSpecifier::pArg:
> + case ConversionSpecifier::nArg:
> + case ConversionSpecifier::ObjCObjArg:
> + case ConversionSpecifier::ScanListArg:
> + case ConversionSpecifier::PercentArg:
> + case ConversionSpecifier::PArg:
> + return true;
> + case ConversionSpecifier::CArg:
> + case ConversionSpecifier::SArg:
> + return LangOpt.ObjC;
> + case ConversionSpecifier::InvalidSpecifier:
> + case ConversionSpecifier::FreeBSDbArg:
> + case ConversionSpecifier::FreeBSDDArg:
> + case ConversionSpecifier::FreeBSDrArg:
> + case ConversionSpecifier::FreeBSDyArg:
> + case ConversionSpecifier::PrintErrno:
> + case ConversionSpecifier::DArg:
> + case ConversionSpecifier::OArg:
> + case ConversionSpecifier::UArg:
> + case ConversionSpecifier::ZArg:
> + return false;
> + }
> + llvm_unreachable("Invalid ConversionSpecifier Kind!");
> +}
> +
> +bool FormatSpecifier::hasStandardLengthConversionCombination() const {
> + if (LM.getKind() == LengthModifier::AsLongDouble) {
> + switch(CS.getKind()) {
> + case ConversionSpecifier::dArg:
> + case ConversionSpecifier::iArg:
> + case ConversionSpecifier::oArg:
> + case ConversionSpecifier::uArg:
> + case ConversionSpecifier::xArg:
> + case ConversionSpecifier::XArg:
> + return false;
> + default:
> + return true;
> + }
> + }
> + return true;
> +}
> +
> +Optional<LengthModifier> FormatSpecifier::getCorrectedLengthModifier()
> const {
> + if (CS.isAnyIntArg() || CS.getKind() == ConversionSpecifier::nArg) {
> + if (LM.getKind() == LengthModifier::AsLongDouble ||
> + LM.getKind() == LengthModifier::AsQuad) {
> + LengthModifier FixedLM(LM);
> + FixedLM.setKind(LengthModifier::AsLongLong);
> + return FixedLM;
> + }
> + }
> +
> + return None;
> +}
> +
> +bool FormatSpecifier::namedTypeToLengthModifier(QualType QT,
> + LengthModifier &LM) {
> + assert(isa<TypedefType>(QT) && "Expected a TypedefType");
> + const TypedefNameDecl *Typedef = cast<TypedefType>(QT)->getDecl();
> +
> + for (;;) {
> + const IdentifierInfo *Identifier = Typedef->getIdentifier();
> + if (Identifier->getName() == "size_t") {
> + LM.setKind(LengthModifier::AsSizeT);
> + return true;
> + } else if (Identifier->getName() == "ssize_t") {
> + // Not C99, but common in Unix.
> + LM.setKind(LengthModifier::AsSizeT);
> + return true;
> + } else if (Identifier->getName() == "intmax_t") {
> + LM.setKind(LengthModifier::AsIntMax);
> + return true;
> + } else if (Identifier->getName() == "uintmax_t") {
> + LM.setKind(LengthModifier::AsIntMax);
> + return true;
> + } else if (Identifier->getName() == "ptrdiff_t") {
> + LM.setKind(LengthModifier::AsPtrDiff);
> + return true;
> + }
> +
> + QualType T = Typedef->getUnderlyingType();
> + if (!isa<TypedefType>(T))
> + break;
> +
> + Typedef = cast<TypedefType>(T)->getDecl();
> + }
> + return false;
> +}
>
> Added: cfe/trunk/lib/AST/FormatStringParsing.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/FormatStringParsing.h?rev=345971&view=auto
>
> ==============================================================================
> --- cfe/trunk/lib/AST/FormatStringParsing.h (added)
> +++ cfe/trunk/lib/AST/FormatStringParsing.h Fri Nov 2 06:14:11 2018
> @@ -0,0 +1,79 @@
> +#ifndef LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H
> +#define LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H
> +
> +#include "clang/AST/ASTContext.h"
> +#include "clang/AST/Type.h"
> +#include "clang/AST/FormatString.h"
> +
> +namespace clang {
> +
> +class LangOptions;
> +
> +template <typename T>
> +class UpdateOnReturn {
> + T &ValueToUpdate;
> + const T &ValueToCopy;
> +public:
> + UpdateOnReturn(T &valueToUpdate, const T &valueToCopy)
> + : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {}
> +
> + ~UpdateOnReturn() {
> + ValueToUpdate = ValueToCopy;
> + }
> +};
> +
> +namespace analyze_format_string {
> +
> +OptionalAmount ParseAmount(const char *&Beg, const char *E);
> +OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E,
> + unsigned &argIndex);
> +
> +OptionalAmount ParsePositionAmount(FormatStringHandler &H,
> + const char *Start, const char *&Beg,
> + const char *E, PositionContext p);
> +
> +bool ParseFieldWidth(FormatStringHandler &H,
> + FormatSpecifier &CS,
> + const char *Start, const char *&Beg, const char *E,
> + unsigned *argIndex);
> +
> +bool ParseArgPosition(FormatStringHandler &H,
> + FormatSpecifier &CS, const char *Start,
> + const char *&Beg, const char *E);
> +
> +/// Returns true if a LengthModifier was parsed and installed in the
> +/// FormatSpecifier& argument, and false otherwise.
> +bool ParseLengthModifier(FormatSpecifier &FS, const char *&Beg, const
> char *E,
> + const LangOptions &LO, bool IsScanf = false);
> +
> +/// Returns true if the invalid specifier in \p SpecifierBegin is a UTF-8
> +/// string; check that it won't go further than \p FmtStrEnd and write
> +/// up the total size in \p Len.
> +bool ParseUTF8InvalidSpecifier(const char *SpecifierBegin,
> + const char *FmtStrEnd, unsigned &Len);
> +
> +template <typename T> class SpecifierResult {
> + T FS;
> + const char *Start;
> + bool Stop;
> +public:
> + SpecifierResult(bool stop = false)
> + : Start(nullptr), Stop(stop) {}
> + SpecifierResult(const char *start,
> + const T &fs)
> + : FS(fs), Start(start), Stop(false) {}
> +
> + const char *getStart() const { return Start; }
> + bool shouldStop() const { return Stop; }
> + bool hasValue() const { return Start != nullptr; }
> + const T &getValue() const {
> + assert(hasValue());
> + return FS;
> + }
> + const T &getValue() { return FS; }
> +};
> +
> +} // end analyze_format_string namespace
> +} // end clang namespace
> +
> +#endif
>
> Added: cfe/trunk/lib/AST/OSLog.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/OSLog.cpp?rev=345971&view=auto
>
> ==============================================================================
> --- cfe/trunk/lib/AST/OSLog.cpp (added)
> +++ cfe/trunk/lib/AST/OSLog.cpp Fri Nov 2 06:14:11 2018
> @@ -0,0 +1,203 @@
> +// TODO: header template
> +
> +#include "clang/AST/OSLog.h"
> +#include "clang/AST/Attr.h"
> +#include "clang/AST/Decl.h"
> +#include "clang/AST/DeclCXX.h"
> +#include "clang/AST/ExprObjC.h"
> +#include "clang/AST/FormatString.h"
> +#include "clang/Basic/Builtins.h"
> +#include "llvm/ADT/SmallBitVector.h"
> +
> +using namespace clang;
> +
> +using clang::analyze_os_log::OSLogBufferItem;
> +using clang::analyze_os_log::OSLogBufferLayout;
> +
> +namespace {
> +class OSLogFormatStringHandler
> + : public analyze_format_string::FormatStringHandler {
> +private:
> + struct ArgData {
> + const Expr *E = nullptr;
> + Optional<OSLogBufferItem::Kind> Kind;
> + Optional<unsigned> Size;
> + Optional<const Expr *> Count;
> + Optional<const Expr *> Precision;
> + Optional<const Expr *> FieldWidth;
> + unsigned char Flags = 0;
> + };
> + SmallVector<ArgData, 4> ArgsData;
> + ArrayRef<const Expr *> Args;
> +
> + OSLogBufferItem::Kind
> + getKind(analyze_format_string::ConversionSpecifier::Kind K) {
> + switch (K) {
> + case clang::analyze_format_string::ConversionSpecifier::sArg: // "%s"
> + return OSLogBufferItem::StringKind;
> + case clang::analyze_format_string::ConversionSpecifier::SArg: // "%S"
> + return OSLogBufferItem::WideStringKind;
> + case clang::analyze_format_string::ConversionSpecifier::PArg: { //
> "%P"
> + return OSLogBufferItem::PointerKind;
> + case clang::analyze_format_string::ConversionSpecifier::ObjCObjArg:
> // "%@"
> + return OSLogBufferItem::ObjCObjKind;
> + case clang::analyze_format_string::ConversionSpecifier::PrintErrno:
> // "%m"
> + return OSLogBufferItem::ErrnoKind;
> + default:
> + return OSLogBufferItem::ScalarKind;
> + }
> + }
> + }
> +
> +public:
> + OSLogFormatStringHandler(ArrayRef<const Expr *> Args) : Args(Args) {
> + ArgsData.reserve(Args.size());
> + }
> +
> + virtual bool HandlePrintfSpecifier(const
> analyze_printf::PrintfSpecifier &FS,
> + const char *StartSpecifier,
> + unsigned SpecifierLen) {
> + if (!FS.consumesDataArgument() &&
> + FS.getConversionSpecifier().getKind() !=
> + clang::analyze_format_string::ConversionSpecifier::PrintErrno)
> + return true;
> +
> + ArgsData.emplace_back();
> + unsigned ArgIndex = FS.getArgIndex();
> + if (ArgIndex < Args.size())
> + ArgsData.back().E = Args[ArgIndex];
> +
> + // First get the Kind
> + ArgsData.back().Kind = getKind(FS.getConversionSpecifier().getKind());
> + if (ArgsData.back().Kind != OSLogBufferItem::ErrnoKind &&
> + !ArgsData.back().E) {
> + // missing argument
> + ArgsData.pop_back();
> + return false;
> + }
> +
> + switch (FS.getConversionSpecifier().getKind()) {
> + case clang::analyze_format_string::ConversionSpecifier::sArg: //
> "%s"
> + case clang::analyze_format_string::ConversionSpecifier::SArg: { //
> "%S"
> + auto &precision = FS.getPrecision();
> + switch (precision.getHowSpecified()) {
> + case clang::analyze_format_string::OptionalAmount::NotSpecified: //
> "%s"
> + break;
> + case clang::analyze_format_string::OptionalAmount::Constant: //
> "%.16s"
> + ArgsData.back().Size = precision.getConstantAmount();
> + break;
> + case clang::analyze_format_string::OptionalAmount::Arg: // "%.*s"
> + ArgsData.back().Count = Args[precision.getArgIndex()];
> + break;
> + case clang::analyze_format_string::OptionalAmount::Invalid:
> + return false;
> + }
> + break;
> + }
> + case clang::analyze_format_string::ConversionSpecifier::PArg: { //
> "%P"
> + auto &precision = FS.getPrecision();
> + switch (precision.getHowSpecified()) {
> + case clang::analyze_format_string::OptionalAmount::NotSpecified: //
> "%P"
> + return false; // length must be supplied with pointer format
> specifier
> + case clang::analyze_format_string::OptionalAmount::Constant: //
> "%.16P"
> + ArgsData.back().Size = precision.getConstantAmount();
> + break;
> + case clang::analyze_format_string::OptionalAmount::Arg: // "%.*P"
> + ArgsData.back().Count = Args[precision.getArgIndex()];
> + break;
> + case clang::analyze_format_string::OptionalAmount::Invalid:
> + return false;
> + }
> + break;
> + }
> + default:
> + if (FS.getPrecision().hasDataArgument()) {
> + ArgsData.back().Precision = Args[FS.getPrecision().getArgIndex()];
> + }
> + break;
> + }
> + if (FS.getFieldWidth().hasDataArgument()) {
> + ArgsData.back().FieldWidth = Args[FS.getFieldWidth().getArgIndex()];
> + }
> +
> + if (FS.isPrivate()) {
> + ArgsData.back().Flags |= OSLogBufferItem::IsPrivate;
> + }
> + if (FS.isPublic()) {
> + ArgsData.back().Flags |= OSLogBufferItem::IsPublic;
> + }
> + return true;
> + }
> +
> + void computeLayout(ASTContext &Ctx, OSLogBufferLayout &Layout) const {
> + Layout.Items.clear();
> + for (auto &Data : ArgsData) {
> + if (Data.FieldWidth) {
> + CharUnits Size =
> Ctx.getTypeSizeInChars((*Data.FieldWidth)->getType());
> + Layout.Items.emplace_back(OSLogBufferItem::ScalarKind,
> *Data.FieldWidth,
> + Size, 0);
> + }
> + if (Data.Precision) {
> + CharUnits Size =
> Ctx.getTypeSizeInChars((*Data.Precision)->getType());
> + Layout.Items.emplace_back(OSLogBufferItem::ScalarKind,
> *Data.Precision,
> + Size, 0);
> + }
> + if (Data.Count) {
> + // "%.*P" has an extra "count" that we insert before the argument.
> + CharUnits Size = Ctx.getTypeSizeInChars((*Data.Count)->getType());
> + Layout.Items.emplace_back(OSLogBufferItem::CountKind,
> *Data.Count, Size,
> + 0);
> + }
> + if (Data.Size)
> + Layout.Items.emplace_back(Ctx,
> CharUnits::fromQuantity(*Data.Size),
> + Data.Flags);
> + if (Data.Kind) {
> + CharUnits Size;
> + if (*Data.Kind == OSLogBufferItem::ErrnoKind)
> + Size = CharUnits::Zero();
> + else
> + Size = Ctx.getTypeSizeInChars(Data.E->getType());
> + Layout.Items.emplace_back(*Data.Kind, Data.E, Size, Data.Flags);
> + } else {
> + auto Size = Ctx.getTypeSizeInChars(Data.E->getType());
> + Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, Data.E,
> Size,
> + Data.Flags);
> + }
> + }
> + }
> +};
> +} // end anonymous namespace
> +
> +bool clang::analyze_os_log::computeOSLogBufferLayout(
> + ASTContext &Ctx, const CallExpr *E, OSLogBufferLayout &Layout) {
> + ArrayRef<const Expr *> Args(E->getArgs(), E->getArgs() +
> E->getNumArgs());
> +
> + const Expr *StringArg;
> + ArrayRef<const Expr *> VarArgs;
> + switch (E->getBuiltinCallee()) {
> + case Builtin::BI__builtin_os_log_format_buffer_size:
> + assert(E->getNumArgs() >= 1 &&
> + "__builtin_os_log_format_buffer_size takes at least 1
> argument");
> + StringArg = E->getArg(0);
> + VarArgs = Args.slice(1);
> + break;
> + case Builtin::BI__builtin_os_log_format:
> + assert(E->getNumArgs() >= 2 &&
> + "__builtin_os_log_format takes at least 2 arguments");
> + StringArg = E->getArg(1);
> + VarArgs = Args.slice(2);
> + break;
> + default:
> + llvm_unreachable("non-os_log builtin passed to
> computeOSLogBufferLayout");
> + }
> +
> + const StringLiteral *Lit =
> cast<StringLiteral>(StringArg->IgnoreParenCasts());
> + assert(Lit && (Lit->isAscii() || Lit->isUTF8()));
> + StringRef Data = Lit->getString();
> + OSLogFormatStringHandler H(VarArgs);
> + ParsePrintfString(H, Data.begin(), Data.end(), Ctx.getLangOpts(),
> + Ctx.getTargetInfo(), /*isFreeBSDKPrintf*/ false);
> +
> + H.computeLayout(Ctx, Layout);
> + return true;
> +}
>
> Added: cfe/trunk/lib/AST/PrintfFormatString.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/PrintfFormatString.cpp?rev=345971&view=auto
>
> ==============================================================================
> --- cfe/trunk/lib/AST/PrintfFormatString.cpp (added)
> +++ cfe/trunk/lib/AST/PrintfFormatString.cpp Fri Nov 2 06:14:11 2018
> @@ -0,0 +1,1029 @@
> +//== PrintfFormatString.cpp - Analysis of printf format strings --*- C++
> -*-==//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// Handling of format string in printf and friends. The structure of
> format
> +// strings for fprintf() are described in C99 7.19.6.1.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "clang/AST/FormatString.h"
> +#include "clang/AST/OSLog.h"
> +#include "FormatStringParsing.h"
> +#include "clang/Basic/TargetInfo.h"
> +
> +using clang::analyze_format_string::ArgType;
> +using clang::analyze_format_string::FormatStringHandler;
> +using clang::analyze_format_string::LengthModifier;
> +using clang::analyze_format_string::OptionalAmount;
> +using clang::analyze_format_string::ConversionSpecifier;
> +using clang::analyze_printf::PrintfSpecifier;
> +
> +using namespace clang;
> +
> +typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier>
> + PrintfSpecifierResult;
> +
>
> +//===----------------------------------------------------------------------===//
> +// Methods for parsing format strings.
>
> +//===----------------------------------------------------------------------===//
> +
> +using analyze_format_string::ParseNonPositionAmount;
> +
> +static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS,
> + const char *Start, const char *&Beg, const
> char *E,
> + unsigned *argIndex) {
> + if (argIndex) {
> + FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
> + } else {
> + const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
> +
> analyze_format_string::PrecisionPos);
> + if (Amt.isInvalid())
> + return true;
> + FS.setPrecision(Amt);
> + }
> + return false;
> +}
> +
> +static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS,
> + const char *FlagBeg, const char *E, bool Warn)
> {
> + StringRef Flag(FlagBeg, E - FlagBeg);
> + // Currently there is only one flag.
> + if (Flag == "tt") {
> + FS.setHasObjCTechnicalTerm(FlagBeg);
> + return false;
> + }
> + // Handle either the case of no flag or an invalid flag.
> + if (Warn) {
> + if (Flag == "")
> + H.HandleEmptyObjCModifierFlag(FlagBeg, E - FlagBeg);
> + else
> + H.HandleInvalidObjCModifierFlag(FlagBeg, E - FlagBeg);
> + }
> + return true;
> +}
> +
> +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);
> +}
> +
> +bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler
> &H,
> + const char *I,
> + const char *E,
> + const LangOptions
> &LO,
> + const TargetInfo
> &Target,
> + bool
> isFreeBSDKPrintf) {
> +
> + unsigned argIndex = 0;
> +
> + // Keep looking for a format specifier until we have exhausted the
> string.
> + while (I != E) {
> + const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E,
> argIndex,
> + LO, Target,
> true,
> +
> isFreeBSDKPrintf);
> + // Did a fail-stop error of any kind occur when parsing the specifier?
> + // If so, don't do any more processing.
> + if (FSR.shouldStop())
> + return true;
> + // Did we exhaust the string or encounter an error that
> + // we can recover from?
> + if (!FSR.hasValue())
> + continue;
> + // We have a format specifier. Pass it to the callback.
> + if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(),
> + I - FSR.getStart()))
> + return true;
> + }
> + assert(I == E && "Format string not exhausted");
> + return false;
> +}
> +
> +bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I,
> + const char *E,
> + const
> LangOptions &LO,
> + const
> TargetInfo &Target) {
> +
> + unsigned argIndex = 0;
> +
> + // Keep looking for a %s format specifier until we have exhausted the
> string.
> + FormatStringHandler H;
> + while (I != E) {
> + const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E,
> argIndex,
> + LO, Target,
> false,
> + false);
> + // Did a fail-stop error of any kind occur when parsing the specifier?
> + // If so, don't do any more processing.
> + if (FSR.shouldStop())
> + return false;
> + // Did we exhaust the string or encounter an error that
> + // we can recover from?
> + if (!FSR.hasValue())
> + continue;
> + const analyze_printf::PrintfSpecifier &FS = FSR.getValue();
> + // Return true if this a %s format specifier.
> + if (FS.getConversionSpecifier().getKind() ==
> ConversionSpecifier::Kind::sArg)
> + return true;
> + }
> + return false;
> +}
> +
>
> +//===----------------------------------------------------------------------===//
> +// Methods on PrintfSpecifier.
>
> +//===----------------------------------------------------------------------===//
> +
> +ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
> + bool IsObjCLiteral) const {
> + const PrintfConversionSpecifier &CS = getConversionSpecifier();
> +
> + if (!CS.consumesDataArgument())
> + return ArgType::Invalid();
> +
> + if (CS.getKind() == ConversionSpecifier::cArg)
> + switch (LM.getKind()) {
> + case LengthModifier::None:
> + return Ctx.IntTy;
> + case LengthModifier::AsLong:
> + case LengthModifier::AsWide:
> + return ArgType(ArgType::WIntTy, "wint_t");
> + case LengthModifier::AsShort:
> + if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
> + return Ctx.IntTy;
> + LLVM_FALLTHROUGH;
> + default:
> + return ArgType::Invalid();
> + }
> +
> + if (CS.isIntArg())
> + switch (LM.getKind()) {
> + case LengthModifier::AsLongDouble:
> + // GNU extension.
> + return Ctx.LongLongTy;
> + case LengthModifier::None:
> + return Ctx.IntTy;
> + case LengthModifier::AsInt32:
> + return ArgType(Ctx.IntTy, "__int32");
> + case LengthModifier::AsChar: return ArgType::AnyCharTy;
> + case LengthModifier::AsShort: return Ctx.ShortTy;
> + case LengthModifier::AsLong: return Ctx.LongTy;
> + case LengthModifier::AsLongLong:
> + case LengthModifier::AsQuad:
> + return Ctx.LongLongTy;
> + case LengthModifier::AsInt64:
> + return ArgType(Ctx.LongLongTy, "__int64");
> + case LengthModifier::AsIntMax:
> + return ArgType(Ctx.getIntMaxType(), "intmax_t");
> + case LengthModifier::AsSizeT:
> + return ArgType::makeSizeT(ArgType(Ctx.getSignedSizeType(),
> "ssize_t"));
> + case LengthModifier::AsInt3264:
> + return Ctx.getTargetInfo().getTriple().isArch64Bit()
> + ? ArgType(Ctx.LongLongTy, "__int64")
> + : ArgType(Ctx.IntTy, "__int32");
> + case LengthModifier::AsPtrDiff:
> + return ArgType::makePtrdiffT(
> + ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
> + case LengthModifier::AsAllocate:
> + case LengthModifier::AsMAllocate:
> + case LengthModifier::AsWide:
> + return ArgType::Invalid();
> + }
> +
> + if (CS.isUIntArg())
> + switch (LM.getKind()) {
> + case LengthModifier::AsLongDouble:
> + // GNU extension.
> + return Ctx.UnsignedLongLongTy;
> + case LengthModifier::None:
> + return Ctx.UnsignedIntTy;
> + case LengthModifier::AsInt32:
> + return ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
> + case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
> + case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
> + case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
> + case LengthModifier::AsLongLong:
> + case LengthModifier::AsQuad:
> + return Ctx.UnsignedLongLongTy;
> + case LengthModifier::AsInt64:
> + return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64");
> + case LengthModifier::AsIntMax:
> + return ArgType(Ctx.getUIntMaxType(), "uintmax_t");
> + case LengthModifier::AsSizeT:
> + return ArgType::makeSizeT(ArgType(Ctx.getSizeType(), "size_t"));
> + case LengthModifier::AsInt3264:
> + return Ctx.getTargetInfo().getTriple().isArch64Bit()
> + ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64")
> + : ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
> + case LengthModifier::AsPtrDiff:
> + return ArgType::makePtrdiffT(
> + ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned
> ptrdiff_t"));
> + case LengthModifier::AsAllocate:
> + case LengthModifier::AsMAllocate:
> + case LengthModifier::AsWide:
> + return ArgType::Invalid();
> + }
> +
> + if (CS.isDoubleArg()) {
> + if (LM.getKind() == LengthModifier::AsLongDouble)
> + return Ctx.LongDoubleTy;
> + return Ctx.DoubleTy;
> + }
> +
> + if (CS.getKind() == ConversionSpecifier::nArg) {
> + switch (LM.getKind()) {
> + case LengthModifier::None:
> + return ArgType::PtrTo(Ctx.IntTy);
> + case LengthModifier::AsChar:
> + return ArgType::PtrTo(Ctx.SignedCharTy);
> + case LengthModifier::AsShort:
> + return ArgType::PtrTo(Ctx.ShortTy);
> + case LengthModifier::AsLong:
> + return ArgType::PtrTo(Ctx.LongTy);
> + case LengthModifier::AsLongLong:
> + case LengthModifier::AsQuad:
> + return ArgType::PtrTo(Ctx.LongLongTy);
> + case LengthModifier::AsIntMax:
> + return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
> + case LengthModifier::AsSizeT:
> + return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(),
> "ssize_t"));
> + case LengthModifier::AsPtrDiff:
> + return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(),
> "ptrdiff_t"));
> + case LengthModifier::AsLongDouble:
> + return ArgType(); // FIXME: Is this a known extension?
> + case LengthModifier::AsAllocate:
> + case LengthModifier::AsMAllocate:
> + case LengthModifier::AsInt32:
> + case LengthModifier::AsInt3264:
> + case LengthModifier::AsInt64:
> + case LengthModifier::AsWide:
> + return ArgType::Invalid();
> + }
> + }
> +
> + switch (CS.getKind()) {
> + case ConversionSpecifier::sArg:
> + if (LM.getKind() == LengthModifier::AsWideChar) {
> + if (IsObjCLiteral)
> + return
> ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
> + "const unichar *");
> + return ArgType(ArgType::WCStrTy, "wchar_t *");
> + }
> + if (LM.getKind() == LengthModifier::AsWide)
> + return ArgType(ArgType::WCStrTy, "wchar_t *");
> + return ArgType::CStrTy;
> + case ConversionSpecifier::SArg:
> + if (IsObjCLiteral)
> + return
> ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
> + "const unichar *");
> + if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
> + LM.getKind() == LengthModifier::AsShort)
> + return ArgType::CStrTy;
> + return ArgType(ArgType::WCStrTy, "wchar_t *");
> + case ConversionSpecifier::CArg:
> + if (IsObjCLiteral)
> + return ArgType(Ctx.UnsignedShortTy, "unichar");
> + if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
> + LM.getKind() == LengthModifier::AsShort)
> + return Ctx.IntTy;
> + return ArgType(Ctx.WideCharTy, "wchar_t");
> + case ConversionSpecifier::pArg:
> + case ConversionSpecifier::PArg:
> + return ArgType::CPointerTy;
> + case ConversionSpecifier::ObjCObjArg:
> + return ArgType::ObjCPointerTy;
> + default:
> + break;
> + }
> +
> + // FIXME: Handle other cases.
> + return ArgType();
> +}
> +
> +bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
> + ASTContext &Ctx, bool IsObjCLiteral) {
> + // %n is different from other conversion specifiers; don't try to fix
> it.
> + if (CS.getKind() == ConversionSpecifier::nArg)
> + return false;
> +
> + // Handle Objective-C objects first. Note that while the '%@' specifier
> will
> + // not warn for structure pointer or void pointer arguments (because
> that's
> + // how CoreFoundation objects are implemented), we only show a fixit
> for '%@'
> + // if we know it's an object (block, id, class, or
> __attribute__((NSObject))).
> + if (QT->isObjCRetainableType()) {
> + if (!IsObjCLiteral)
> + return false;
> +
> + CS.setKind(ConversionSpecifier::ObjCObjArg);
> +
> + // Disable irrelevant flags
> + HasThousandsGrouping = false;
> + HasPlusPrefix = false;
> + HasSpacePrefix = false;
> + HasAlternativeForm = false;
> + HasLeadingZeroes = false;
> + Precision.setHowSpecified(OptionalAmount::NotSpecified);
> + LM.setKind(LengthModifier::None);
> +
> + return true;
> + }
> +
> + // Handle strings next (char *, wchar_t *)
> + if (QT->isPointerType() &&
> (QT->getPointeeType()->isAnyCharacterType())) {
> + CS.setKind(ConversionSpecifier::sArg);
> +
> + // Disable irrelevant flags
> + HasAlternativeForm = 0;
> + HasLeadingZeroes = 0;
> +
> + // Set the long length modifier for wide characters
> + if (QT->getPointeeType()->isWideCharType())
> + LM.setKind(LengthModifier::AsWideChar);
> + else
> + LM.setKind(LengthModifier::None);
> +
> + return true;
> + }
> +
> + // If it's an enum, get its underlying type.
> + if (const EnumType *ETy = QT->getAs<EnumType>())
> + QT = ETy->getDecl()->getIntegerType();
> +
> + // We can only work with builtin types.
> + const BuiltinType *BT = QT->getAs<BuiltinType>();
> + if (!BT)
> + return false;
> +
> + // Set length modifier
> + switch (BT->getKind()) {
> + case BuiltinType::Bool:
> + case BuiltinType::WChar_U:
> + case BuiltinType::WChar_S:
> + case BuiltinType::Char8: // FIXME: Treat like 'char'?
> + case BuiltinType::Char16:
> + case BuiltinType::Char32:
> + case BuiltinType::UInt128:
> + case BuiltinType::Int128:
> + case BuiltinType::Half:
> + case BuiltinType::Float16:
> + case BuiltinType::Float128:
> + case BuiltinType::ShortAccum:
> + case BuiltinType::Accum:
> + case BuiltinType::LongAccum:
> + case BuiltinType::UShortAccum:
> + case BuiltinType::UAccum:
> + case BuiltinType::ULongAccum:
> + case BuiltinType::ShortFract:
> + case BuiltinType::Fract:
> + case BuiltinType::LongFract:
> + case BuiltinType::UShortFract:
> + case BuiltinType::UFract:
> + case BuiltinType::ULongFract:
> + case BuiltinType::SatShortAccum:
> + case BuiltinType::SatAccum:
> + case BuiltinType::SatLongAccum:
> + case BuiltinType::SatUShortAccum:
> + case BuiltinType::SatUAccum:
> + case BuiltinType::SatULongAccum:
> + case BuiltinType::SatShortFract:
> + case BuiltinType::SatFract:
> + case BuiltinType::SatLongFract:
> + case BuiltinType::SatUShortFract:
> + case BuiltinType::SatUFract:
> + case BuiltinType::SatULongFract:
> + // Various types which are non-trivial to correct.
> + return false;
> +
> +#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
> + case BuiltinType::Id:
> +#include "clang/Basic/OpenCLImageTypes.def"
> +#define SIGNED_TYPE(Id, SingletonId)
> +#define UNSIGNED_TYPE(Id, SingletonId)
> +#define FLOATING_TYPE(Id, SingletonId)
> +#define BUILTIN_TYPE(Id, SingletonId) \
> + case BuiltinType::Id:
> +#include "clang/AST/BuiltinTypes.def"
> + // Misc other stuff which doesn't make sense here.
> + return false;
> +
> + case BuiltinType::UInt:
> + case BuiltinType::Int:
> + case BuiltinType::Float:
> + case BuiltinType::Double:
> + LM.setKind(LengthModifier::None);
> + break;
> +
> + case BuiltinType::Char_U:
> + case BuiltinType::UChar:
> + case BuiltinType::Char_S:
> + case BuiltinType::SChar:
> + LM.setKind(LengthModifier::AsChar);
> + break;
> +
> + case BuiltinType::Short:
> + case BuiltinType::UShort:
> + LM.setKind(LengthModifier::AsShort);
> + break;
> +
> + case BuiltinType::Long:
> + case BuiltinType::ULong:
> + LM.setKind(LengthModifier::AsLong);
> + break;
> +
> + case BuiltinType::LongLong:
> + case BuiltinType::ULongLong:
> + LM.setKind(LengthModifier::AsLongLong);
> + break;
> +
> + case BuiltinType::LongDouble:
> + LM.setKind(LengthModifier::AsLongDouble);
> + break;
> + }
> +
> + // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers
> in C99.
> + if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
> + namedTypeToLengthModifier(QT, LM);
> +
> + // If fixing the length modifier was enough, we might be done.
> + if (hasValidLengthModifier(Ctx.getTargetInfo())) {
> + // If we're going to offer a fix anyway, make sure the sign matches.
> + switch (CS.getKind()) {
> + case ConversionSpecifier::uArg:
> + case ConversionSpecifier::UArg:
> + if (QT->isSignedIntegerType())
> +
> CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg);
> + break;
> + case ConversionSpecifier::dArg:
> + case ConversionSpecifier::DArg:
> + case ConversionSpecifier::iArg:
> + if (QT->isUnsignedIntegerType() && !HasPlusPrefix)
> +
> CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg);
> + break;
> + default:
> + // Other specifiers do not have signed/unsigned variants.
> + break;
> + }
> +
> + const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
> + if (ATR.isValid() && ATR.matchesType(Ctx, QT))
> + return true;
> + }
> +
> + // Set conversion specifier and disable any flags which do not apply to
> it.
> + // Let typedefs to char fall through to int, as %c is silly for uint8_t.
> + if (!isa<TypedefType>(QT) && QT->isCharType()) {
> + CS.setKind(ConversionSpecifier::cArg);
> + LM.setKind(LengthModifier::None);
> + Precision.setHowSpecified(OptionalAmount::NotSpecified);
> + HasAlternativeForm = 0;
> + HasLeadingZeroes = 0;
> + HasPlusPrefix = 0;
> + }
> + // Test for Floating type first as LongDouble can pass
> isUnsignedIntegerType
> + else if (QT->isRealFloatingType()) {
> + CS.setKind(ConversionSpecifier::fArg);
> + }
> + else if (QT->isSignedIntegerType()) {
> + CS.setKind(ConversionSpecifier::dArg);
> + HasAlternativeForm = 0;
> + }
> + else if (QT->isUnsignedIntegerType()) {
> + CS.setKind(ConversionSpecifier::uArg);
> + HasAlternativeForm = 0;
> + HasPlusPrefix = 0;
> + } else {
> + llvm_unreachable("Unexpected type");
> + }
> +
> + return true;
> +}
> +
> +void PrintfSpecifier::toString(raw_ostream &os) const {
> + // Whilst some features have no defined order, we are using the order
> + // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)
> + os << "%";
> +
> + // Positional args
> + if (usesPositionalArg()) {
> + os << getPositionalArgIndex() << "$";
> + }
> +
> + // Conversion flags
> + if (IsLeftJustified) os << "-";
> + if (HasPlusPrefix) os << "+";
> + if (HasSpacePrefix) os << " ";
> + if (HasAlternativeForm) os << "#";
> + if (HasLeadingZeroes) os << "0";
> +
> + // Minimum field width
> + FieldWidth.toString(os);
> + // Precision
> + Precision.toString(os);
> + // Length modifier
> + os << LM.toString();
> + // Conversion specifier
> + os << CS.toString();
> +}
> +
> +bool PrintfSpecifier::hasValidPlusPrefix() const {
> + if (!HasPlusPrefix)
> + return true;
> +
> + // The plus prefix only makes sense for signed conversions
> + switch (CS.getKind()) {
> + case ConversionSpecifier::dArg:
> + case ConversionSpecifier::DArg:
> + case ConversionSpecifier::iArg:
> + case ConversionSpecifier::fArg:
> + case ConversionSpecifier::FArg:
> + case ConversionSpecifier::eArg:
> + case ConversionSpecifier::EArg:
> + case ConversionSpecifier::gArg:
> + case ConversionSpecifier::GArg:
> + case ConversionSpecifier::aArg:
> + case ConversionSpecifier::AArg:
> + case ConversionSpecifier::FreeBSDrArg:
> + case ConversionSpecifier::FreeBSDyArg:
> + return true;
> +
> + default:
> + return false;
> + }
> +}
> +
> +bool PrintfSpecifier::hasValidAlternativeForm() const {
> + if (!HasAlternativeForm)
> + return true;
> +
> + // Alternate form flag only valid with the oxXaAeEfFgG conversions
> + switch (CS.getKind()) {
> + case ConversionSpecifier::oArg:
> + case ConversionSpecifier::OArg:
> + case ConversionSpecifier::xArg:
> + case ConversionSpecifier::XArg:
> + case ConversionSpecifier::aArg:
> + case ConversionSpecifier::AArg:
> + case ConversionSpecifier::eArg:
> + case ConversionSpecifier::EArg:
> + case ConversionSpecifier::fArg:
> + case ConversionSpecifier::FArg:
> + case ConversionSpecifier::gArg:
> + case ConversionSpecifier::GArg:
> + case ConversionSpecifier::FreeBSDrArg:
> + case ConversionSpecifier::FreeBSDyArg:
> + return true;
> +
> + default:
> + return false;
> + }
> +}
> +
> +bool PrintfSpecifier::hasValidLeadingZeros() const {
> + if (!HasLeadingZeroes)
> + return true;
> +
> + // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions
> + switch (CS.getKind()) {
> + case ConversionSpecifier::dArg:
> + case ConversionSpecifier::DArg:
> + case ConversionSpecifier::iArg:
> + case ConversionSpecifier::oArg:
> + case ConversionSpecifier::OArg:
> + case ConversionSpecifier::uArg:
> + case ConversionSpecifier::UArg:
> + case ConversionSpecifier::xArg:
> + case ConversionSpecifier::XArg:
> + case ConversionSpecifier::aArg:
> + case ConversionSpecifier::AArg:
> + case ConversionSpecifier::eArg:
> + case ConversionSpecifier::EArg:
> + case ConversionSpecifier::fArg:
> + case ConversionSpecifier::FArg:
> + case ConversionSpecifier::gArg:
> + case ConversionSpecifier::GArg:
> + case ConversionSpecifier::FreeBSDrArg:
> + case ConversionSpecifier::FreeBSDyArg:
> + return true;
> +
> + default:
> + return false;
> + }
> +}
> +
> +bool PrintfSpecifier::hasValidSpacePrefix() const {
> + if (!HasSpacePrefix)
> + return true;
> +
> + // The space prefix only makes sense for signed conversions
> + switch (CS.getKind()) {
> + case ConversionSpecifier::dArg:
> + case ConversionSpecifier::DArg:
> + case ConversionSpecifier::iArg:
> + case ConversionSpecifier::fArg:
> + case ConversionSpecifier::FArg:
> + case ConversionSpecifier::eArg:
> + case ConversionSpecifier::EArg:
> + case ConversionSpecifier::gArg:
> + case ConversionSpecifier::GArg:
> + case ConversionSpecifier::aArg:
> + case ConversionSpecifier::AArg:
> + case ConversionSpecifier::FreeBSDrArg:
> + case ConversionSpecifier::FreeBSDyArg:
> + return true;
> +
> + default:
> + return false;
> + }
> +}
> +
> +bool PrintfSpecifier::hasValidLeftJustified() const {
> + if (!IsLeftJustified)
> + return true;
> +
> + // The left justified flag is valid for all conversions except n
> + switch (CS.getKind()) {
> + case ConversionSpecifier::nArg:
> + return false;
> +
> + default:
> + return true;
> + }
> +}
> +
> +bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const {
> + if (!HasThousandsGrouping)
> + return true;
> +
> + switch (CS.getKind()) {
> + case ConversionSpecifier::dArg:
> + case ConversionSpecifier::DArg:
> + case ConversionSpecifier::iArg:
> + case ConversionSpecifier::uArg:
> + case ConversionSpecifier::UArg:
> + case ConversionSpecifier::fArg:
> + case ConversionSpecifier::FArg:
> + case ConversionSpecifier::gArg:
> + case ConversionSpecifier::GArg:
> + return true;
> + default:
> + return false;
> + }
> +}
> +
> +bool PrintfSpecifier::hasValidPrecision() const {
> + if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
> + return true;
> +
> + // Precision is only valid with the diouxXaAeEfFgGsP conversions
> + switch (CS.getKind()) {
> + case ConversionSpecifier::dArg:
> + case ConversionSpecifier::DArg:
> + case ConversionSpecifier::iArg:
> + case ConversionSpecifier::oArg:
> + case ConversionSpecifier::OArg:
> + case ConversionSpecifier::uArg:
> + case ConversionSpecifier::UArg:
> + case ConversionSpecifier::xArg:
> + case ConversionSpecifier::XArg:
> + case ConversionSpecifier::aArg:
> + case ConversionSpecifier::AArg:
> + case ConversionSpecifier::eArg:
> + case ConversionSpecifier::EArg:
> + case ConversionSpecifier::fArg:
> + case ConversionSpecifier::FArg:
> + case ConversionSpecifier::gArg:
> + case ConversionSpecifier::GArg:
> + case ConversionSpecifier::sArg:
> + case ConversionSpecifier::FreeBSDrArg:
> + case ConversionSpecifier::FreeBSDyArg:
> + case ConversionSpecifier::PArg:
> + return true;
> +
> + default:
> + return false;
> + }
> +}
> +bool PrintfSpecifier::hasValidFieldWidth() const {
> + if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)
> + return true;
> +
> + // The field width is valid for all conversions except n
> + switch (CS.getKind()) {
> + case ConversionSpecifier::nArg:
> + return false;
> +
> + default:
> + return true;
> + }
> +}
>
> Added: cfe/trunk/lib/AST/ScanfFormatString.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ScanfFormatString.cpp?rev=345971&view=auto
>
> ==============================================================================
> --- cfe/trunk/lib/AST/ScanfFormatString.cpp (added)
> +++ cfe/trunk/lib/AST/ScanfFormatString.cpp Fri Nov 2 06:14:11 2018
> @@ -0,0 +1,563 @@
> +//= ScanfFormatString.cpp - Analysis of printf format strings --*- C++
> -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// Handling of format string in scanf and friends. The structure of
> format
> +// strings for fscanf() are described in C99 7.19.6.2.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "clang/AST/FormatString.h"
> +#include "FormatStringParsing.h"
> +#include "clang/Basic/TargetInfo.h"
> +
> +using clang::analyze_format_string::ArgType;
> +using clang::analyze_format_string::FormatStringHandler;
> +using clang::analyze_format_string::LengthModifier;
> +using clang::analyze_format_string::OptionalAmount;
> +using clang::analyze_format_string::ConversionSpecifier;
> +using clang::analyze_scanf::ScanfConversionSpecifier;
> +using clang::analyze_scanf::ScanfSpecifier;
> +using clang::UpdateOnReturn;
> +using namespace clang;
> +
> +typedef clang::analyze_format_string::SpecifierResult<ScanfSpecifier>
> + ScanfSpecifierResult;
> +
> +static bool ParseScanList(FormatStringHandler &H,
> + ScanfConversionSpecifier &CS,
> + const char *&Beg, const char *E) {
> + const char *I = Beg;
> + const char *start = I - 1;
> + UpdateOnReturn <const char*> UpdateBeg(Beg, I);
> +
> + // No more characters?
> + if (I == E) {
> + H.HandleIncompleteScanList(start, I);
> + return true;
> + }
> +
> + // Special case: ']' is the first character.
> + if (*I == ']') {
> + if (++I == E) {
> + H.HandleIncompleteScanList(start, I - 1);
> + return true;
> + }
> + }
> +
> + // Special case: "^]" are the first characters.
> + if (I + 1 != E && I[0] == '^' && I[1] == ']') {
> + I += 2;
> + if (I == E) {
> + H.HandleIncompleteScanList(start, I - 1);
> + return true;
> + }
> + }
> +
> + // Look for a ']' character which denotes the end of the scan list.
> + while (*I != ']') {
> + if (++I == E) {
> + H.HandleIncompleteScanList(start, I - 1);
> + return true;
> + }
> + }
> +
> + CS.setEndScanList(I);
> + return false;
> +}
> +
> +// FIXME: Much of this is copy-paste from ParsePrintfSpecifier.
> +// We can possibly refactor.
> +static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
> + const char *&Beg,
> + const char *E,
> + unsigned &argIndex,
> + const LangOptions &LO,
> + const TargetInfo &Target)
> {
> + using namespace clang::analyze_format_string;
> + using namespace clang::analyze_scanf;
> + 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?
> + H.HandleIncompleteSpecifier(Start, E - Start);
> + return true;
> + }
> +
> + ScanfSpecifier 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 '*' flag if it is present.
> + if (*I == '*') {
> + FS.setSuppressAssignment(I);
> + if (++I == E) {
> + H.HandleIncompleteSpecifier(Start, E - Start);
> + return true;
> + }
> + }
> +
> + // Look for the field width (if any). Unlike printf, this is either
> + // a fixed integer or isn't present.
> + const OptionalAmount &Amt =
> clang::analyze_format_string::ParseAmount(I, E);
> + if (Amt.getHowSpecified() != OptionalAmount::NotSpecified) {
> + assert(Amt.getHowSpecified() == OptionalAmount::Constant);
> + FS.setFieldWidth(Amt);
> +
> + if (I == E) {
> + // No more characters left?
> + H.HandleIncompleteSpecifier(Start, E - Start);
> + return true;
> + }
> + }
> +
> + // Look for the length modifier.
> + if (ParseLengthModifier(FS, I, E, LO, /*scanf=*/true) && I == E) {
> + // No more characters left?
> + H.HandleIncompleteSpecifier(Start, E - Start);
> + return true;
> + }
> +
> + // Detect spurious null characters, which are likely errors.
> + if (*I == '\0') {
> + H.HandleNullChar(I);
> + return true;
> + }
> +
> + // Finally, look for the conversion specifier.
> + const char *conversionPosition = I++;
> + ScanfConversionSpecifier::Kind k =
> ScanfConversionSpecifier::InvalidSpecifier;
> + switch (*conversionPosition) {
> + default:
> + break;
> + 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 '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 'c': k = ConversionSpecifier::cArg; break;
> + case 'C': k = ConversionSpecifier::CArg; break;
> + case 'S': k = ConversionSpecifier::SArg; break;
> + case '[': k = ConversionSpecifier::ScanListArg; break;
> + case 'u': k = ConversionSpecifier::uArg; break;
> + case 'x': k = ConversionSpecifier::xArg; break;
> + case 'o': k = ConversionSpecifier::oArg; break;
> + case 's': k = ConversionSpecifier::sArg; break;
> + case 'p': k = ConversionSpecifier::pArg; break;
> + // Apple extensions
> + // Apple-specific
> + case 'D':
> + 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;
> + }
> + ScanfConversionSpecifier CS(conversionPosition, k);
> + if (k == ScanfConversionSpecifier::ScanListArg) {
> + if (ParseScanList(H, CS, I, E))
> + return true;
> + }
> + FS.setConversionSpecifier(CS);
> + if (CS.consumesDataArgument() && !FS.getSuppressAssignment()
> + && !FS.usesPositionalArg())
> + FS.setArgIndex(argIndex++);
> +
> + // FIXME: '%' and '*' doesn't make sense. Issue a warning.
> + // FIXME: 'ConsumedSoFar' and '*' doesn't make sense.
> +
> + if (k == ScanfConversionSpecifier::InvalidSpecifier) {
> + unsigned Len = I - Beg;
> + if (ParseUTF8InvalidSpecifier(Beg, E, Len)) {
> + CS.setEndScanList(Beg + Len);
> + FS.setConversionSpecifier(CS);
> + }
> + // Assume the conversion takes one argument.
> + return !H.HandleInvalidScanfConversionSpecifier(FS, Beg, Len);
> + }
> + return ScanfSpecifierResult(Start, FS);
> +}
> +
> +ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
> + const ScanfConversionSpecifier &CS = getConversionSpecifier();
> +
> + if (!CS.consumesDataArgument())
> + return ArgType::Invalid();
> +
> + switch(CS.getKind()) {
> + // Signed int.
> + case ConversionSpecifier::dArg:
> + case ConversionSpecifier::DArg:
> + case ConversionSpecifier::iArg:
> + switch (LM.getKind()) {
> + case LengthModifier::None:
> + return ArgType::PtrTo(Ctx.IntTy);
> + case LengthModifier::AsChar:
> + return ArgType::PtrTo(ArgType::AnyCharTy);
> + case LengthModifier::AsShort:
> + return ArgType::PtrTo(Ctx.ShortTy);
> + case LengthModifier::AsLong:
> + return ArgType::PtrTo(Ctx.LongTy);
> + case LengthModifier::AsLongLong:
> + case LengthModifier::AsQuad:
> + return ArgType::PtrTo(Ctx.LongLongTy);
> + case LengthModifier::AsInt64:
> + return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));
> + case LengthModifier::AsIntMax:
> + return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
> + case LengthModifier::AsSizeT:
> + return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(),
> "ssize_t"));
> + case LengthModifier::AsPtrDiff:
> + return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(),
> "ptrdiff_t"));
> + case LengthModifier::AsLongDouble:
> + // GNU extension.
> + return ArgType::PtrTo(Ctx.LongLongTy);
> + case LengthModifier::AsAllocate:
> + case LengthModifier::AsMAllocate:
> + case LengthModifier::AsInt32:
> + case LengthModifier::AsInt3264:
> + case LengthModifier::AsWide:
> + return ArgType::Invalid();
> + }
> +
> + // Unsigned int.
> + case ConversionSpecifier::oArg:
> + case ConversionSpecifier::OArg:
> + case ConversionSpecifier::uArg:
> + case ConversionSpecifier::UArg:
> + case ConversionSpecifier::xArg:
> + case ConversionSpecifier::XArg:
> + switch (LM.getKind()) {
> + case LengthModifier::None:
> + return ArgType::PtrTo(Ctx.UnsignedIntTy);
> + case LengthModifier::AsChar:
> + return ArgType::PtrTo(Ctx.UnsignedCharTy);
> + case LengthModifier::AsShort:
> + return ArgType::PtrTo(Ctx.UnsignedShortTy);
> + case LengthModifier::AsLong:
> + return ArgType::PtrTo(Ctx.UnsignedLongTy);
> + case LengthModifier::AsLongLong:
> + case LengthModifier::AsQuad:
> + return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
> + case LengthModifier::AsInt64:
> + return ArgType::PtrTo(ArgType(Ctx.UnsignedLongLongTy, "unsigned
> __int64"));
> + case LengthModifier::AsIntMax:
> + return ArgType::PtrTo(ArgType(Ctx.getUIntMaxType(),
> "uintmax_t"));
> + case LengthModifier::AsSizeT:
> + return ArgType::PtrTo(ArgType(Ctx.getSizeType(), "size_t"));
> + case LengthModifier::AsPtrDiff:
> + return ArgType::PtrTo(
> + ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned
> ptrdiff_t"));
> + case LengthModifier::AsLongDouble:
> + // GNU extension.
> + return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
> + case LengthModifier::AsAllocate:
> + case LengthModifier::AsMAllocate:
> + case LengthModifier::AsInt32:
> + case LengthModifier::AsInt3264:
> + case LengthModifier::AsWide:
> + return ArgType::Invalid();
> + }
> +
> + // Float.
> + case ConversionSpecifier::aArg:
> + case ConversionSpecifier::AArg:
> + case ConversionSpecifier::eArg:
> + case ConversionSpecifier::EArg:
> + case ConversionSpecifier::fArg:
> + case ConversionSpecifier::FArg:
> + case ConversionSpecifier::gArg:
> + case ConversionSpecifier::GArg:
> + switch (LM.getKind()) {
> + case LengthModifier::None:
> + return ArgType::PtrTo(Ctx.FloatTy);
> + case LengthModifier::AsLong:
> + return ArgType::PtrTo(Ctx.DoubleTy);
> + case LengthModifier::AsLongDouble:
> + return ArgType::PtrTo(Ctx.LongDoubleTy);
> + default:
> + return ArgType::Invalid();
> + }
> +
> + // Char, string and scanlist.
> + case ConversionSpecifier::cArg:
> + case ConversionSpecifier::sArg:
> + case ConversionSpecifier::ScanListArg:
> + switch (LM.getKind()) {
> + case LengthModifier::None:
> + return ArgType::PtrTo(ArgType::AnyCharTy);
> + case LengthModifier::AsLong:
> + case LengthModifier::AsWide:
> + return ArgType::PtrTo(ArgType(Ctx.getWideCharType(),
> "wchar_t"));
> + case LengthModifier::AsAllocate:
> + case LengthModifier::AsMAllocate:
> + return ArgType::PtrTo(ArgType::CStrTy);
> + case LengthModifier::AsShort:
> + if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
> + return ArgType::PtrTo(ArgType::AnyCharTy);
> + LLVM_FALLTHROUGH;
> + default:
> + return ArgType::Invalid();
> + }
> + case ConversionSpecifier::CArg:
> + case ConversionSpecifier::SArg:
> + // FIXME: Mac OS X specific?
> + switch (LM.getKind()) {
> + case LengthModifier::None:
> + case LengthModifier::AsWide:
> + return ArgType::PtrTo(ArgType(Ctx.getWideCharType(),
> "wchar_t"));
> + case LengthModifier::AsAllocate:
> + case LengthModifier::AsMAllocate:
> + return ArgType::PtrTo(ArgType(ArgType::WCStrTy, "wchar_t *"));
> + case LengthModifier::AsShort:
> + if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
> + return ArgType::PtrTo(ArgType::AnyCharTy);
> + LLVM_FALLTHROUGH;
> + default:
> + return ArgType::Invalid();
> + }
> +
> + // Pointer.
> + case ConversionSpecifier::pArg:
> + return ArgType::PtrTo(ArgType::CPointerTy);
> +
> + // Write-back.
> + case ConversionSpecifier::nArg:
> + switch (LM.getKind()) {
> + case LengthModifier::None:
> + return ArgType::PtrTo(Ctx.IntTy);
> + case LengthModifier::AsChar:
> + return ArgType::PtrTo(Ctx.SignedCharTy);
> + case LengthModifier::AsShort:
> + return ArgType::PtrTo(Ctx.ShortTy);
> + case LengthModifier::AsLong:
> + return ArgType::PtrTo(Ctx.LongTy);
> + case LengthModifier::AsLongLong:
> + case LengthModifier::AsQuad:
> + return ArgType::PtrTo(Ctx.LongLongTy);
> + case LengthModifier::AsInt64:
> + return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));
> + case LengthModifier::AsIntMax:
> + return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
> + case LengthModifier::AsSizeT:
> + return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(),
> "ssize_t"));
> + case LengthModifier::AsPtrDiff:
> + return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(),
> "ptrdiff_t"));
> + case LengthModifier::AsLongDouble:
> + return ArgType(); // FIXME: Is this a known extension?
> + case LengthModifier::AsAllocate:
> + case LengthModifier::AsMAllocate:
> + case LengthModifier::AsInt32:
> + case LengthModifier::AsInt3264:
> + case LengthModifier::AsWide:
> + return ArgType::Invalid();
> + }
> +
> + default:
> + break;
> + }
> +
> + return ArgType();
> +}
> +
> +bool ScanfSpecifier::fixType(QualType QT, QualType RawQT,
> + const LangOptions &LangOpt,
> + ASTContext &Ctx) {
> +
> + // %n is different from other conversion specifiers; don't try to fix
> it.
> + if (CS.getKind() == ConversionSpecifier::nArg)
> + return false;
> +
> + if (!QT->isPointerType())
> + return false;
> +
> + QualType PT = QT->getPointeeType();
> +
> + // If it's an enum, get its underlying type.
> + if (const EnumType *ETy = PT->getAs<EnumType>()) {
> + // Don't try to fix incomplete enums.
> + if (!ETy->getDecl()->isComplete())
> + return false;
> + PT = ETy->getDecl()->getIntegerType();
> + }
> +
> + const BuiltinType *BT = PT->getAs<BuiltinType>();
> + if (!BT)
> + return false;
> +
> + // Pointer to a character.
> + if (PT->isAnyCharacterType()) {
> + CS.setKind(ConversionSpecifier::sArg);
> + if (PT->isWideCharType())
> + LM.setKind(LengthModifier::AsWideChar);
> + else
> + LM.setKind(LengthModifier::None);
> +
> + // If we know the target array length, we can use it as a field width.
> + if (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(RawQT))
> {
> + if (CAT->getSizeModifier() == ArrayType::Normal)
> + FieldWidth = OptionalAmount(OptionalAmount::Constant,
> + CAT->getSize().getZExtValue() - 1,
> + "", 0, false);
> +
> + }
> + return true;
> + }
> +
> + // Figure out the length modifier.
> + switch (BT->getKind()) {
> + // no modifier
> + case BuiltinType::UInt:
> + case BuiltinType::Int:
> + case BuiltinType::Float:
> + LM.setKind(LengthModifier::None);
> + break;
> +
> + // hh
> + case BuiltinType::Char_U:
> + case BuiltinType::UChar:
> + case BuiltinType::Char_S:
> + case BuiltinType::SChar:
> + LM.setKind(LengthModifier::AsChar);
> + break;
> +
> + // h
> + case BuiltinType::Short:
> + case BuiltinType::UShort:
> + LM.setKind(LengthModifier::AsShort);
> + break;
> +
> + // l
> + case BuiltinType::Long:
> + case BuiltinType::ULong:
> + case BuiltinType::Double:
> + LM.setKind(LengthModifier::AsLong);
> + break;
> +
> + // ll
> + case BuiltinType::LongLong:
> + case BuiltinType::ULongLong:
> + LM.setKind(LengthModifier::AsLongLong);
> + break;
> +
> + // L
> + case BuiltinType::LongDouble:
> + LM.setKind(LengthModifier::AsLongDouble);
> + break;
> +
> + // Don't know.
> + default:
> + return false;
> + }
> +
> + // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers
> in C99.
> + if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
> + namedTypeToLengthModifier(PT, LM);
> +
> + // If fixing the length modifier was enough, we are done.
> + if (hasValidLengthModifier(Ctx.getTargetInfo())) {
> + const analyze_scanf::ArgType &AT = getArgType(Ctx);
> + if (AT.isValid() && AT.matchesType(Ctx, QT))
> + return true;
> + }
> +
> + // Figure out the conversion specifier.
> + if (PT->isRealFloatingType())
> + CS.setKind(ConversionSpecifier::fArg);
> + else if (PT->isSignedIntegerType())
> + CS.setKind(ConversionSpecifier::dArg);
> + else if (PT->isUnsignedIntegerType())
> + CS.setKind(ConversionSpecifier::uArg);
> + else
> + llvm_unreachable("Unexpected type");
> +
> + return true;
> +}
> +
> +void ScanfSpecifier::toString(raw_ostream &os) const {
> + os << "%";
> +
> + if (usesPositionalArg())
> + os << getPositionalArgIndex() << "$";
> + if (SuppressAssignment)
> + os << "*";
> +
> + FieldWidth.toString(os);
> + os << LM.toString();
> + os << CS.toString();
> +}
> +
> +bool clang::analyze_format_string::ParseScanfString(FormatStringHandler
> &H,
> + const char *I,
> + const char *E,
> + const LangOptions &LO,
> + const TargetInfo
> &Target) {
> +
> + unsigned argIndex = 0;
> +
> + // Keep looking for a format specifier until we have exhausted the
> string.
> + while (I != E) {
> + const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E,
> argIndex,
> + LO, Target);
> + // Did a fail-stop error of any kind occur when parsing the specifier?
> + // If so, don't do any more processing.
> + if (FSR.shouldStop())
> + return true;
> + // Did we exhaust the string or encounter an error that
> + // we can recover from?
> + if (!FSR.hasValue())
> + continue;
> + // We have a format specifier. Pass it to the callback.
> + if (!H.HandleScanfSpecifier(FSR.getValue(), FSR.getStart(),
> + I - FSR.getStart())) {
> + return true;
> + }
> + }
> + assert(I == E && "Format string not exhausted");
> + return false;
> +}
>
> Modified: cfe/trunk/lib/Analysis/CMakeLists.txt
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CMakeLists.txt?rev=345971&r1=345970&r2=345971&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Analysis/CMakeLists.txt (original)
> +++ cfe/trunk/lib/Analysis/CMakeLists.txt Fri Nov 2 06:14:11 2018
> @@ -16,15 +16,11 @@ add_clang_library(clangAnalysis
> CodeInjector.cpp
> Dominators.cpp
> ExprMutationAnalyzer.cpp
> - FormatString.cpp
> LiveVariables.cpp
> - OSLog.cpp
> ObjCNoReturn.cpp
> PostOrderCFGView.cpp
> - PrintfFormatString.cpp
> ProgramPoint.cpp
> ReachableCode.cpp
> - ScanfFormatString.cpp
> ThreadSafety.cpp
> ThreadSafetyCommon.cpp
> ThreadSafetyLogical.cpp
>
> Removed: cfe/trunk/lib/Analysis/FormatString.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/FormatString.cpp?rev=345970&view=auto
>
> ==============================================================================
> --- cfe/trunk/lib/Analysis/FormatString.cpp (original)
> +++ cfe/trunk/lib/Analysis/FormatString.cpp (removed)
> @@ -1,955 +0,0 @@
> -// FormatString.cpp - Common stuff for handling printf/scanf formats -*-
> C++ -*-
> -//
> -// The LLVM Compiler Infrastructure
> -//
> -// This file is distributed under the University of Illinois Open Source
> -// License. See LICENSE.TXT for details.
> -//
>
> -//===----------------------------------------------------------------------===//
> -//
> -// Shared details for processing format strings of printf and scanf
> -// (and friends).
> -//
>
> -//===----------------------------------------------------------------------===//
> -
> -#include "FormatStringParsing.h"
> -#include "clang/Basic/LangOptions.h"
> -#include "clang/Basic/TargetInfo.h"
> -#include "llvm/Support/ConvertUTF.h"
> -
> -using clang::analyze_format_string::ArgType;
> -using clang::analyze_format_string::FormatStringHandler;
> -using clang::analyze_format_string::FormatSpecifier;
> -using clang::analyze_format_string::LengthModifier;
> -using clang::analyze_format_string::OptionalAmount;
> -using clang::analyze_format_string::PositionContext;
> -using clang::analyze_format_string::ConversionSpecifier;
> -using namespace clang;
> -
> -// Key function to FormatStringHandler.
> -FormatStringHandler::~FormatStringHandler() {}
> -
>
> -//===----------------------------------------------------------------------===//
> -// Functions for parsing format strings components in both printf and
> -// scanf format strings.
>
> -//===----------------------------------------------------------------------===//
> -
> -OptionalAmount
> -clang::analyze_format_string::ParseAmount(const char *&Beg, const char
> *E) {
> - const char *I = Beg;
> - UpdateOnReturn <const char*> UpdateBeg(Beg, I);
> -
> - unsigned accumulator = 0;
> - bool hasDigits = false;
> -
> - for ( ; I != E; ++I) {
> - char c = *I;
> - if (c >= '0' && c <= '9') {
> - hasDigits = true;
> - accumulator = (accumulator * 10) + (c - '0');
> - continue;
> - }
> -
> - if (hasDigits)
> - return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, I
> - Beg,
> - false);
> -
> - break;
> - }
> -
> - return OptionalAmount();
> -}
> -
> -OptionalAmount
> -clang::analyze_format_string::ParseNonPositionAmount(const char *&Beg,
> - const char *E,
> - unsigned &argIndex) {
> - if (*Beg == '*') {
> - ++Beg;
> - return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false);
> - }
> -
> - return ParseAmount(Beg, E);
> -}
> -
> -OptionalAmount
> -clang::analyze_format_string::ParsePositionAmount(FormatStringHandler &H,
> - const char *Start,
> - const char *&Beg,
> - const char *E,
> - PositionContext p) {
> - if (*Beg == '*') {
> - const char *I = Beg + 1;
> - const OptionalAmount &Amt = ParseAmount(I, E);
> -
> - if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {
> - H.HandleInvalidPosition(Beg, I - Beg, p);
> - return OptionalAmount(false);
> - }
> -
> - if (I == E) {
> - // No more characters left?
> - H.HandleIncompleteSpecifier(Start, E - Start);
> - return OptionalAmount(false);
> - }
> -
> - assert(Amt.getHowSpecified() == OptionalAmount::Constant);
> -
> - if (*I == '$') {
> - // Handle positional arguments
> -
> - // Special case: '*0$', since this is an easy mistake.
> - if (Amt.getConstantAmount() == 0) {
> - H.HandleZeroPosition(Beg, I - Beg + 1);
> - return OptionalAmount(false);
> - }
> -
> - const char *Tmp = Beg;
> - Beg = ++I;
> -
> - return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount()
> - 1,
> - Tmp, 0, true);
> - }
> -
> - H.HandleInvalidPosition(Beg, I - Beg, p);
> - return OptionalAmount(false);
> - }
> -
> - return ParseAmount(Beg, E);
> -}
> -
> -
> -bool
> -clang::analyze_format_string::ParseFieldWidth(FormatStringHandler &H,
> - FormatSpecifier &CS,
> - const char *Start,
> - const char *&Beg, const
> char *E,
> - unsigned *argIndex) {
> - // FIXME: Support negative field widths.
> - if (argIndex) {
> - CS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex));
> - }
> - else {
> - const OptionalAmount Amt =
> - ParsePositionAmount(H, Start, Beg, E,
> - analyze_format_string::FieldWidthPos);
> -
> - if (Amt.isInvalid())
> - return true;
> - CS.setFieldWidth(Amt);
> - }
> - return false;
> -}
> -
> -bool
> -clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H,
> - FormatSpecifier &FS,
> - const char *Start,
> - const char *&Beg,
> - const char *E) {
> - const char *I = Beg;
> -
> - const OptionalAmount &Amt = ParseAmount(I, E);
> -
> - if (I == E) {
> - // No more characters left?
> - H.HandleIncompleteSpecifier(Start, E - Start);
> - return true;
> - }
> -
> - if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$')
> {
> - // Warn that positional arguments are non-standard.
> - H.HandlePosition(Start, I - Start);
> -
> - // Special case: '%0$', since this is an easy mistake.
> - if (Amt.getConstantAmount() == 0) {
> - H.HandleZeroPosition(Start, I - Start);
> - return true;
> - }
> -
> - FS.setArgIndex(Amt.getConstantAmount() - 1);
> - FS.setUsesPositionalArg();
> - // Update the caller's pointer if we decided to consume
> - // these characters.
> - Beg = I;
> - return false;
> - }
> -
> - return false;
> -}
> -
> -bool
> -clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
> - const char *&I,
> - const char *E,
> - const LangOptions &LO,
> - bool IsScanf) {
> - LengthModifier::Kind lmKind = LengthModifier::None;
> - const char *lmPosition = I;
> - switch (*I) {
> - default:
> - return false;
> - case 'h':
> - ++I;
> - if (I != E && *I == 'h') {
> - ++I;
> - lmKind = LengthModifier::AsChar;
> - } else {
> - lmKind = LengthModifier::AsShort;
> - }
> - break;
> - case 'l':
> - ++I;
> - if (I != E && *I == 'l') {
> - ++I;
> - lmKind = LengthModifier::AsLongLong;
> - } else {
> - lmKind = LengthModifier::AsLong;
> - }
> - break;
> - case 'j': lmKind = LengthModifier::AsIntMax; ++I; break;
> - case 'z': lmKind = LengthModifier::AsSizeT; ++I; break;
> - case 't': lmKind = LengthModifier::AsPtrDiff; ++I; break;
> - case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;
> - case 'q': lmKind = LengthModifier::AsQuad; ++I; break;
> - case 'a':
> - if (IsScanf && !LO.C99 && !LO.CPlusPlus11) {
> - // For scanf in C90, look at the next character to see if this
> should
> - // be parsed as the GNU extension 'a' length modifier. If not,
> this
> - // will be parsed as a conversion specifier.
> - ++I;
> - if (I != E && (*I == 's' || *I == 'S' || *I == '[')) {
> - lmKind = LengthModifier::AsAllocate;
> - break;
> - }
> - --I;
> - }
> - return false;
> - case 'm':
> - if (IsScanf) {
> - lmKind = LengthModifier::AsMAllocate;
> - ++I;
> - break;
> - }
> - return false;
> - // printf: AsInt64, AsInt32, AsInt3264
> - // scanf: AsInt64
> - case 'I':
> - if (I + 1 != E && I + 2 != E) {
> - if (I[1] == '6' && I[2] == '4') {
> - I += 3;
> - lmKind = LengthModifier::AsInt64;
> - break;
> - }
> - if (IsScanf)
> - return false;
> -
> - if (I[1] == '3' && I[2] == '2') {
> - I += 3;
> - lmKind = LengthModifier::AsInt32;
> - break;
> - }
> - }
> - ++I;
> - lmKind = LengthModifier::AsInt3264;
> - break;
> - case 'w':
> - lmKind = LengthModifier::AsWide; ++I; break;
> - }
> - LengthModifier lm(lmPosition, lmKind);
> - FS.setLengthModifier(lm);
> - return true;
> -}
> -
> -bool clang::analyze_format_string::ParseUTF8InvalidSpecifier(
> - const char *SpecifierBegin, const char *FmtStrEnd, unsigned &Len) {
> - if (SpecifierBegin + 1 >= FmtStrEnd)
> - return false;
> -
> - const llvm::UTF8 *SB =
> - reinterpret_cast<const llvm::UTF8 *>(SpecifierBegin + 1);
> - const llvm::UTF8 *SE = reinterpret_cast<const llvm::UTF8 *>(FmtStrEnd);
> - const char FirstByte = *SB;
> -
> - // If the invalid specifier is a multibyte UTF-8 string, return the
> - // total length accordingly so that the conversion specifier can be
> - // properly updated to reflect a complete UTF-8 specifier.
> - unsigned NumBytes = llvm::getNumBytesForUTF8(FirstByte);
> - if (NumBytes == 1)
> - return false;
> - if (SB + NumBytes > SE)
> - return false;
> -
> - Len = NumBytes + 1;
> - return true;
> -}
> -
>
> -//===----------------------------------------------------------------------===//
> -// Methods on ArgType.
>
> -//===----------------------------------------------------------------------===//
> -
> -clang::analyze_format_string::ArgType::MatchKind
> -ArgType::matchesType(ASTContext &C, QualType argTy) const {
> - if (Ptr) {
> - // It has to be a pointer.
> - const PointerType *PT = argTy->getAs<PointerType>();
> - if (!PT)
> - return NoMatch;
> -
> - // We cannot write through a const qualified pointer.
> - if (PT->getPointeeType().isConstQualified())
> - return NoMatch;
> -
> - argTy = PT->getPointeeType();
> - }
> -
> - switch (K) {
> - case InvalidTy:
> - llvm_unreachable("ArgType must be valid");
> -
> - case UnknownTy:
> - return Match;
> -
> - case AnyCharTy: {
> - if (const EnumType *ETy = argTy->getAs<EnumType>()) {
> - // If the enum is incomplete we know nothing about the underlying
> type.
> - // Assume that it's 'int'.
> - if (!ETy->getDecl()->isComplete())
> - return NoMatch;
> - argTy = ETy->getDecl()->getIntegerType();
> - }
> -
> - if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
> - switch (BT->getKind()) {
> - default:
> - break;
> - case BuiltinType::Char_S:
> - case BuiltinType::SChar:
> - case BuiltinType::UChar:
> - case BuiltinType::Char_U:
> - return Match;
> - }
> - return NoMatch;
> - }
> -
> - case SpecificTy: {
> - if (const EnumType *ETy = argTy->getAs<EnumType>()) {
> - // If the enum is incomplete we know nothing about the underlying
> type.
> - // Assume that it's 'int'.
> - if (!ETy->getDecl()->isComplete())
> - argTy = C.IntTy;
> - else
> - argTy = ETy->getDecl()->getIntegerType();
> - }
> - argTy = C.getCanonicalType(argTy).getUnqualifiedType();
> -
> - if (T == argTy)
> - return Match;
> - // Check for "compatible types".
> - if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
> - switch (BT->getKind()) {
> - default:
> - break;
> - case BuiltinType::Char_S:
> - case BuiltinType::SChar:
> - case BuiltinType::Char_U:
> - case BuiltinType::UChar:
> - return T == C.UnsignedCharTy || T == C.SignedCharTy ? Match
> - : NoMatch;
> - case BuiltinType::Short:
> - return T == C.UnsignedShortTy ? Match : NoMatch;
> - case BuiltinType::UShort:
> - return T == C.ShortTy ? Match : NoMatch;
> - case BuiltinType::Int:
> - return T == C.UnsignedIntTy ? Match : NoMatch;
> - case BuiltinType::UInt:
> - return T == C.IntTy ? Match : NoMatch;
> - case BuiltinType::Long:
> - return T == C.UnsignedLongTy ? Match : NoMatch;
> - case BuiltinType::ULong:
> - return T == C.LongTy ? Match : NoMatch;
> - case BuiltinType::LongLong:
> - return T == C.UnsignedLongLongTy ? Match : NoMatch;
> - case BuiltinType::ULongLong:
> - return T == C.LongLongTy ? Match : NoMatch;
> - }
> - return NoMatch;
> - }
> -
> - case CStrTy: {
> - const PointerType *PT = argTy->getAs<PointerType>();
> - if (!PT)
> - return NoMatch;
> - QualType pointeeTy = PT->getPointeeType();
> - if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>())
> - switch (BT->getKind()) {
> - case BuiltinType::Void:
> - case BuiltinType::Char_U:
> - case BuiltinType::UChar:
> - case BuiltinType::Char_S:
> - case BuiltinType::SChar:
> - return Match;
> - default:
> - break;
> - }
> -
> - return NoMatch;
> - }
> -
> - case WCStrTy: {
> - const PointerType *PT = argTy->getAs<PointerType>();
> - if (!PT)
> - return NoMatch;
> - QualType pointeeTy =
> - C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();
> - return pointeeTy == C.getWideCharType() ? Match : NoMatch;
> - }
> -
> - case WIntTy: {
> - QualType WInt =
> C.getCanonicalType(C.getWIntType()).getUnqualifiedType();
> -
> - if (C.getCanonicalType(argTy).getUnqualifiedType() == WInt)
> - return Match;
> -
> - QualType PromoArg = argTy->isPromotableIntegerType()
> - ? C.getPromotedIntegerType(argTy)
> - : argTy;
> - PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType();
> -
> - // If the promoted argument is the corresponding signed type of the
> - // wint_t type, then it should match.
> - if (PromoArg->hasSignedIntegerRepresentation() &&
> - C.getCorrespondingUnsignedType(PromoArg) == WInt)
> - return Match;
> -
> - return WInt == PromoArg ? Match : NoMatch;
> - }
> -
> - case CPointerTy:
> - if (argTy->isVoidPointerType()) {
> - return Match;
> - } if (argTy->isPointerType() || argTy->isObjCObjectPointerType() ||
> - argTy->isBlockPointerType() || argTy->isNullPtrType()) {
> - return NoMatchPedantic;
> - } else {
> - return NoMatch;
> - }
> -
> - case ObjCPointerTy: {
> - if (argTy->getAs<ObjCObjectPointerType>() ||
> - argTy->getAs<BlockPointerType>())
> - return Match;
> -
> - // Handle implicit toll-free bridging.
> - if (const PointerType *PT = argTy->getAs<PointerType>()) {
> - // Things such as CFTypeRef are really just opaque pointers
> - // to C structs representing CF types that can often be bridged
> - // to Objective-C objects. Since the compiler doesn't know which
> - // structs can be toll-free bridged, we just accept them all.
> - QualType pointee = PT->getPointeeType();
> - if (pointee->getAsStructureType() || pointee->isVoidType())
> - return Match;
> - }
> - return NoMatch;
> - }
> - }
> -
> - llvm_unreachable("Invalid ArgType Kind!");
> -}
> -
> -QualType ArgType::getRepresentativeType(ASTContext &C) const {
> - QualType Res;
> - switch (K) {
> - case InvalidTy:
> - llvm_unreachable("No representative type for Invalid ArgType");
> - case UnknownTy:
> - llvm_unreachable("No representative type for Unknown ArgType");
> - case AnyCharTy:
> - Res = C.CharTy;
> - break;
> - case SpecificTy:
> - Res = T;
> - break;
> - case CStrTy:
> - Res = C.getPointerType(C.CharTy);
> - break;
> - case WCStrTy:
> - Res = C.getPointerType(C.getWideCharType());
> - break;
> - case ObjCPointerTy:
> - Res = C.ObjCBuiltinIdTy;
> - break;
> - case CPointerTy:
> - Res = C.VoidPtrTy;
> - break;
> - case WIntTy: {
> - Res = C.getWIntType();
> - break;
> - }
> - }
> -
> - if (Ptr)
> - Res = C.getPointerType(Res);
> - return Res;
> -}
> -
> -std::string ArgType::getRepresentativeTypeName(ASTContext &C) const {
> - std::string S = getRepresentativeType(C).getAsString();
> -
> - std::string Alias;
> - if (Name) {
> - // Use a specific name for this type, e.g. "size_t".
> - Alias = Name;
> - if (Ptr) {
> - // If ArgType is actually a pointer to T, append an asterisk.
> - Alias += (Alias[Alias.size()-1] == '*') ? "*" : " *";
> - }
> - // If Alias is the same as the underlying type, e.g. wchar_t, then
> drop it.
> - if (S == Alias)
> - Alias.clear();
> - }
> -
> - if (!Alias.empty())
> - return std::string("'") + Alias + "' (aka '" + S + "')";
> - return std::string("'") + S + "'";
> -}
> -
> -
>
> -//===----------------------------------------------------------------------===//
> -// Methods on OptionalAmount.
>
> -//===----------------------------------------------------------------------===//
> -
> -ArgType
> -analyze_format_string::OptionalAmount::getArgType(ASTContext &Ctx) const {
> - return Ctx.IntTy;
> -}
> -
>
> -//===----------------------------------------------------------------------===//
> -// Methods on LengthModifier.
>
> -//===----------------------------------------------------------------------===//
> -
> -const char *
> -analyze_format_string::LengthModifier::toString() const {
> - switch (kind) {
> - case AsChar:
> - return "hh";
> - case AsShort:
> - return "h";
> - case AsLong: // or AsWideChar
> - return "l";
> - case AsLongLong:
> - return "ll";
> - case AsQuad:
> - return "q";
> - case AsIntMax:
> - return "j";
> - case AsSizeT:
> - return "z";
> - case AsPtrDiff:
> - return "t";
> - case AsInt32:
> - return "I32";
> - case AsInt3264:
> - return "I";
> - case AsInt64:
> - return "I64";
> - case AsLongDouble:
> - return "L";
> - case AsAllocate:
> - return "a";
> - case AsMAllocate:
> - return "m";
> - case AsWide:
> - return "w";
> - case None:
> - return "";
> - }
> - return nullptr;
> -}
> -
>
> -//===----------------------------------------------------------------------===//
> -// Methods on ConversionSpecifier.
>
> -//===----------------------------------------------------------------------===//
> -
> -const char *ConversionSpecifier::toString() const {
> - switch (kind) {
> - case dArg: return "d";
> - case DArg: return "D";
> - case iArg: return "i";
> - case oArg: return "o";
> - case OArg: return "O";
> - case uArg: return "u";
> - case UArg: return "U";
> - case xArg: return "x";
> - case XArg: return "X";
> - case fArg: return "f";
> - case FArg: return "F";
> - case eArg: return "e";
> - case EArg: return "E";
> - case gArg: return "g";
> - case GArg: return "G";
> - case aArg: return "a";
> - case AArg: return "A";
> - case cArg: return "c";
> - case sArg: return "s";
> - case pArg: return "p";
> - case PArg:
> - return "P";
> - case nArg: return "n";
> - case PercentArg: return "%";
> - case ScanListArg: return "[";
> - case InvalidSpecifier: return nullptr;
> -
> - // POSIX unicode extensions.
> - case CArg: return "C";
> - case SArg: return "S";
> -
> - // Objective-C specific specifiers.
> - case ObjCObjArg: return "@";
> -
> - // FreeBSD kernel specific specifiers.
> - case FreeBSDbArg: return "b";
> - case FreeBSDDArg: return "D";
> - case FreeBSDrArg: return "r";
> - case FreeBSDyArg: return "y";
> -
> - // GlibC specific specifiers.
> - case PrintErrno: return "m";
> -
> - // MS specific specifiers.
> - case ZArg: return "Z";
> - }
> - return nullptr;
> -}
> -
> -Optional<ConversionSpecifier>
> -ConversionSpecifier::getStandardSpecifier() const {
> - ConversionSpecifier::Kind NewKind;
> -
> - switch (getKind()) {
> - default:
> - return None;
> - case DArg:
> - NewKind = dArg;
> - break;
> - case UArg:
> - NewKind = uArg;
> - break;
> - case OArg:
> - NewKind = oArg;
> - break;
> - }
> -
> - ConversionSpecifier FixedCS(*this);
> - FixedCS.setKind(NewKind);
> - return FixedCS;
> -}
> -
>
> -//===----------------------------------------------------------------------===//
> -// Methods on OptionalAmount.
>
> -//===----------------------------------------------------------------------===//
> -
> -void OptionalAmount::toString(raw_ostream &os) const {
> - switch (hs) {
> - case Invalid:
> - case NotSpecified:
> - return;
> - case Arg:
> - if (UsesDotPrefix)
> - os << ".";
> - if (usesPositionalArg())
> - os << "*" << getPositionalArgIndex() << "$";
> - else
> - os << "*";
> - break;
> - case Constant:
> - if (UsesDotPrefix)
> - os << ".";
> - os << amt;
> - break;
> - }
> -}
> -
> -bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target)
> const {
> - switch (LM.getKind()) {
> - case LengthModifier::None:
> - return true;
> -
> - // Handle most integer flags
> - case LengthModifier::AsShort:
> - if (Target.getTriple().isOSMSVCRT()) {
> - switch (CS.getKind()) {
> - case ConversionSpecifier::cArg:
> - case ConversionSpecifier::CArg:
> - case ConversionSpecifier::sArg:
> - case ConversionSpecifier::SArg:
> - case ConversionSpecifier::ZArg:
> - return true;
> - default:
> - break;
> - }
> - }
> - LLVM_FALLTHROUGH;
> - case LengthModifier::AsChar:
> - case LengthModifier::AsLongLong:
> - case LengthModifier::AsQuad:
> - case LengthModifier::AsIntMax:
> - case LengthModifier::AsSizeT:
> - case LengthModifier::AsPtrDiff:
> - switch (CS.getKind()) {
> - case ConversionSpecifier::dArg:
> - case ConversionSpecifier::DArg:
> - case ConversionSpecifier::iArg:
> - case ConversionSpecifier::oArg:
> - case ConversionSpecifier::OArg:
> - case ConversionSpecifier::uArg:
> - case ConversionSpecifier::UArg:
> - case ConversionSpecifier::xArg:
> - case ConversionSpecifier::XArg:
> - case ConversionSpecifier::nArg:
> - return true;
> - case ConversionSpecifier::FreeBSDrArg:
> - case ConversionSpecifier::FreeBSDyArg:
> - return Target.getTriple().isOSFreeBSD() ||
> Target.getTriple().isPS4();
> - default:
> - return false;
> - }
> -
> - // Handle 'l' flag
> - case LengthModifier::AsLong: // or AsWideChar
> - switch (CS.getKind()) {
> - case ConversionSpecifier::dArg:
> - case ConversionSpecifier::DArg:
> - case ConversionSpecifier::iArg:
> - case ConversionSpecifier::oArg:
> - case ConversionSpecifier::OArg:
> - case ConversionSpecifier::uArg:
> - case ConversionSpecifier::UArg:
> - case ConversionSpecifier::xArg:
> - case ConversionSpecifier::XArg:
> - case ConversionSpecifier::aArg:
> - case ConversionSpecifier::AArg:
> - case ConversionSpecifier::fArg:
> - case ConversionSpecifier::FArg:
> - case ConversionSpecifier::eArg:
> - case ConversionSpecifier::EArg:
> - case ConversionSpecifier::gArg:
> - case ConversionSpecifier::GArg:
> - case ConversionSpecifier::nArg:
> - case ConversionSpecifier::cArg:
> - case ConversionSpecifier::sArg:
> - case ConversionSpecifier::ScanListArg:
> - case ConversionSpecifier::ZArg:
> - return true;
> - case ConversionSpecifier::FreeBSDrArg:
> - case ConversionSpecifier::FreeBSDyArg:
> - return Target.getTriple().isOSFreeBSD() ||
> Target.getTriple().isPS4();
> - default:
> - return false;
> - }
> -
> - case LengthModifier::AsLongDouble:
> - switch (CS.getKind()) {
> - case ConversionSpecifier::aArg:
> - case ConversionSpecifier::AArg:
> - case ConversionSpecifier::fArg:
> - case ConversionSpecifier::FArg:
> - case ConversionSpecifier::eArg:
> - case ConversionSpecifier::EArg:
> - case ConversionSpecifier::gArg:
> - case ConversionSpecifier::GArg:
> - return true;
> - // GNU libc extension.
> - case ConversionSpecifier::dArg:
> - case ConversionSpecifier::iArg:
> - case ConversionSpecifier::oArg:
> - case ConversionSpecifier::uArg:
> - case ConversionSpecifier::xArg:
> - case ConversionSpecifier::XArg:
> - return !Target.getTriple().isOSDarwin() &&
> - !Target.getTriple().isOSWindows();
> - default:
> - return false;
> - }
> -
> - case LengthModifier::AsAllocate:
> - switch (CS.getKind()) {
> - case ConversionSpecifier::sArg:
> - case ConversionSpecifier::SArg:
> - case ConversionSpecifier::ScanListArg:
> - return true;
> - default:
> - return false;
> - }
> -
> - case LengthModifier::AsMAllocate:
> - switch (CS.getKind()) {
> - case ConversionSpecifier::cArg:
> - case ConversionSpecifier::CArg:
> - case ConversionSpecifier::sArg:
> - case ConversionSpecifier::SArg:
> - case ConversionSpecifier::ScanListArg:
> - return true;
> - default:
> - return false;
> - }
> - case LengthModifier::AsInt32:
> - case LengthModifier::AsInt3264:
> - case LengthModifier::AsInt64:
> - switch (CS.getKind()) {
> - case ConversionSpecifier::dArg:
> - case ConversionSpecifier::iArg:
> - case ConversionSpecifier::oArg:
> - case ConversionSpecifier::uArg:
> - case ConversionSpecifier::xArg:
> - case ConversionSpecifier::XArg:
> - return Target.getTriple().isOSMSVCRT();
> - default:
> - return false;
> - }
> - case LengthModifier::AsWide:
> - switch (CS.getKind()) {
> - case ConversionSpecifier::cArg:
> - case ConversionSpecifier::CArg:
> - case ConversionSpecifier::sArg:
> - case ConversionSpecifier::SArg:
> - case ConversionSpecifier::ZArg:
> - return Target.getTriple().isOSMSVCRT();
> - default:
> - return false;
> - }
> - }
> - llvm_unreachable("Invalid LengthModifier Kind!");
> -}
> -
> -bool FormatSpecifier::hasStandardLengthModifier() const {
> - switch (LM.getKind()) {
> - case LengthModifier::None:
> - case LengthModifier::AsChar:
> - case LengthModifier::AsShort:
> - case LengthModifier::AsLong:
> - case LengthModifier::AsLongLong:
> - case LengthModifier::AsIntMax:
> - case LengthModifier::AsSizeT:
> - case LengthModifier::AsPtrDiff:
> - case LengthModifier::AsLongDouble:
> - return true;
> - case LengthModifier::AsAllocate:
> - case LengthModifier::AsMAllocate:
> - case LengthModifier::AsQuad:
> - case LengthModifier::AsInt32:
> - case LengthModifier::AsInt3264:
> - case LengthModifier::AsInt64:
> - case LengthModifier::AsWide:
> - return false;
> - }
> - llvm_unreachable("Invalid LengthModifier Kind!");
> -}
> -
> -bool FormatSpecifier::hasStandardConversionSpecifier(
> - const LangOptions &LangOpt) const {
> - switch (CS.getKind()) {
> - case ConversionSpecifier::cArg:
> - case ConversionSpecifier::dArg:
> - case ConversionSpecifier::iArg:
> - case ConversionSpecifier::oArg:
> - case ConversionSpecifier::uArg:
> - case ConversionSpecifier::xArg:
> - case ConversionSpecifier::XArg:
> - case ConversionSpecifier::fArg:
> - case ConversionSpecifier::FArg:
> - case ConversionSpecifier::eArg:
> - case ConversionSpecifier::EArg:
> - case ConversionSpecifier::gArg:
> - case ConversionSpecifier::GArg:
> - case ConversionSpecifier::aArg:
> - case ConversionSpecifier::AArg:
> - case ConversionSpecifier::sArg:
> - case ConversionSpecifier::pArg:
> - case ConversionSpecifier::nArg:
> - case ConversionSpecifier::ObjCObjArg:
> - case ConversionSpecifier::ScanListArg:
> - case ConversionSpecifier::PercentArg:
> - case ConversionSpecifier::PArg:
> - return true;
> - case ConversionSpecifier::CArg:
> - case ConversionSpecifier::SArg:
> - return LangOpt.ObjC;
> - case ConversionSpecifier::InvalidSpecifier:
> - case ConversionSpecifier::FreeBSDbArg:
> - case ConversionSpecifier::FreeBSDDArg:
> - case ConversionSpecifier::FreeBSDrArg:
> - case ConversionSpecifier::FreeBSDyArg:
> - case ConversionSpecifier::PrintErrno:
> - case ConversionSpecifier::DArg:
> - case ConversionSpecifier::OArg:
> - case ConversionSpecifier::UArg:
> - case ConversionSpecifier::ZArg:
> - return false;
> - }
> - llvm_unreachable("Invalid ConversionSpecifier Kind!");
> -}
> -
> -bool FormatSpecifier::hasStandardLengthConversionCombination() const {
> - if (LM.getKind() == LengthModifier::AsLongDouble) {
> - switch(CS.getKind()) {
> - case ConversionSpecifier::dArg:
> - case ConversionSpecifier::iArg:
> - case ConversionSpecifier::oArg:
> - case ConversionSpecifier::uArg:
> - case ConversionSpecifier::xArg:
> - case ConversionSpecifier::XArg:
> - return false;
> - default:
> - return true;
> - }
> - }
> - return true;
> -}
> -
> -Optional<LengthModifier> FormatSpecifier::getCorrectedLengthModifier()
> const {
> - if (CS.isAnyIntArg() || CS.getKind() == ConversionSpecifier::nArg) {
> - if (LM.getKind() == LengthModifier::AsLongDouble ||
> - LM.getKind() == LengthModifier::AsQuad) {
> - LengthModifier FixedLM(LM);
> - FixedLM.setKind(LengthModifier::AsLongLong);
> - return FixedLM;
> - }
> - }
> -
> - return None;
> -}
> -
> -bool FormatSpecifier::namedTypeToLengthModifier(QualType QT,
> - LengthModifier &LM) {
> - assert(isa<TypedefType>(QT) && "Expected a TypedefType");
> - const TypedefNameDecl *Typedef = cast<TypedefType>(QT)->getDecl();
> -
> - for (;;) {
> - const IdentifierInfo *Identifier = Typedef->getIdentifier();
> - if (Identifier->getName() == "size_t") {
> - LM.setKind(LengthModifier::AsSizeT);
> - return true;
> - } else if (Identifier->getName() == "ssize_t") {
> - // Not C99, but common in Unix.
> - LM.setKind(LengthModifier::AsSizeT);
> - return true;
> - } else if (Identifier->getName() == "intmax_t") {
> - LM.setKind(LengthModifier::AsIntMax);
> - return true;
> - } else if (Identifier->getName() == "uintmax_t") {
> - LM.setKind(LengthModifier::AsIntMax);
> - return true;
> - } else if (Identifier->getName() == "ptrdiff_t") {
> - LM.setKind(LengthModifier::AsPtrDiff);
> - return true;
> - }
> -
> - QualType T = Typedef->getUnderlyingType();
> - if (!isa<TypedefType>(T))
> - break;
> -
> - Typedef = cast<TypedefType>(T)->getDecl();
> - }
> - return false;
> -}
>
> Removed: cfe/trunk/lib/Analysis/FormatStringParsing.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/FormatStringParsing.h?rev=345970&view=auto
>
> ==============================================================================
> --- cfe/trunk/lib/Analysis/FormatStringParsing.h (original)
> +++ cfe/trunk/lib/Analysis/FormatStringParsing.h (removed)
> @@ -1,79 +0,0 @@
> -#ifndef LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H
> -#define LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H
> -
> -#include "clang/AST/ASTContext.h"
> -#include "clang/AST/Type.h"
> -#include "clang/Analysis/Analyses/FormatString.h"
> -
> -namespace clang {
> -
> -class LangOptions;
> -
> -template <typename T>
> -class UpdateOnReturn {
> - T &ValueToUpdate;
> - const T &ValueToCopy;
> -public:
> - UpdateOnReturn(T &valueToUpdate, const T &valueToCopy)
> - : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {}
> -
> - ~UpdateOnReturn() {
> - ValueToUpdate = ValueToCopy;
> - }
> -};
> -
> -namespace analyze_format_string {
> -
> -OptionalAmount ParseAmount(const char *&Beg, const char *E);
> -OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E,
> - unsigned &argIndex);
> -
> -OptionalAmount ParsePositionAmount(FormatStringHandler &H,
> - const char *Start, const char *&Beg,
> - const char *E, PositionContext p);
> -
> -bool ParseFieldWidth(FormatStringHandler &H,
> - FormatSpecifier &CS,
> - const char *Start, const char *&Beg, const char *E,
> - unsigned *argIndex);
> -
> -bool ParseArgPosition(FormatStringHandler &H,
> - FormatSpecifier &CS, const char *Start,
> - const char *&Beg, const char *E);
> -
> -/// Returns true if a LengthModifier was parsed and installed in the
> -/// FormatSpecifier& argument, and false otherwise.
> -bool ParseLengthModifier(FormatSpecifier &FS, const char *&Beg, const
> char *E,
> - const LangOptions &LO, bool IsScanf = false);
> -
> -/// Returns true if the invalid specifier in \p SpecifierBegin is a UTF-8
> -/// string; check that it won't go further than \p FmtStrEnd and write
> -/// up the total size in \p Len.
> -bool ParseUTF8InvalidSpecifier(const char *SpecifierBegin,
> - const char *FmtStrEnd, unsigned &Len);
> -
> -template <typename T> class SpecifierResult {
> - T FS;
> - const char *Start;
> - bool Stop;
> -public:
> - SpecifierResult(bool stop = false)
> - : Start(nullptr), Stop(stop) {}
> - SpecifierResult(const char *start,
> - const T &fs)
> - : FS(fs), Start(start), Stop(false) {}
> -
> - const char *getStart() const { return Start; }
> - bool shouldStop() const { return Stop; }
> - bool hasValue() const { return Start != nullptr; }
> - const T &getValue() const {
> - assert(hasValue());
> - return FS;
> - }
> - const T &getValue() { return FS; }
> -};
> -
> -} // end analyze_format_string namespace
> -} // end clang namespace
> -
> -#endif
>
> Removed: cfe/trunk/lib/Analysis/OSLog.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/OSLog.cpp?rev=345970&view=auto
>
> ==============================================================================
> --- cfe/trunk/lib/Analysis/OSLog.cpp (original)
> +++ cfe/trunk/lib/Analysis/OSLog.cpp (removed)
> @@ -1,203 +0,0 @@
> -// TODO: header template
> -
> -#include "clang/Analysis/Analyses/OSLog.h"
> -#include "clang/AST/Attr.h"
> -#include "clang/AST/Decl.h"
> -#include "clang/AST/DeclCXX.h"
> -#include "clang/AST/ExprObjC.h"
> -#include "clang/Analysis/Analyses/FormatString.h"
> -#include "clang/Basic/Builtins.h"
> -#include "llvm/ADT/SmallBitVector.h"
> -
> -using namespace clang;
> -
> -using clang::analyze_os_log::OSLogBufferItem;
> -using clang::analyze_os_log::OSLogBufferLayout;
> -
> -namespace {
> -class OSLogFormatStringHandler
> - : public analyze_format_string::FormatStringHandler {
> -private:
> - struct ArgData {
> - const Expr *E = nullptr;
> - Optional<OSLogBufferItem::Kind> Kind;
> - Optional<unsigned> Size;
> - Optional<const Expr *> Count;
> - Optional<const Expr *> Precision;
> - Optional<const Expr *> FieldWidth;
> - unsigned char Flags = 0;
> - };
> - SmallVector<ArgData, 4> ArgsData;
> - ArrayRef<const Expr *> Args;
> -
> - OSLogBufferItem::Kind
> - getKind(analyze_format_string::ConversionSpecifier::Kind K) {
> - switch (K) {
> - case clang::analyze_format_string::ConversionSpecifier::sArg: // "%s"
> - return OSLogBufferItem::StringKind;
> - case clang::analyze_format_string::ConversionSpecifier::SArg: // "%S"
> - return OSLogBufferItem::WideStringKind;
> - case clang::analyze_format_string::ConversionSpecifier::PArg: { //
> "%P"
> - return OSLogBufferItem::PointerKind;
> - case clang::analyze_format_string::ConversionSpecifier::ObjCObjArg:
> // "%@"
> - return OSLogBufferItem::ObjCObjKind;
> - case clang::analyze_format_string::ConversionSpecifier::PrintErrno:
> // "%m"
> - return OSLogBufferItem::ErrnoKind;
> - default:
> - return OSLogBufferItem::ScalarKind;
> - }
> - }
> - }
> -
> -public:
> - OSLogFormatStringHandler(ArrayRef<const Expr *> Args) : Args(Args) {
> - ArgsData.reserve(Args.size());
> - }
> -
> - virtual bool HandlePrintfSpecifier(const
> analyze_printf::PrintfSpecifier &FS,
> - const char *StartSpecifier,
> - unsigned SpecifierLen) {
> - if (!FS.consumesDataArgument() &&
> - FS.getConversionSpecifier().getKind() !=
> - clang::analyze_format_string::ConversionSpecifier::PrintErrno)
> - return true;
> -
> - ArgsData.emplace_back();
> - unsigned ArgIndex = FS.getArgIndex();
> - if (ArgIndex < Args.size())
> - ArgsData.back().E = Args[ArgIndex];
> -
> - // First get the Kind
> - ArgsData.back().Kind = getKind(FS.getConversionSpecifier().getKind());
> - if (ArgsData.back().Kind != OSLogBufferItem::ErrnoKind &&
> - !ArgsData.back().E) {
> - // missing argument
> - ArgsData.pop_back();
> - return false;
> - }
> -
> - switch (FS.getConversionSpecifier().getKind()) {
> - case clang::analyze_format_string::ConversionSpecifier::sArg: //
> "%s"
> - case clang::analyze_format_string::ConversionSpecifier::SArg: { //
> "%S"
> - auto &precision = FS.getPrecision();
> - switch (precision.getHowSpecified()) {
> - case clang::analyze_format_string::OptionalAmount::NotSpecified: //
> "%s"
> - break;
> - case clang::analyze_format_string::OptionalAmount::Constant: //
> "%.16s"
> - ArgsData.back().Size = precision.getConstantAmount();
> - break;
> - case clang::analyze_format_string::OptionalAmount::Arg: // "%.*s"
> - ArgsData.back().Count = Args[precision.getArgIndex()];
> - break;
> - case clang::analyze_format_string::OptionalAmount::Invalid:
> - return false;
> - }
> - break;
> - }
> - case clang::analyze_format_string::ConversionSpecifier::PArg: { //
> "%P"
> - auto &precision = FS.getPrecision();
> - switch (precision.getHowSpecified()) {
> - case clang::analyze_format_string::OptionalAmount::NotSpecified: //
> "%P"
> - return false; // length must be supplied with pointer format
> specifier
> - case clang::analyze_format_string::OptionalAmount::Constant: //
> "%.16P"
> - ArgsData.back().Size = precision.getConstantAmount();
> - break;
> - case clang::analyze_format_string::OptionalAmount::Arg: // "%.*P"
> - ArgsData.back().Count = Args[precision.getArgIndex()];
> - break;
> - case clang::analyze_format_string::OptionalAmount::Invalid:
> - return false;
> - }
> - break;
> - }
> - default:
> - if (FS.getPrecision().hasDataArgument()) {
> - ArgsData.back().Precision = Args[FS.getPrecision().getArgIndex()];
> - }
> - break;
> - }
> - if (FS.getFieldWidth().hasDataArgument()) {
> - ArgsData.back().FieldWidth = Args[FS.getFieldWidth().getArgIndex()];
> - }
> -
> - if (FS.isPrivate()) {
> - ArgsData.back().Flags |= OSLogBufferItem::IsPrivate;
> - }
> - if (FS.isPublic()) {
> - ArgsData.back().Flags |= OSLogBufferItem::IsPublic;
> - }
> - return true;
> - }
> -
> - void computeLayout(ASTContext &Ctx, OSLogBufferLayout &Layout) const {
> - Layout.Items.clear();
> - for (auto &Data : ArgsData) {
> - if (Data.FieldWidth) {
> - CharUnits Size =
> Ctx.getTypeSizeInChars((*Data.FieldWidth)->getType());
> - Layout.Items.emplace_back(OSLogBufferItem::ScalarKind,
> *Data.FieldWidth,
> - Size, 0);
> - }
> - if (Data.Precision) {
> - CharUnits Size =
> Ctx.getTypeSizeInChars((*Data.Precision)->getType());
> - Layout.Items.emplace_back(OSLogBufferItem::ScalarKind,
> *Data.Precision,
> - Size, 0);
> - }
> - if (Data.Count) {
> - // "%.*P" has an extra "count" that we insert before the argument.
> - CharUnits Size = Ctx.getTypeSizeInChars((*Data.Count)->getType());
> - Layout.Items.emplace_back(OSLogBufferItem::CountKind,
> *Data.Count, Size,
> - 0);
> - }
> - if (Data.Size)
> - Layout.Items.emplace_back(Ctx,
> CharUnits::fromQuantity(*Data.Size),
> - Data.Flags);
> - if (Data.Kind) {
> - CharUnits Size;
> - if (*Data.Kind == OSLogBufferItem::ErrnoKind)
> - Size = CharUnits::Zero();
> - else
> - Size = Ctx.getTypeSizeInChars(Data.E->getType());
> - Layout.Items.emplace_back(*Data.Kind, Data.E, Size, Data.Flags);
> - } else {
> - auto Size = Ctx.getTypeSizeInChars(Data.E->getType());
> - Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, Data.E,
> Size,
> - Data.Flags);
> - }
> - }
> - }
> -};
> -} // end anonymous namespace
> -
> -bool clang::analyze_os_log::computeOSLogBufferLayout(
> - ASTContext &Ctx, const CallExpr *E, OSLogBufferLayout &Layout) {
> - ArrayRef<const Expr *> Args(E->getArgs(), E->getArgs() +
> E->getNumArgs());
> -
> - const Expr *StringArg;
> - ArrayRef<const Expr *> VarArgs;
> - switch (E->getBuiltinCallee()) {
> - case Builtin::BI__builtin_os_log_format_buffer_size:
> - assert(E->getNumArgs() >= 1 &&
> - "__builtin_os_log_format_buffer_size takes at least 1
> argument");
> - StringArg = E->getArg(0);
> - VarArgs = Args.slice(1);
> - break;
> - case Builtin::BI__builtin_os_log_format:
> - assert(E->getNumArgs() >= 2 &&
> - "__builtin_os_log_format takes at least 2 arguments");
> - StringArg = E->getArg(1);
> - VarArgs = Args.slice(2);
> - break;
> - default:
> - llvm_unreachable("non-os_log builtin passed to
> computeOSLogBufferLayout");
> - }
> -
> - const StringLiteral *Lit =
> cast<StringLiteral>(StringArg->IgnoreParenCasts());
> - assert(Lit && (Lit->isAscii() || Lit->isUTF8()));
> - StringRef Data = Lit->getString();
> - OSLogFormatStringHandler H(VarArgs);
> - ParsePrintfString(H, Data.begin(), Data.end(), Ctx.getLangOpts(),
> - Ctx.getTargetInfo(), /*isFreeBSDKPrintf*/ false);
> -
> - H.computeLayout(Ctx, Layout);
> - return true;
> -}
>
> Removed: cfe/trunk/lib/Analysis/PrintfFormatString.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/PrintfFormatString.cpp?rev=345970&view=auto
>
> ==============================================================================
> --- cfe/trunk/lib/Analysis/PrintfFormatString.cpp (original)
> +++ cfe/trunk/lib/Analysis/PrintfFormatString.cpp (removed)
> @@ -1,1029 +0,0 @@
> -//== PrintfFormatString.cpp - Analysis of printf format strings --*- C++
> -*-==//
> -//
> -// The LLVM Compiler Infrastructure
> -//
> -// This file is distributed under the University of Illinois Open Source
> -// License. See LICENSE.TXT for details.
> -//
>
> -//===----------------------------------------------------------------------===//
> -//
> -// Handling of format string in printf and friends. The structure of
> format
> -// strings for fprintf() are described in C99 7.19.6.1.
> -//
>
> -//===----------------------------------------------------------------------===//
> -
> -#include "clang/Analysis/Analyses/FormatString.h"
> -#include "clang/Analysis/Analyses/OSLog.h"
> -#include "FormatStringParsing.h"
> -#include "clang/Basic/TargetInfo.h"
> -
> -using clang::analyze_format_string::ArgType;
> -using clang::analyze_format_string::FormatStringHandler;
> -using clang::analyze_format_string::LengthModifier;
> -using clang::analyze_format_string::OptionalAmount;
> -using clang::analyze_format_string::ConversionSpecifier;
> -using clang::analyze_printf::PrintfSpecifier;
> -
> -using namespace clang;
> -
> -typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier>
> - PrintfSpecifierResult;
> -
>
> -//===----------------------------------------------------------------------===//
> -// Methods for parsing format strings.
>
> -//===----------------------------------------------------------------------===//
> -
> -using analyze_format_string::ParseNonPositionAmount;
> -
> -static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS,
> - const char *Start, const char *&Beg, const
> char *E,
> - unsigned *argIndex) {
> - if (argIndex) {
> - FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
> - } else {
> - const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
> -
> analyze_format_string::PrecisionPos);
> - if (Amt.isInvalid())
> - return true;
> - FS.setPrecision(Amt);
> - }
> - return false;
> -}
> -
> -static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS,
> - const char *FlagBeg, const char *E, bool Warn)
> {
> - StringRef Flag(FlagBeg, E - FlagBeg);
> - // Currently there is only one flag.
> - if (Flag == "tt") {
> - FS.setHasObjCTechnicalTerm(FlagBeg);
> - return false;
> - }
> - // Handle either the case of no flag or an invalid flag.
> - if (Warn) {
> - if (Flag == "")
> - H.HandleEmptyObjCModifierFlag(FlagBeg, E - FlagBeg);
> - else
> - H.HandleInvalidObjCModifierFlag(FlagBeg, E - FlagBeg);
> - }
> - return true;
> -}
> -
> -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);
> -}
> -
> -bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler
> &H,
> - const char *I,
> - const char *E,
> - const LangOptions
> &LO,
> - const TargetInfo
> &Target,
> - bool
> isFreeBSDKPrintf) {
> -
> - unsigned argIndex = 0;
> -
> - // Keep looking for a format specifier until we have exhausted the
> string.
> - while (I != E) {
> - const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E,
> argIndex,
> - LO, Target,
> true,
> -
> isFreeBSDKPrintf);
> - // Did a fail-stop error of any kind occur when parsing the specifier?
> - // If so, don't do any more processing.
> - if (FSR.shouldStop())
> - return true;
> - // Did we exhaust the string or encounter an error that
> - // we can recover from?
> - if (!FSR.hasValue())
> - continue;
> - // We have a format specifier. Pass it to the callback.
> - if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(),
> - I - FSR.getStart()))
> - return true;
> - }
> - assert(I == E && "Format string not exhausted");
> - return false;
> -}
> -
> -bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I,
> - const char *E,
> - const
> LangOptions &LO,
> - const
> TargetInfo &Target) {
> -
> - unsigned argIndex = 0;
> -
> - // Keep looking for a %s format specifier until we have exhausted the
> string.
> - FormatStringHandler H;
> - while (I != E) {
> - const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E,
> argIndex,
> - LO, Target,
> false,
> - false);
> - // Did a fail-stop error of any kind occur when parsing the specifier?
> - // If so, don't do any more processing.
> - if (FSR.shouldStop())
> - return false;
> - // Did we exhaust the string or encounter an error that
> - // we can recover from?
> - if (!FSR.hasValue())
> - continue;
> - const analyze_printf::PrintfSpecifier &FS = FSR.getValue();
> - // Return true if this a %s format specifier.
> - if (FS.getConversionSpecifier().getKind() ==
> ConversionSpecifier::Kind::sArg)
> - return true;
> - }
> - return false;
> -}
> -
>
> -//===----------------------------------------------------------------------===//
> -// Methods on PrintfSpecifier.
>
> -//===----------------------------------------------------------------------===//
> -
> -ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
> - bool IsObjCLiteral) const {
> - const PrintfConversionSpecifier &CS = getConversionSpecifier();
> -
> - if (!CS.consumesDataArgument())
> - return ArgType::Invalid();
> -
> - if (CS.getKind() == ConversionSpecifier::cArg)
> - switch (LM.getKind()) {
> - case LengthModifier::None:
> - return Ctx.IntTy;
> - case LengthModifier::AsLong:
> - case LengthModifier::AsWide:
> - return ArgType(ArgType::WIntTy, "wint_t");
> - case LengthModifier::AsShort:
> - if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
> - return Ctx.IntTy;
> - LLVM_FALLTHROUGH;
> - default:
> - return ArgType::Invalid();
> - }
> -
> - if (CS.isIntArg())
> - switch (LM.getKind()) {
> - case LengthModifier::AsLongDouble:
> - // GNU extension.
> - return Ctx.LongLongTy;
> - case LengthModifier::None:
> - return Ctx.IntTy;
> - case LengthModifier::AsInt32:
> - return ArgType(Ctx.IntTy, "__int32");
> - case LengthModifier::AsChar: return ArgType::AnyCharTy;
> - case LengthModifier::AsShort: return Ctx.ShortTy;
> - case LengthModifier::AsLong: return Ctx.LongTy;
> - case LengthModifier::AsLongLong:
> - case LengthModifier::AsQuad:
> - return Ctx.LongLongTy;
> - case LengthModifier::AsInt64:
> - return ArgType(Ctx.LongLongTy, "__int64");
> - case LengthModifier::AsIntMax:
> - return ArgType(Ctx.getIntMaxType(), "intmax_t");
> - case LengthModifier::AsSizeT:
> - return ArgType::makeSizeT(ArgType(Ctx.getSignedSizeType(),
> "ssize_t"));
> - case LengthModifier::AsInt3264:
> - return Ctx.getTargetInfo().getTriple().isArch64Bit()
> - ? ArgType(Ctx.LongLongTy, "__int64")
> - : ArgType(Ctx.IntTy, "__int32");
> - case LengthModifier::AsPtrDiff:
> - return ArgType::makePtrdiffT(
> - ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
> - case LengthModifier::AsAllocate:
> - case LengthModifier::AsMAllocate:
> - case LengthModifier::AsWide:
> - return ArgType::Invalid();
> - }
> -
> - if (CS.isUIntArg())
> - switch (LM.getKind()) {
> - case LengthModifier::AsLongDouble:
> - // GNU extension.
> - return Ctx.UnsignedLongLongTy;
> - case LengthModifier::None:
> - return Ctx.UnsignedIntTy;
> - case LengthModifier::AsInt32:
> - return ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
> - case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
> - case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
> - case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
> - case LengthModifier::AsLongLong:
> - case LengthModifier::AsQuad:
> - return Ctx.UnsignedLongLongTy;
> - case LengthModifier::AsInt64:
> - return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64");
> - case LengthModifier::AsIntMax:
> - return ArgType(Ctx.getUIntMaxType(), "uintmax_t");
> - case LengthModifier::AsSizeT:
> - return ArgType::makeSizeT(ArgType(Ctx.getSizeType(), "size_t"));
> - case LengthModifier::AsInt3264:
> - return Ctx.getTargetInfo().getTriple().isArch64Bit()
> - ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64")
> - : ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
> - case LengthModifier::AsPtrDiff:
> - return ArgType::makePtrdiffT(
> - ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned
> ptrdiff_t"));
> - case LengthModifier::AsAllocate:
> - case LengthModifier::AsMAllocate:
> - case LengthModifier::AsWide:
> - return ArgType::Invalid();
> - }
> -
> - if (CS.isDoubleArg()) {
> - if (LM.getKind() == LengthModifier::AsLongDouble)
> - return Ctx.LongDoubleTy;
> - return Ctx.DoubleTy;
> - }
> -
> - if (CS.getKind() == ConversionSpecifier::nArg) {
> - switch (LM.getKind()) {
> - case LengthModifier::None:
> - return ArgType::PtrTo(Ctx.IntTy);
> - case LengthModifier::AsChar:
> - return ArgType::PtrTo(Ctx.SignedCharTy);
> - case LengthModifier::AsShort:
> - return ArgType::PtrTo(Ctx.ShortTy);
> - case LengthModifier::AsLong:
> - return ArgType::PtrTo(Ctx.LongTy);
> - case LengthModifier::AsLongLong:
> - case LengthModifier::AsQuad:
> - return ArgType::PtrTo(Ctx.LongLongTy);
> - case LengthModifier::AsIntMax:
> - return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
> - case LengthModifier::AsSizeT:
> - return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(),
> "ssize_t"));
> - case LengthModifier::AsPtrDiff:
> - return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(),
> "ptrdiff_t"));
> - case LengthModifier::AsLongDouble:
> - return ArgType(); // FIXME: Is this a known extension?
> - case LengthModifier::AsAllocate:
> - case LengthModifier::AsMAllocate:
> - case LengthModifier::AsInt32:
> - case LengthModifier::AsInt3264:
> - case LengthModifier::AsInt64:
> - case LengthModifier::AsWide:
> - return ArgType::Invalid();
> - }
> - }
> -
> - switch (CS.getKind()) {
> - case ConversionSpecifier::sArg:
> - if (LM.getKind() == LengthModifier::AsWideChar) {
> - if (IsObjCLiteral)
> - return
> ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
> - "const unichar *");
> - return ArgType(ArgType::WCStrTy, "wchar_t *");
> - }
> - if (LM.getKind() == LengthModifier::AsWide)
> - return ArgType(ArgType::WCStrTy, "wchar_t *");
> - return ArgType::CStrTy;
> - case ConversionSpecifier::SArg:
> - if (IsObjCLiteral)
> - return
> ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
> - "const unichar *");
> - if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
> - LM.getKind() == LengthModifier::AsShort)
> - return ArgType::CStrTy;
> - return ArgType(ArgType::WCStrTy, "wchar_t *");
> - case ConversionSpecifier::CArg:
> - if (IsObjCLiteral)
> - return ArgType(Ctx.UnsignedShortTy, "unichar");
> - if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
> - LM.getKind() == LengthModifier::AsShort)
> - return Ctx.IntTy;
> - return ArgType(Ctx.WideCharTy, "wchar_t");
> - case ConversionSpecifier::pArg:
> - case ConversionSpecifier::PArg:
> - return ArgType::CPointerTy;
> - case ConversionSpecifier::ObjCObjArg:
> - return ArgType::ObjCPointerTy;
> - default:
> - break;
> - }
> -
> - // FIXME: Handle other cases.
> - return ArgType();
> -}
> -
> -bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
> - ASTContext &Ctx, bool IsObjCLiteral) {
> - // %n is different from other conversion specifiers; don't try to fix
> it.
> - if (CS.getKind() == ConversionSpecifier::nArg)
> - return false;
> -
> - // Handle Objective-C objects first. Note that while the '%@' specifier
> will
> - // not warn for structure pointer or void pointer arguments (because
> that's
> - // how CoreFoundation objects are implemented), we only show a fixit
> for '%@'
> - // if we know it's an object (block, id, class, or
> __attribute__((NSObject))).
> - if (QT->isObjCRetainableType()) {
> - if (!IsObjCLiteral)
> - return false;
> -
> - CS.setKind(ConversionSpecifier::ObjCObjArg);
> -
> - // Disable irrelevant flags
> - HasThousandsGrouping = false;
> - HasPlusPrefix = false;
> - HasSpacePrefix = false;
> - HasAlternativeForm = false;
> - HasLeadingZeroes = false;
> - Precision.setHowSpecified(OptionalAmount::NotSpecified);
> - LM.setKind(LengthModifier::None);
> -
> - return true;
> - }
> -
> - // Handle strings next (char *, wchar_t *)
> - if (QT->isPointerType() &&
> (QT->getPointeeType()->isAnyCharacterType())) {
> - CS.setKind(ConversionSpecifier::sArg);
> -
> - // Disable irrelevant flags
> - HasAlternativeForm = 0;
> - HasLeadingZeroes = 0;
> -
> - // Set the long length modifier for wide characters
> - if (QT->getPointeeType()->isWideCharType())
> - LM.setKind(LengthModifier::AsWideChar);
> - else
> - LM.setKind(LengthModifier::None);
> -
> - return true;
> - }
> -
> - // If it's an enum, get its underlying type.
> - if (const EnumType *ETy = QT->getAs<EnumType>())
> - QT = ETy->getDecl()->getIntegerType();
> -
> - // We can only work with builtin types.
> - const BuiltinType *BT = QT->getAs<BuiltinType>();
> - if (!BT)
> - return false;
> -
> - // Set length modifier
> - switch (BT->getKind()) {
> - case BuiltinType::Bool:
> - case BuiltinType::WChar_U:
> - case BuiltinType::WChar_S:
> - case BuiltinType::Char8: // FIXME: Treat like 'char'?
> - case BuiltinType::Char16:
> - case BuiltinType::Char32:
> - case BuiltinType::UInt128:
> - case BuiltinType::Int128:
> - case BuiltinType::Half:
> - case BuiltinType::Float16:
> - case BuiltinType::Float128:
> - case BuiltinType::ShortAccum:
> - case BuiltinType::Accum:
> - case BuiltinType::LongAccum:
> - case BuiltinType::UShortAccum:
> - case BuiltinType::UAccum:
> - case BuiltinType::ULongAccum:
> - case BuiltinType::ShortFract:
> - case BuiltinType::Fract:
> - case BuiltinType::LongFract:
> - case BuiltinType::UShortFract:
> - case BuiltinType::UFract:
> - case BuiltinType::ULongFract:
> - case BuiltinType::SatShortAccum:
> - case BuiltinType::SatAccum:
> - case BuiltinType::SatLongAccum:
> - case BuiltinType::SatUShortAccum:
> - case BuiltinType::SatUAccum:
> - case BuiltinType::SatULongAccum:
> - case BuiltinType::SatShortFract:
> - case BuiltinType::SatFract:
> - case BuiltinType::SatLongFract:
> - case BuiltinType::SatUShortFract:
> - case BuiltinType::SatUFract:
> - case BuiltinType::SatULongFract:
> - // Various types which are non-trivial to correct.
> - return false;
> -
> -#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
> - case BuiltinType::Id:
> -#include "clang/Basic/OpenCLImageTypes.def"
> -#define SIGNED_TYPE(Id, SingletonId)
> -#define UNSIGNED_TYPE(Id, SingletonId)
> -#define FLOATING_TYPE(Id, SingletonId)
> -#define BUILTIN_TYPE(Id, SingletonId) \
> - case BuiltinType::Id:
> -#include "clang/AST/BuiltinTypes.def"
> - // Misc other stuff which doesn't make sense here.
> - return false;
> -
> - case BuiltinType::UInt:
> - case BuiltinType::Int:
> - case BuiltinType::Float:
> - case BuiltinType::Double:
> - LM.setKind(LengthModifier::None);
> - break;
> -
> - case BuiltinType::Char_U:
> - case BuiltinType::UChar:
> - case BuiltinType::Char_S:
> - case BuiltinType::SChar:
> - LM.setKind(LengthModifier::AsChar);
> - break;
> -
> - case BuiltinType::Short:
> - case BuiltinType::UShort:
> - LM.setKind(LengthModifier::AsShort);
> - break;
> -
> - case BuiltinType::Long:
> - case BuiltinType::ULong:
> - LM.setKind(LengthModifier::AsLong);
> - break;
> -
> - case BuiltinType::LongLong:
> - case BuiltinType::ULongLong:
> - LM.setKind(LengthModifier::AsLongLong);
> - break;
> -
> - case BuiltinType::LongDouble:
> - LM.setKind(LengthModifier::AsLongDouble);
> - break;
> - }
> -
> - // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers
> in C99.
> - if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
> - namedTypeToLengthModifier(QT, LM);
> -
> - // If fixing the length modifier was enough, we might be done.
> - if (hasValidLengthModifier(Ctx.getTargetInfo())) {
> - // If we're going to offer a fix anyway, make sure the sign matches.
> - switch (CS.getKind()) {
> - case ConversionSpecifier::uArg:
> - case ConversionSpecifier::UArg:
> - if (QT->isSignedIntegerType())
> -
> CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg);
> - break;
> - case ConversionSpecifier::dArg:
> - case ConversionSpecifier::DArg:
> - case ConversionSpecifier::iArg:
> - if (QT->isUnsignedIntegerType() && !HasPlusPrefix)
> -
> CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg);
> - break;
> - default:
> - // Other specifiers do not have signed/unsigned variants.
> - break;
> - }
> -
> - const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
> - if (ATR.isValid() && ATR.matchesType(Ctx, QT))
> - return true;
> - }
> -
> - // Set conversion specifier and disable any flags which do not apply to
> it.
> - // Let typedefs to char fall through to int, as %c is silly for uint8_t.
> - if (!isa<TypedefType>(QT) && QT->isCharType()) {
> - CS.setKind(ConversionSpecifier::cArg);
> - LM.setKind(LengthModifier::None);
> - Precision.setHowSpecified(OptionalAmount::NotSpecified);
> - HasAlternativeForm = 0;
> - HasLeadingZeroes = 0;
> - HasPlusPrefix = 0;
> - }
> - // Test for Floating type first as LongDouble can pass
> isUnsignedIntegerType
> - else if (QT->isRealFloatingType()) {
> - CS.setKind(ConversionSpecifier::fArg);
> - }
> - else if (QT->isSignedIntegerType()) {
> - CS.setKind(ConversionSpecifier::dArg);
> - HasAlternativeForm = 0;
> - }
> - else if (QT->isUnsignedIntegerType()) {
> - CS.setKind(ConversionSpecifier::uArg);
> - HasAlternativeForm = 0;
> - HasPlusPrefix = 0;
> - } else {
> - llvm_unreachable("Unexpected type");
> - }
> -
> - return true;
> -}
> -
> -void PrintfSpecifier::toString(raw_ostream &os) const {
> - // Whilst some features have no defined order, we are using the order
> - // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)
> - os << "%";
> -
> - // Positional args
> - if (usesPositionalArg()) {
> - os << getPositionalArgIndex() << "$";
> - }
> -
> - // Conversion flags
> - if (IsLeftJustified) os << "-";
> - if (HasPlusPrefix) os << "+";
> - if (HasSpacePrefix) os << " ";
> - if (HasAlternativeForm) os << "#";
> - if (HasLeadingZeroes) os << "0";
> -
> - // Minimum field width
> - FieldWidth.toString(os);
> - // Precision
> - Precision.toString(os);
> - // Length modifier
> - os << LM.toString();
> - // Conversion specifier
> - os << CS.toString();
> -}
> -
> -bool PrintfSpecifier::hasValidPlusPrefix() const {
> - if (!HasPlusPrefix)
> - return true;
> -
> - // The plus prefix only makes sense for signed conversions
> - switch (CS.getKind()) {
> - case ConversionSpecifier::dArg:
> - case ConversionSpecifier::DArg:
> - case ConversionSpecifier::iArg:
> - case ConversionSpecifier::fArg:
> - case ConversionSpecifier::FArg:
> - case ConversionSpecifier::eArg:
> - case ConversionSpecifier::EArg:
> - case ConversionSpecifier::gArg:
> - case ConversionSpecifier::GArg:
> - case ConversionSpecifier::aArg:
> - case ConversionSpecifier::AArg:
> - case ConversionSpecifier::FreeBSDrArg:
> - case ConversionSpecifier::FreeBSDyArg:
> - return true;
> -
> - default:
> - return false;
> - }
> -}
> -
> -bool PrintfSpecifier::hasValidAlternativeForm() const {
> - if (!HasAlternativeForm)
> - return true;
> -
> - // Alternate form flag only valid with the oxXaAeEfFgG conversions
> - switch (CS.getKind()) {
> - case ConversionSpecifier::oArg:
> - case ConversionSpecifier::OArg:
> - case ConversionSpecifier::xArg:
> - case ConversionSpecifier::XArg:
> - case ConversionSpecifier::aArg:
> - case ConversionSpecifier::AArg:
> - case ConversionSpecifier::eArg:
> - case ConversionSpecifier::EArg:
> - case ConversionSpecifier::fArg:
> - case ConversionSpecifier::FArg:
> - case ConversionSpecifier::gArg:
> - case ConversionSpecifier::GArg:
> - case ConversionSpecifier::FreeBSDrArg:
> - case ConversionSpecifier::FreeBSDyArg:
> - return true;
> -
> - default:
> - return false;
> - }
> -}
> -
> -bool PrintfSpecifier::hasValidLeadingZeros() const {
> - if (!HasLeadingZeroes)
> - return true;
> -
> - // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions
> - switch (CS.getKind()) {
> - case ConversionSpecifier::dArg:
> - case ConversionSpecifier::DArg:
> - case ConversionSpecifier::iArg:
> - case ConversionSpecifier::oArg:
> - case ConversionSpecifier::OArg:
> - case ConversionSpecifier::uArg:
> - case ConversionSpecifier::UArg:
> - case ConversionSpecifier::xArg:
> - case ConversionSpecifier::XArg:
> - case ConversionSpecifier::aArg:
> - case ConversionSpecifier::AArg:
> - case ConversionSpecifier::eArg:
> - case ConversionSpecifier::EArg:
> - case ConversionSpecifier::fArg:
> - case ConversionSpecifier::FArg:
> - case ConversionSpecifier::gArg:
> - case ConversionSpecifier::GArg:
> - case ConversionSpecifier::FreeBSDrArg:
> - case ConversionSpecifier::FreeBSDyArg:
> - return true;
> -
> - default:
> - return false;
> - }
> -}
> -
> -bool PrintfSpecifier::hasValidSpacePrefix() const {
> - if (!HasSpacePrefix)
> - return true;
> -
> - // The space prefix only makes sense for signed conversions
> - switch (CS.getKind()) {
> - case ConversionSpecifier::dArg:
> - case ConversionSpecifier::DArg:
> - case ConversionSpecifier::iArg:
> - case ConversionSpecifier::fArg:
> - case ConversionSpecifier::FArg:
> - case ConversionSpecifier::eArg:
> - case ConversionSpecifier::EArg:
> - case ConversionSpecifier::gArg:
> - case ConversionSpecifier::GArg:
> - case ConversionSpecifier::aArg:
> - case ConversionSpecifier::AArg:
> - case ConversionSpecifier::FreeBSDrArg:
> - case ConversionSpecifier::FreeBSDyArg:
> - return true;
> -
> - default:
> - return false;
> - }
> -}
> -
> -bool PrintfSpecifier::hasValidLeftJustified() const {
> - if (!IsLeftJustified)
> - return true;
> -
> - // The left justified flag is valid for all conversions except n
> - switch (CS.getKind()) {
> - case ConversionSpecifier::nArg:
> - return false;
> -
> - default:
> - return true;
> - }
> -}
> -
> -bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const {
> - if (!HasThousandsGrouping)
> - return true;
> -
> - switch (CS.getKind()) {
> - case ConversionSpecifier::dArg:
> - case ConversionSpecifier::DArg:
> - case ConversionSpecifier::iArg:
> - case ConversionSpecifier::uArg:
> - case ConversionSpecifier::UArg:
> - case ConversionSpecifier::fArg:
> - case ConversionSpecifier::FArg:
> - case ConversionSpecifier::gArg:
> - case ConversionSpecifier::GArg:
> - return true;
> - default:
> - return false;
> - }
> -}
> -
> -bool PrintfSpecifier::hasValidPrecision() const {
> - if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
> - return true;
> -
> - // Precision is only valid with the diouxXaAeEfFgGsP conversions
> - switch (CS.getKind()) {
> - case ConversionSpecifier::dArg:
> - case ConversionSpecifier::DArg:
> - case ConversionSpecifier::iArg:
> - case ConversionSpecifier::oArg:
> - case ConversionSpecifier::OArg:
> - case ConversionSpecifier::uArg:
> - case ConversionSpecifier::UArg:
> - case ConversionSpecifier::xArg:
> - case ConversionSpecifier::XArg:
> - case ConversionSpecifier::aArg:
> - case ConversionSpecifier::AArg:
> - case ConversionSpecifier::eArg:
> - case ConversionSpecifier::EArg:
> - case ConversionSpecifier::fArg:
> - case ConversionSpecifier::FArg:
> - case ConversionSpecifier::gArg:
> - case ConversionSpecifier::GArg:
> - case ConversionSpecifier::sArg:
> - case ConversionSpecifier::FreeBSDrArg:
> - case ConversionSpecifier::FreeBSDyArg:
> - case ConversionSpecifier::PArg:
> - return true;
> -
> - default:
> - return false;
> - }
> -}
> -bool PrintfSpecifier::hasValidFieldWidth() const {
> - if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)
> - return true;
> -
> - // The field width is valid for all conversions except n
> - switch (CS.getKind()) {
> - case ConversionSpecifier::nArg:
> - return false;
> -
> - default:
> - return true;
> - }
> -}
>
> Removed: cfe/trunk/lib/Analysis/ScanfFormatString.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ScanfFormatString.cpp?rev=345970&view=auto
>
> ==============================================================================
> --- cfe/trunk/lib/Analysis/ScanfFormatString.cpp (original)
> +++ cfe/trunk/lib/Analysis/ScanfFormatString.cpp (removed)
> @@ -1,563 +0,0 @@
> -//= ScanfFormatString.cpp - Analysis of printf format strings --*- C++
> -*-===//
> -//
> -// The LLVM Compiler Infrastructure
> -//
> -// This file is distributed under the University of Illinois Open Source
> -// License. See LICENSE.TXT for details.
> -//
>
> -//===----------------------------------------------------------------------===//
> -//
> -// Handling of format string in scanf and friends. The structure of
> format
> -// strings for fscanf() are described in C99 7.19.6.2.
> -//
>
> -//===----------------------------------------------------------------------===//
> -
> -#include "clang/Analysis/Analyses/FormatString.h"
> -#include "FormatStringParsing.h"
> -#include "clang/Basic/TargetInfo.h"
> -
> -using clang::analyze_format_string::ArgType;
> -using clang::analyze_format_string::FormatStringHandler;
> -using clang::analyze_format_string::LengthModifier;
> -using clang::analyze_format_string::OptionalAmount;
> -using clang::analyze_format_string::ConversionSpecifier;
> -using clang::analyze_scanf::ScanfConversionSpecifier;
> -using clang::analyze_scanf::ScanfSpecifier;
> -using clang::UpdateOnReturn;
> -using namespace clang;
> -
> -typedef clang::analyze_format_string::SpecifierResult<ScanfSpecifier>
> - ScanfSpecifierResult;
> -
> -static bool ParseScanList(FormatStringHandler &H,
> - ScanfConversionSpecifier &CS,
> - const char *&Beg, const char *E) {
> - const char *I = Beg;
> - const char *start = I - 1;
> - UpdateOnReturn <const char*> UpdateBeg(Beg, I);
> -
> - // No more characters?
> - if (I == E) {
> - H.HandleIncompleteScanList(start, I);
> - return true;
> - }
> -
> - // Special case: ']' is the first character.
> - if (*I == ']') {
> - if (++I == E) {
> - H.HandleIncompleteScanList(start, I - 1);
> - return true;
> - }
> - }
> -
> - // Special case: "^]" are the first characters.
> - if (I + 1 != E && I[0] == '^' && I[1] == ']') {
> - I += 2;
> - if (I == E) {
> - H.HandleIncompleteScanList(start, I - 1);
> - return true;
> - }
> - }
> -
> - // Look for a ']' character which denotes the end of the scan list.
> - while (*I != ']') {
> - if (++I == E) {
> - H.HandleIncompleteScanList(start, I - 1);
> - return true;
> - }
> - }
> -
> - CS.setEndScanList(I);
> - return false;
> -}
> -
> -// FIXME: Much of this is copy-paste from ParsePrintfSpecifier.
> -// We can possibly refactor.
> -static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
> - const char *&Beg,
> - const char *E,
> - unsigned &argIndex,
> - const LangOptions &LO,
> - const TargetInfo &Target)
> {
> - using namespace clang::analyze_format_string;
> - using namespace clang::analyze_scanf;
> - 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?
> - H.HandleIncompleteSpecifier(Start, E - Start);
> - return true;
> - }
> -
> - ScanfSpecifier 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 '*' flag if it is present.
> - if (*I == '*') {
> - FS.setSuppressAssignment(I);
> - if (++I == E) {
> - H.HandleIncompleteSpecifier(Start, E - Start);
> - return true;
> - }
> - }
> -
> - // Look for the field width (if any). Unlike printf, this is either
> - // a fixed integer or isn't present.
> - const OptionalAmount &Amt =
> clang::analyze_format_string::ParseAmount(I, E);
> - if (Amt.getHowSpecified() != OptionalAmount::NotSpecified) {
> - assert(Amt.getHowSpecified() == OptionalAmount::Constant);
> - FS.setFieldWidth(Amt);
> -
> - if (I == E) {
> - // No more characters left?
> - H.HandleIncompleteSpecifier(Start, E - Start);
> - return true;
> - }
> - }
> -
> - // Look for the length modifier.
> - if (ParseLengthModifier(FS, I, E, LO, /*scanf=*/true) && I == E) {
> - // No more characters left?
> - H.HandleIncompleteSpecifier(Start, E - Start);
> - return true;
> - }
> -
> - // Detect spurious null characters, which are likely errors.
> - if (*I == '\0') {
> - H.HandleNullChar(I);
> - return true;
> - }
> -
> - // Finally, look for the conversion specifier.
> - const char *conversionPosition = I++;
> - ScanfConversionSpecifier::Kind k =
> ScanfConversionSpecifier::InvalidSpecifier;
> - switch (*conversionPosition) {
> - default:
> - break;
> - 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 '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 'c': k = ConversionSpecifier::cArg; break;
> - case 'C': k = ConversionSpecifier::CArg; break;
> - case 'S': k = ConversionSpecifier::SArg; break;
> - case '[': k = ConversionSpecifier::ScanListArg; break;
> - case 'u': k = ConversionSpecifier::uArg; break;
> - case 'x': k = ConversionSpecifier::xArg; break;
> - case 'o': k = ConversionSpecifier::oArg; break;
> - case 's': k = ConversionSpecifier::sArg; break;
> - case 'p': k = ConversionSpecifier::pArg; break;
> - // Apple extensions
> - // Apple-specific
> - case 'D':
> - 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;
> - }
> - ScanfConversionSpecifier CS(conversionPosition, k);
> - if (k == ScanfConversionSpecifier::ScanListArg) {
> - if (ParseScanList(H, CS, I, E))
> - return true;
> - }
> - FS.setConversionSpecifier(CS);
> - if (CS.consumesDataArgument() && !FS.getSuppressAssignment()
> - && !FS.usesPositionalArg())
> - FS.setArgIndex(argIndex++);
> -
> - // FIXME: '%' and '*' doesn't make sense. Issue a warning.
> - // FIXME: 'ConsumedSoFar' and '*' doesn't make sense.
> -
> - if (k == ScanfConversionSpecifier::InvalidSpecifier) {
> - unsigned Len = I - Beg;
> - if (ParseUTF8InvalidSpecifier(Beg, E, Len)) {
> - CS.setEndScanList(Beg + Len);
> - FS.setConversionSpecifier(CS);
> - }
> - // Assume the conversion takes one argument.
> - return !H.HandleInvalidScanfConversionSpecifier(FS, Beg, Len);
> - }
> - return ScanfSpecifierResult(Start, FS);
> -}
> -
> -ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
> - const ScanfConversionSpecifier &CS = getConversionSpecifier();
> -
> - if (!CS.consumesDataArgument())
> - return ArgType::Invalid();
> -
> - switch(CS.getKind()) {
> - // Signed int.
> - case ConversionSpecifier::dArg:
> - case ConversionSpecifier::DArg:
> - case ConversionSpecifier::iArg:
> - switch (LM.getKind()) {
> - case LengthModifier::None:
> - return ArgType::PtrTo(Ctx.IntTy);
> - case LengthModifier::AsChar:
> - return ArgType::PtrTo(ArgType::AnyCharTy);
> - case LengthModifier::AsShort:
> - return ArgType::PtrTo(Ctx.ShortTy);
> - case LengthModifier::AsLong:
> - return ArgType::PtrTo(Ctx.LongTy);
> - case LengthModifier::AsLongLong:
> - case LengthModifier::AsQuad:
> - return ArgType::PtrTo(Ctx.LongLongTy);
> - case LengthModifier::AsInt64:
> - return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));
> - case LengthModifier::AsIntMax:
> - return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
> - case LengthModifier::AsSizeT:
> - return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(),
> "ssize_t"));
> - case LengthModifier::AsPtrDiff:
> - return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(),
> "ptrdiff_t"));
> - case LengthModifier::AsLongDouble:
> - // GNU extension.
> - return ArgType::PtrTo(Ctx.LongLongTy);
> - case LengthModifier::AsAllocate:
> - case LengthModifier::AsMAllocate:
> - case LengthModifier::AsInt32:
> - case LengthModifier::AsInt3264:
> - case LengthModifier::AsWide:
> - return ArgType::Invalid();
> - }
> -
> - // Unsigned int.
> - case ConversionSpecifier::oArg:
> - case ConversionSpecifier::OArg:
> - case ConversionSpecifier::uArg:
> - case ConversionSpecifier::UArg:
> - case ConversionSpecifier::xArg:
> - case ConversionSpecifier::XArg:
> - switch (LM.getKind()) {
> - case LengthModifier::None:
> - return ArgType::PtrTo(Ctx.UnsignedIntTy);
> - case LengthModifier::AsChar:
> - return ArgType::PtrTo(Ctx.UnsignedCharTy);
> - case LengthModifier::AsShort:
> - return ArgType::PtrTo(Ctx.UnsignedShortTy);
> - case LengthModifier::AsLong:
> - return ArgType::PtrTo(Ctx.UnsignedLongTy);
> - case LengthModifier::AsLongLong:
> - case LengthModifier::AsQuad:
> - return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
> - case LengthModifier::AsInt64:
> - return ArgType::PtrTo(ArgType(Ctx.UnsignedLongLongTy, "unsigned
> __int64"));
> - case LengthModifier::AsIntMax:
> - return ArgType::PtrTo(ArgType(Ctx.getUIntMaxType(),
> "uintmax_t"));
> - case LengthModifier::AsSizeT:
> - return ArgType::PtrTo(ArgType(Ctx.getSizeType(), "size_t"));
> - case LengthModifier::AsPtrDiff:
> - return ArgType::PtrTo(
> - ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned
> ptrdiff_t"));
> - case LengthModifier::AsLongDouble:
> - // GNU extension.
> - return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
> - case LengthModifier::AsAllocate:
> - case LengthModifier::AsMAllocate:
> - case LengthModifier::AsInt32:
> - case LengthModifier::AsInt3264:
> - case LengthModifier::AsWide:
> - return ArgType::Invalid();
> - }
> -
> - // Float.
> - case ConversionSpecifier::aArg:
> - case ConversionSpecifier::AArg:
> - case ConversionSpecifier::eArg:
> - case ConversionSpecifier::EArg:
> - case ConversionSpecifier::fArg:
> - case ConversionSpecifier::FArg:
> - case ConversionSpecifier::gArg:
> - case ConversionSpecifier::GArg:
> - switch (LM.getKind()) {
> - case LengthModifier::None:
> - return ArgType::PtrTo(Ctx.FloatTy);
> - case LengthModifier::AsLong:
> - return ArgType::PtrTo(Ctx.DoubleTy);
> - case LengthModifier::AsLongDouble:
> - return ArgType::PtrTo(Ctx.LongDoubleTy);
> - default:
> - return ArgType::Invalid();
> - }
> -
> - // Char, string and scanlist.
> - case ConversionSpecifier::cArg:
> - case ConversionSpecifier::sArg:
> - case ConversionSpecifier::ScanListArg:
> - switch (LM.getKind()) {
> - case LengthModifier::None:
> - return ArgType::PtrTo(ArgType::AnyCharTy);
> - case LengthModifier::AsLong:
> - case LengthModifier::AsWide:
> - return ArgType::PtrTo(ArgType(Ctx.getWideCharType(),
> "wchar_t"));
> - case LengthModifier::AsAllocate:
> - case LengthModifier::AsMAllocate:
> - return ArgType::PtrTo(ArgType::CStrTy);
> - case LengthModifier::AsShort:
> - if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
> - return ArgType::PtrTo(ArgType::AnyCharTy);
> - LLVM_FALLTHROUGH;
> - default:
> - return ArgType::Invalid();
> - }
> - case ConversionSpecifier::CArg:
> - case ConversionSpecifier::SArg:
> - // FIXME: Mac OS X specific?
> - switch (LM.getKind()) {
> - case LengthModifier::None:
> - case LengthModifier::AsWide:
> - return ArgType::PtrTo(ArgType(Ctx.getWideCharType(),
> "wchar_t"));
> - case LengthModifier::AsAllocate:
> - case LengthModifier::AsMAllocate:
> - return ArgType::PtrTo(ArgType(ArgType::WCStrTy, "wchar_t *"));
> - case LengthModifier::AsShort:
> - if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
> - return ArgType::PtrTo(ArgType::AnyCharTy);
> - LLVM_FALLTHROUGH;
> - default:
> - return ArgType::Invalid();
> - }
> -
> - // Pointer.
> - case ConversionSpecifier::pArg:
> - return ArgType::PtrTo(ArgType::CPointerTy);
> -
> - // Write-back.
> - case ConversionSpecifier::nArg:
> - switch (LM.getKind()) {
> - case LengthModifier::None:
> - return ArgType::PtrTo(Ctx.IntTy);
> - case LengthModifier::AsChar:
> - return ArgType::PtrTo(Ctx.SignedCharTy);
> - case LengthModifier::AsShort:
> - return ArgType::PtrTo(Ctx.ShortTy);
> - case LengthModifier::AsLong:
> - return ArgType::PtrTo(Ctx.LongTy);
> - case LengthModifier::AsLongLong:
> - case LengthModifier::AsQuad:
> - return ArgType::PtrTo(Ctx.LongLongTy);
> - case LengthModifier::AsInt64:
> - return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));
> - case LengthModifier::AsIntMax:
> - return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
> - case LengthModifier::AsSizeT:
> - return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(),
> "ssize_t"));
> - case LengthModifier::AsPtrDiff:
> - return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(),
> "ptrdiff_t"));
> - case LengthModifier::AsLongDouble:
> - return ArgType(); // FIXME: Is this a known extension?
> - case LengthModifier::AsAllocate:
> - case LengthModifier::AsMAllocate:
> - case LengthModifier::AsInt32:
> - case LengthModifier::AsInt3264:
> - case LengthModifier::AsWide:
> - return ArgType::Invalid();
> - }
> -
> - default:
> - break;
> - }
> -
> - return ArgType();
> -}
> -
> -bool ScanfSpecifier::fixType(QualType QT, QualType RawQT,
> - const LangOptions &LangOpt,
> - ASTContext &Ctx) {
> -
> - // %n is different from other conversion specifiers; don't try to fix
> it.
> - if (CS.getKind() == ConversionSpecifier::nArg)
> - return false;
> -
> - if (!QT->isPointerType())
> - return false;
> -
> - QualType PT = QT->getPointeeType();
> -
> - // If it's an enum, get its underlying type.
> - if (const EnumType *ETy = PT->getAs<EnumType>()) {
> - // Don't try to fix incomplete enums.
> - if (!ETy->getDecl()->isComplete())
> - return false;
> - PT = ETy->getDecl()->getIntegerType();
> - }
> -
> - const BuiltinType *BT = PT->getAs<BuiltinType>();
> - if (!BT)
> - return false;
> -
> - // Pointer to a character.
> - if (PT->isAnyCharacterType()) {
> - CS.setKind(ConversionSpecifier::sArg);
> - if (PT->isWideCharType())
> - LM.setKind(LengthModifier::AsWideChar);
> - else
> - LM.setKind(LengthModifier::None);
> -
> - // If we know the target array length, we can use it as a field width.
> - if (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(RawQT))
> {
> - if (CAT->getSizeModifier() == ArrayType::Normal)
> - FieldWidth = OptionalAmount(OptionalAmount::Constant,
> - CAT->getSize().getZExtValue() - 1,
> - "", 0, false);
> -
> - }
> - return true;
> - }
> -
> - // Figure out the length modifier.
> - switch (BT->getKind()) {
> - // no modifier
> - case BuiltinType::UInt:
> - case BuiltinType::Int:
> - case BuiltinType::Float:
> - LM.setKind(LengthModifier::None);
> - break;
> -
> - // hh
> - case BuiltinType::Char_U:
> - case BuiltinType::UChar:
> - case BuiltinType::Char_S:
> - case BuiltinType::SChar:
> - LM.setKind(LengthModifier::AsChar);
> - break;
> -
> - // h
> - case BuiltinType::Short:
> - case BuiltinType::UShort:
> - LM.setKind(LengthModifier::AsShort);
> - break;
> -
> - // l
> - case BuiltinType::Long:
> - case BuiltinType::ULong:
> - case BuiltinType::Double:
> - LM.setKind(LengthModifier::AsLong);
> - break;
> -
> - // ll
> - case BuiltinType::LongLong:
> - case BuiltinType::ULongLong:
> - LM.setKind(LengthModifier::AsLongLong);
> - break;
> -
> - // L
> - case BuiltinType::LongDouble:
> - LM.setKind(LengthModifier::AsLongDouble);
> - break;
> -
> - // Don't know.
> - default:
> - return false;
> - }
> -
> - // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers
> in C99.
> - if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
> - namedTypeToLengthModifier(PT, LM);
> -
> - // If fixing the length modifier was enough, we are done.
> - if (hasValidLengthModifier(Ctx.getTargetInfo())) {
> - const analyze_scanf::ArgType &AT = getArgType(Ctx);
> - if (AT.isValid() && AT.matchesType(Ctx, QT))
> - return true;
> - }
> -
> - // Figure out the conversion specifier.
> - if (PT->isRealFloatingType())
> - CS.setKind(ConversionSpecifier::fArg);
> - else if (PT->isSignedIntegerType())
> - CS.setKind(ConversionSpecifier::dArg);
> - else if (PT->isUnsignedIntegerType())
> - CS.setKind(ConversionSpecifier::uArg);
> - else
> - llvm_unreachable("Unexpected type");
> -
> - return true;
> -}
> -
> -void ScanfSpecifier::toString(raw_ostream &os) const {
> - os << "%";
> -
> - if (usesPositionalArg())
> - os << getPositionalArgIndex() << "$";
> - if (SuppressAssignment)
> - os << "*";
> -
> - FieldWidth.toString(os);
> - os << LM.toString();
> - os << CS.toString();
> -}
> -
> -bool clang::analyze_format_string::ParseScanfString(FormatStringHandler
> &H,
> - const char *I,
> - const char *E,
> - const LangOptions &LO,
> - const TargetInfo
> &Target) {
> -
> - unsigned argIndex = 0;
> -
> - // Keep looking for a format specifier until we have exhausted the
> string.
> - while (I != E) {
> - const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E,
> argIndex,
> - LO, Target);
> - // Did a fail-stop error of any kind occur when parsing the specifier?
> - // If so, don't do any more processing.
> - if (FSR.shouldStop())
> - return true;
> - // Did we exhaust the string or encounter an error that
> - // we can recover from?
> - if (!FSR.hasValue())
> - continue;
> - // We have a format specifier. Pass it to the callback.
> - if (!H.HandleScanfSpecifier(FSR.getValue(), FSR.getStart(),
> - I - FSR.getStart())) {
> - return true;
> - }
> - }
> - assert(I == E && "Format string not exhausted");
> - return false;
> -}
>
> Modified: cfe/trunk/lib/CodeGen/CGBuiltin.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBuiltin.cpp?rev=345971&r1=345970&r2=345971&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGBuiltin.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGBuiltin.cpp Fri Nov 2 06:14:11 2018
> @@ -21,7 +21,7 @@
> #include "TargetInfo.h"
> #include "clang/AST/ASTContext.h"
> #include "clang/AST/Decl.h"
> -#include "clang/Analysis/Analyses/OSLog.h"
> +#include "clang/AST/OSLog.h"
> #include "clang/Basic/TargetBuiltins.h"
> #include "clang/Basic/TargetInfo.h"
> #include "clang/CodeGen/CGFunctionInfo.h"
> @@ -3606,13 +3606,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(
> case Builtin::BI__builtin_os_log_format:
> return emitBuiltinOSLogFormat(*E);
>
> - case Builtin::BI__builtin_os_log_format_buffer_size: {
> - analyze_os_log::OSLogBufferLayout Layout;
> - analyze_os_log::computeOSLogBufferLayout(CGM.getContext(), E, Layout);
> - return RValue::get(ConstantInt::get(ConvertType(E->getType()),
> - Layout.size().getQuantity()));
> - }
> -
> case Builtin::BI__xray_customevent: {
> if (!ShouldXRayInstrumentFunction())
> return RValue::getIgnored();
>
> Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=345971&r1=345970&r2=345971&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaChecking.cpp Fri Nov 2 06:14:11 2018
> @@ -27,6 +27,7 @@
> #include "clang/AST/ExprCXX.h"
> #include "clang/AST/ExprObjC.h"
> #include "clang/AST/ExprOpenMP.h"
> +#include "clang/AST/FormatString.h"
> #include "clang/AST/NSAPI.h"
> #include "clang/AST/NonTrivialTypeVisitor.h"
> #include "clang/AST/OperationKinds.h"
> @@ -35,7 +36,6 @@
> #include "clang/AST/Type.h"
> #include "clang/AST/TypeLoc.h"
> #include "clang/AST/UnresolvedSet.h"
> -#include "clang/Analysis/Analyses/FormatString.h"
> #include "clang/Basic/AddressSpaces.h"
> #include "clang/Basic/CharInfo.h"
> #include "clang/Basic/Diagnostic.h"
>
> Modified: cfe/trunk/test/CodeGen/builtins.c
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/builtins.c?rev=345971&r1=345970&r2=345971&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/CodeGen/builtins.c (original)
> +++ cfe/trunk/test/CodeGen/builtins.c Fri Nov 2 06:14:11 2018
> @@ -729,25 +729,28 @@ void test_builtin_os_log_merge_helper1(v
>
> // CHECK-LABEL: define void @test_builtin_os_log_errno
> void test_builtin_os_log_errno() {
> - // CHECK: %[[VLA:.*]] = alloca i8, i64 4, align 16
> - // CHECK: call void @__os_log_helper_16_2_1_0_96(i8* %[[VLA]])
> + // CHECK-NOT: @stacksave
> + // CHECK: %[[BUF:.*]] = alloca [4 x i8], align 1
> + // CHECK: %[[DECAY:.*]] = getelementptr inbounds [4 x i8], [4 x i8]*
> %[[BUF]], i32 0, i32 0
> + // CHECK: call void @__os_log_helper_1_2_1_0_96(i8* %[[DECAY]])
> + // CHECK-NOT: @stackrestore
>
> char buf[__builtin_os_log_format_buffer_size("%m")];
> __builtin_os_log_format(buf, "%m");
> }
>
> -// CHECK-LABEL: define linkonce_odr hidden void
> @__os_log_helper_16_2_1_0_96
> +// CHECK-LABEL: define linkonce_odr hidden void
> @__os_log_helper_1_2_1_0_96
> // CHECK: (i8* %[[BUFFER:.*]])
>
> // CHECK: %[[BUFFER_ADDR:.*]] = alloca i8*, align 8
> // CHECK: store i8* %[[BUFFER]], i8** %[[BUFFER_ADDR]], align 8
> // CHECK: %[[BUF:.*]] = load i8*, i8** %[[BUFFER_ADDR]], align 8
> // CHECK: %[[SUMMARY:.*]] = getelementptr i8, i8* %[[BUF]], i64 0
> -// CHECK: store i8 2, i8* %[[SUMMARY]], align 16
> +// CHECK: store i8 2, i8* %[[SUMMARY]], align 1
> // CHECK: %[[NUMARGS:.*]] = getelementptr i8, i8* %[[BUF]], i64 1
> // CHECK: store i8 1, i8* %[[NUMARGS]], align 1
> // CHECK: %[[ARGDESCRIPTOR:.*]] = getelementptr i8, i8* %[[BUF]], i64 2
> -// CHECK: store i8 96, i8* %[[ARGDESCRIPTOR]], align 2
> +// CHECK: store i8 96, i8* %[[ARGDESCRIPTOR]], align 1
> // CHECK: %[[ARGSIZE:.*]] = getelementptr i8, i8* %[[BUF]], i64 3
> // CHECK: store i8 0, i8* %[[ARGSIZE]], align 1
> // CHECK-NEXT: ret void
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20181102/046e3a84/attachment-0001.html>
More information about the cfe-commits
mailing list