OSLog.cpp 7.7 KB

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