OSLog.cpp 7.3 KB

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