Home | History | Annotate | Line # | Download | only in AST
      1 // TODO: header template
      2 
      3 #include "clang/AST/OSLog.h"
      4 #include "clang/AST/Attr.h"
      5 #include "clang/AST/Decl.h"
      6 #include "clang/AST/DeclCXX.h"
      7 #include "clang/AST/ExprObjC.h"
      8 #include "clang/AST/FormatString.h"
      9 #include "clang/Basic/Builtins.h"
     10 #include "llvm/ADT/SmallBitVector.h"
     11 
     12 using namespace clang;
     13 
     14 using clang::analyze_os_log::OSLogBufferItem;
     15 using clang::analyze_os_log::OSLogBufferLayout;
     16 
     17 namespace {
     18 class OSLogFormatStringHandler
     19     : public analyze_format_string::FormatStringHandler {
     20 private:
     21   struct ArgData {
     22     const Expr *E = nullptr;
     23     Optional<OSLogBufferItem::Kind> Kind;
     24     Optional<unsigned> Size;
     25     Optional<const Expr *> Count;
     26     Optional<const Expr *> Precision;
     27     Optional<const Expr *> FieldWidth;
     28     unsigned char Flags = 0;
     29     StringRef MaskType;
     30   };
     31   SmallVector<ArgData, 4> ArgsData;
     32   ArrayRef<const Expr *> Args;
     33 
     34   OSLogBufferItem::Kind
     35   getKind(analyze_format_string::ConversionSpecifier::Kind K) {
     36     switch (K) {
     37     case clang::analyze_format_string::ConversionSpecifier::sArg: // "%s"
     38       return OSLogBufferItem::StringKind;
     39     case clang::analyze_format_string::ConversionSpecifier::SArg: // "%S"
     40       return OSLogBufferItem::WideStringKind;
     41     case clang::analyze_format_string::ConversionSpecifier::PArg: { // "%P"
     42       return OSLogBufferItem::PointerKind;
     43     case clang::analyze_format_string::ConversionSpecifier::ObjCObjArg: // "%@"
     44       return OSLogBufferItem::ObjCObjKind;
     45     case clang::analyze_format_string::ConversionSpecifier::PrintErrno: // "%m"
     46       return OSLogBufferItem::ErrnoKind;
     47     default:
     48       return OSLogBufferItem::ScalarKind;
     49     }
     50     }
     51   }
     52 
     53 public:
     54   OSLogFormatStringHandler(ArrayRef<const Expr *> Args) : Args(Args) {
     55     ArgsData.reserve(Args.size());
     56   }
     57 
     58   bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
     59                              const char *StartSpecifier,
     60                              unsigned SpecifierLen) override {
     61     if (!FS.consumesDataArgument() &&
     62         FS.getConversionSpecifier().getKind() !=
     63             clang::analyze_format_string::ConversionSpecifier::PrintErrno)
     64       return true;
     65 
     66     ArgsData.emplace_back();
     67     unsigned ArgIndex = FS.getArgIndex();
     68     if (ArgIndex < Args.size())
     69       ArgsData.back().E = Args[ArgIndex];
     70 
     71     // First get the Kind
     72     ArgsData.back().Kind = getKind(FS.getConversionSpecifier().getKind());
     73     if (ArgsData.back().Kind != OSLogBufferItem::ErrnoKind &&
     74         !ArgsData.back().E) {
     75       // missing argument
     76       ArgsData.pop_back();
     77       return false;
     78     }
     79 
     80     switch (FS.getConversionSpecifier().getKind()) {
     81     case clang::analyze_format_string::ConversionSpecifier::sArg:   // "%s"
     82     case clang::analyze_format_string::ConversionSpecifier::SArg: { // "%S"
     83       auto &precision = FS.getPrecision();
     84       switch (precision.getHowSpecified()) {
     85       case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%s"
     86         break;
     87       case clang::analyze_format_string::OptionalAmount::Constant: // "%.16s"
     88         ArgsData.back().Size = precision.getConstantAmount();
     89         break;
     90       case clang::analyze_format_string::OptionalAmount::Arg: // "%.*s"
     91         ArgsData.back().Count = Args[precision.getArgIndex()];
     92         break;
     93       case clang::analyze_format_string::OptionalAmount::Invalid:
     94         return false;
     95       }
     96       break;
     97     }
     98     case clang::analyze_format_string::ConversionSpecifier::PArg: { // "%P"
     99       auto &precision = FS.getPrecision();
    100       switch (precision.getHowSpecified()) {
    101       case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%P"
    102         return false; // length must be supplied with pointer format specifier
    103       case clang::analyze_format_string::OptionalAmount::Constant: // "%.16P"
    104         ArgsData.back().Size = precision.getConstantAmount();
    105         break;
    106       case clang::analyze_format_string::OptionalAmount::Arg: // "%.*P"
    107         ArgsData.back().Count = Args[precision.getArgIndex()];
    108         break;
    109       case clang::analyze_format_string::OptionalAmount::Invalid:
    110         return false;
    111       }
    112       break;
    113     }
    114     default:
    115       if (FS.getPrecision().hasDataArgument()) {
    116         ArgsData.back().Precision = Args[FS.getPrecision().getArgIndex()];
    117       }
    118       break;
    119     }
    120     if (FS.getFieldWidth().hasDataArgument()) {
    121       ArgsData.back().FieldWidth = Args[FS.getFieldWidth().getArgIndex()];
    122     }
    123 
    124     if (FS.isSensitive())
    125       ArgsData.back().Flags |= OSLogBufferItem::IsSensitive;
    126     else if (FS.isPrivate())
    127       ArgsData.back().Flags |= OSLogBufferItem::IsPrivate;
    128     else if (FS.isPublic())
    129       ArgsData.back().Flags |= OSLogBufferItem::IsPublic;
    130 
    131     ArgsData.back().MaskType = FS.getMaskType();
    132     return true;
    133   }
    134 
    135   void computeLayout(ASTContext &Ctx, OSLogBufferLayout &Layout) const {
    136     Layout.Items.clear();
    137     for (auto &Data : ArgsData) {
    138       if (!Data.MaskType.empty()) {
    139         CharUnits Size = CharUnits::fromQuantity(8);
    140         Layout.Items.emplace_back(OSLogBufferItem::MaskKind, nullptr,
    141                                   Size, 0, Data.MaskType);
    142       }
    143 
    144       if (Data.FieldWidth) {
    145         CharUnits Size = Ctx.getTypeSizeInChars((*Data.FieldWidth)->getType());
    146         Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.FieldWidth,
    147                                   Size, 0);
    148       }
    149       if (Data.Precision) {
    150         CharUnits Size = Ctx.getTypeSizeInChars((*Data.Precision)->getType());
    151         Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.Precision,
    152                                   Size, 0);
    153       }
    154       if (Data.Count) {
    155         // "%.*P" has an extra "count" that we insert before the argument.
    156         CharUnits Size = Ctx.getTypeSizeInChars((*Data.Count)->getType());
    157         Layout.Items.emplace_back(OSLogBufferItem::CountKind, *Data.Count, Size,
    158                                   0);
    159       }
    160       if (Data.Size)
    161         Layout.Items.emplace_back(Ctx, CharUnits::fromQuantity(*Data.Size),
    162                                   Data.Flags);
    163       if (Data.Kind) {
    164         CharUnits Size;
    165         if (*Data.Kind == OSLogBufferItem::ErrnoKind)
    166           Size = CharUnits::Zero();
    167         else
    168           Size = Ctx.getTypeSizeInChars(Data.E->getType());
    169         Layout.Items.emplace_back(*Data.Kind, Data.E, Size, Data.Flags);
    170       } else {
    171         auto Size = Ctx.getTypeSizeInChars(Data.E->getType());
    172         Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, Data.E, Size,
    173                                   Data.Flags);
    174       }
    175     }
    176   }
    177 };
    178 } // end anonymous namespace
    179 
    180 bool clang::analyze_os_log::computeOSLogBufferLayout(
    181     ASTContext &Ctx, const CallExpr *E, OSLogBufferLayout &Layout) {
    182   ArrayRef<const Expr *> Args(E->getArgs(), E->getArgs() + E->getNumArgs());
    183 
    184   const Expr *StringArg;
    185   ArrayRef<const Expr *> VarArgs;
    186   switch (E->getBuiltinCallee()) {
    187   case Builtin::BI__builtin_os_log_format_buffer_size:
    188     assert(E->getNumArgs() >= 1 &&
    189            "__builtin_os_log_format_buffer_size takes at least 1 argument");
    190     StringArg = E->getArg(0);
    191     VarArgs = Args.slice(1);
    192     break;
    193   case Builtin::BI__builtin_os_log_format:
    194     assert(E->getNumArgs() >= 2 &&
    195            "__builtin_os_log_format takes at least 2 arguments");
    196     StringArg = E->getArg(1);
    197     VarArgs = Args.slice(2);
    198     break;
    199   default:
    200     llvm_unreachable("non-os_log builtin passed to computeOSLogBufferLayout");
    201   }
    202 
    203   const StringLiteral *Lit = cast<StringLiteral>(StringArg->IgnoreParenCasts());
    204   assert(Lit && (Lit->isAscii() || Lit->isUTF8()));
    205   StringRef Data = Lit->getString();
    206   OSLogFormatStringHandler H(VarArgs);
    207   ParsePrintfString(H, Data.begin(), Data.end(), Ctx.getLangOpts(),
    208                     Ctx.getTargetInfo(), /*isFreeBSDKPrintf*/ false);
    209 
    210   H.computeLayout(Ctx, Layout);
    211   return true;
    212 }
    213