OSLog.cpp 7.6 KB

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