r345971 - Reapply Logging: make os_log buffer size an integer constant expression.
Tim Northover via cfe-commits
cfe-commits at lists.llvm.org
Fri Nov 2 06:14:11 PDT 2018
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
More information about the cfe-commits
mailing list