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