From 8f3f025a96d337e46c11dfd8ffe22cbf27a3ee85 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Wed, 11 Nov 2015 15:25:24 +0000 Subject: [PATCH] Add complex types checkers. --- clang-plugin/printf_check.cc | 161 ++++++++++++++++++++++++++++++----- 1 file changed, 139 insertions(+), 22 deletions(-) diff --git a/clang-plugin/printf_check.cc b/clang-plugin/printf_check.cc index 7f20bdaac..d4d00fab4 100644 --- a/clang-plugin/printf_check.cc +++ b/clang-plugin/printf_check.cc @@ -43,25 +43,46 @@ namespace rspamd { static bool cstring_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx); + static bool int_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx); + static bool long_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx); + static bool size_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx); + static bool char_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx); + static bool double_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx); + static bool long_double_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx); + static bool pointer_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx); + static bool pid_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx); + static bool int64_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx); + static bool tok_arg_handler (const Expr *arg, + struct PrintfArgChecker *ctx); + + static bool fstring_arg_handler (const Expr *arg, + struct PrintfArgChecker *ctx); + + static bool gstring_arg_handler (const Expr *arg, + struct PrintfArgChecker *ctx); + + static bool gerr_arg_handler (const Expr *arg, + struct PrintfArgChecker *ctx); + using arg_parser_t = bool (*) (const Expr *, struct PrintfArgChecker *); static void @@ -69,7 +90,7 @@ namespace rspamd { { auto const &sm = ast->getSourceManager (); auto loc = e->getExprLoc (); - llvm::errs() << err << " at " << loc.printToString (sm) << "\n"; + llvm::errs () << err << " at " << loc.printToString (sm) << "\n"; } struct PrintfArgChecker { @@ -82,15 +103,18 @@ namespace rspamd { ASTContext *past; PrintfArgChecker (arg_parser_t _p, ASTContext *_ast) : - parser(_p), past(_ast) + parser (_p), past (_ast) { width = 0; precision = 0; is_unsigned = false; } - virtual ~PrintfArgChecker () {} - bool operator () (const Expr *e) + virtual ~PrintfArgChecker () + { + } + + bool operator() (const Expr *e) { return parser (e, this); } @@ -100,16 +124,16 @@ namespace rspamd { std::unordered_map printf_functions; ASTContext *pcontext; - std::unique_ptr parseFlags (const std::string &flags) + std::unique_ptr parseFlags (const std::string &flags) { - auto type = flags.back(); + auto type = flags.back (); switch (type) { case 's': - return llvm::make_unique(cstring_arg_handler, + return llvm::make_unique (cstring_arg_handler, this->pcontext); case 'd': - return llvm::make_unique(int_arg_handler, + return llvm::make_unique (int_arg_handler, this->pcontext); case 'z': return llvm::make_unique (size_arg_handler, @@ -123,7 +147,8 @@ namespace rspamd { this->pcontext); case 'F': case 'G': - return llvm::make_unique (long_double_arg_handler, + return llvm::make_unique ( + long_double_arg_handler, this->pcontext); case 'c': return llvm::make_unique (char_arg_handler, @@ -137,6 +162,18 @@ namespace rspamd { case 'L': return llvm::make_unique (int64_arg_handler, this->pcontext); + case 'T': + return llvm::make_unique (tok_arg_handler, + this->pcontext); + case 'V': + return llvm::make_unique (fstring_arg_handler, + this->pcontext); + case 'v': + return llvm::make_unique (gstring_arg_handler, + this->pcontext); + case 'e': + return llvm::make_unique (gerr_arg_handler, + this->pcontext); default: llvm::errs () << "unknown parser flag: " << type << "\n"; break; @@ -145,7 +182,7 @@ namespace rspamd { return nullptr; } - std::shared_ptr > + std::shared_ptr > genParsers (const StringRef query) { enum { @@ -158,7 +195,7 @@ namespace rspamd { int width, precision; std::string flags; - auto res = std::make_shared >(); + auto res = std::make_shared < std::vector < PrintfArgChecker > > (); for (const auto c : query) { switch (state) { @@ -266,8 +303,9 @@ namespace rspamd { return res; } + public: - impl (ASTContext *_ctx) : pcontext(_ctx) + impl (ASTContext *_ctx) : pcontext (_ctx) { /* name -> format string position */ printf_functions = { @@ -321,10 +359,12 @@ namespace rspamd { std::ostringstream err_buf; err_buf << "number of arguments for " << fname << " missmatches query string '" << - qval->getString().str() - << "', expected " << parsers->size () << " args" - << ", got " << (E->getNumArgs () - (pos + 1)) - << " args"; + qval->getString ().str () + << "', expected " << parsers->size () << + " args" + << ", got " << + (E->getNumArgs () - (pos + 1)) + << " args"; print_error (err_buf.str (), E, this->pcontext); return false; @@ -334,7 +374,7 @@ namespace rspamd { auto arg = args[i]; if (arg) { - if (!parsers->at(i - (pos + 1))(arg)) { + if (!parsers->at (i - (pos + 1)) (arg)) { return false; } } @@ -348,7 +388,7 @@ namespace rspamd { }; PrintfCheckVisitor::PrintfCheckVisitor (ASTContext *ctx) : - pimpl { new impl(ctx) } + pimpl{new impl (ctx)} { } @@ -374,7 +414,7 @@ namespace rspamd { return false; } - auto ptr_type = type->getPointeeType().split().Ty; + auto ptr_type = type->getPointeeType ().split ().Ty; if (!ptr_type->isCharType ()) { /* We might have gchar * here */ @@ -396,7 +436,7 @@ namespace rspamd { static bool check_builtin_type (const Expr *arg, struct PrintfArgChecker *ctx, - const std::vector &k, const std::string &fmt) + const std::vector &k, const std::string &fmt) { auto type = arg->getType ().split ().Ty; @@ -433,8 +473,11 @@ namespace rspamd { static bool int_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx) { - return check_builtin_type (arg, ctx, {BuiltinType::Kind::UInt, - BuiltinType::Kind::Int}, "%d or *"); + return check_builtin_type (arg, + ctx, + {BuiltinType::Kind::UInt, + BuiltinType::Kind::Int}, + "%d or *"); } static bool @@ -498,6 +541,7 @@ namespace rspamd { {BuiltinType::Kind::LongDouble}, "%F or %G"); } + static bool pid_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx) { @@ -558,4 +602,77 @@ namespace rspamd { return true; } + + static bool + check_struct_type (const Expr *arg, struct PrintfArgChecker *ctx, + const std::string &sname, const std::string &fmt) + { + auto type = arg->getType ().split ().Ty; + + if (!type->isPointerType ()) { + print_error ( + std::string ("bad string argument for %s: ") + + arg->getType ().getAsString (), arg, ctx->past); + return false; + } + + auto ptr_type = type->getPointeeType ().split ().Ty; + auto desugared_type = ptr_type->getUnqualifiedDesugaredType (); + + if (!desugared_type->isRecordType ()) { + print_error ( + std::string ("not a record type for ") + fmt + " arg: " + + arg->getType ().getAsString (), arg, ctx->past); + return false; + } + + auto struct_type = desugared_type->getAsStructureType (); + auto struct_decl = struct_type->getDecl (); + auto struct_def = struct_decl->getNameAsString (); + + if (struct_def != sname) { + print_error (std::string ("bad argument '") + struct_def + "' for " + + fmt + " arg: " + + arg->getType ().getAsString (), arg, ctx->past); + return false; + } + + return true; + } + + static bool + tok_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx) + { + return check_struct_type (arg, + ctx, + "f_str_tok", + "%T"); + } + + static bool + fstring_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx) + { + return check_struct_type (arg, + ctx, + "f_str_s", + "%V"); + } + + static bool + gstring_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx) + { + return check_struct_type (arg, + ctx, + "_GString", + "%v"); + } + + static bool + gerr_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx) + { + return check_struct_type (arg, + ctx, + "_GError", + "%e"); + } }; -- 2.39.5