diff options
Diffstat (limited to 'clang-plugin')
-rw-r--r-- | clang-plugin/printf_check.cc | 214 |
1 files changed, 213 insertions, 1 deletions
diff --git a/clang-plugin/printf_check.cc b/clang-plugin/printf_check.cc index cd9aa1de7..a6918e425 100644 --- a/clang-plugin/printf_check.cc +++ b/clang-plugin/printf_check.cc @@ -41,6 +41,16 @@ namespace rspamd { 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); using arg_parser_t = bool (*) (const Expr *, struct PrintfArgChecker *); @@ -58,10 +68,16 @@ namespace rspamd { public: int width; int precision; + bool is_unsigned; 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) @@ -85,6 +101,23 @@ namespace rspamd { case 'd': return llvm::make_unique<PrintfArgChecker>(int_arg_handler, this->pcontext); + case 'z': + return llvm::make_unique<PrintfArgChecker> (size_arg_handler, + this->pcontext); + case 'l': + return llvm::make_unique<PrintfArgChecker> (long_arg_handler, + this->pcontext); + case 'f': + case 'g': + return llvm::make_unique<PrintfArgChecker> (double_arg_handler, + this->pcontext); + case 'F': + case 'G': + return llvm::make_unique<PrintfArgChecker> (long_double_arg_handler, + this->pcontext); + case 'c': + return llvm::make_unique<PrintfArgChecker> (char_arg_handler, + this->pcontext); default: llvm::errs () << "unknown parser flag: " << type << "\n"; break; @@ -366,4 +399,183 @@ namespace rspamd { return true; } + + static bool + long_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx) + { + auto type = arg->getType ().split ().Ty; + + auto desugared_type = type->getUnqualifiedDesugaredType (); + + if (!desugared_type->isIntegerType ()) { + print_error ( + std::string ("bad integer argument for %l arg: ") + + arg->getType ().getAsString (), arg, ctx->past); + return false; + } + else if (!desugared_type->isBuiltinType ()) { + print_error ( + std::string ("bad integer argument for %l arg: ") + + arg->getType ().getAsString (), arg, ctx->past); + return false; + } + + auto builtin_type = dyn_cast<BuiltinType> (desugared_type); + auto kind = builtin_type->getKind (); + + if (kind != BuiltinType::Kind::ULong && + kind != BuiltinType::Kind::Long) { + print_error ( + std::string ("bad integer argument for %l arg: ") + + arg->getType ().getAsString (), arg, ctx->past); + return false; + } + + return true; + } + + static bool + char_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx) + { + auto type = arg->getType ().split ().Ty; + + auto desugared_type = type->getUnqualifiedDesugaredType (); + + if (!desugared_type->isCharType ()) { + print_error ( + std::string ("bad char argument for %c arg: ") + + arg->getType ().getAsString (), arg, ctx->past); + return false; + } + else if (!desugared_type->isBuiltinType ()) { + print_error ( + std::string ("bad char argument for %c arg: ") + + arg->getType ().getAsString (), arg, ctx->past); + return false; + } + + auto builtin_type = dyn_cast<BuiltinType> (desugared_type); + auto kind = builtin_type->getKind (); + + if (kind != BuiltinType::Kind::UChar && + kind != BuiltinType::Kind::SChar) { + print_error ( + std::string ("bad char argument for %c arg: ") + + arg->getType ().getAsString (), arg, ctx->past); + return false; + } + + return true; + } + + static bool + size_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx) + { + auto type = arg->getType ().split ().Ty; + + auto desugared_type = type->getUnqualifiedDesugaredType (); + + if (!desugared_type->isIntegerType ()) { + print_error ( + std::string ("bad integer argument for %z arg: ") + + arg->getType ().getAsString (), arg, ctx->past); + return false; + } + else if (!desugared_type->isBuiltinType ()) { + print_error ( + std::string ("bad integer argument for %z arg: ") + + arg->getType ().getAsString (), arg, ctx->past); + return false; + } + + auto builtin_type = dyn_cast<BuiltinType> (desugared_type); + auto kind = builtin_type->getKind (); + + if (sizeof (size_t) == sizeof (long)) { + if (kind != BuiltinType::Kind::ULong && + kind != BuiltinType::Kind::Long) { + print_error ( + std::string ("bad integer argument for %z arg: ") + + arg->getType ().getAsString (), arg, ctx->past); + return false; + } + } + else if (sizeof (size_t) == sizeof (int)) { + if (kind != BuiltinType::Kind::UInt && + kind != BuiltinType::Kind::Int) { + print_error ( + std::string ("bad integer argument for %z arg: ") + + arg->getType ().getAsString (), arg, ctx->past); + return false; + } + } + + return true; + } + + static bool + double_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx) + { + auto type = arg->getType ().split ().Ty; + + auto desugared_type = type->getUnqualifiedDesugaredType (); + + if (!desugared_type->isRealFloatingType ()) { + print_error ( + std::string ("bad double argument for %f or %g arg: ") + + arg->getType ().getAsString (), arg, ctx->past); + return false; + } + else if (!desugared_type->isBuiltinType ()) { + print_error ( + std::string ("bad double argument for %f or %g arg: ") + + arg->getType ().getAsString (), arg, ctx->past); + return false; + } + + auto builtin_type = dyn_cast<BuiltinType> (desugared_type); + auto kind = builtin_type->getKind (); + + if (kind != BuiltinType::Kind::Double) { + print_error ( + std::string ("bad double argument for %f or %g arg: ") + + arg->getType ().getAsString (), arg, ctx->past); + return false; + } + + return true; + } + + static bool + long_double_arg_handler (const Expr *arg, struct PrintfArgChecker *ctx) + { + auto type = arg->getType ().split ().Ty; + + auto desugared_type = type->getUnqualifiedDesugaredType (); + + if (!desugared_type->isRealFloatingType ()) { + print_error ( + std::string ("bad long double argument for %F or %G arg: ") + + arg->getType ().getAsString (), arg, ctx->past); + return false; + } + else if (!desugared_type->isBuiltinType ()) { + print_error ( + std::string ("bad long double argument for %F or %G arg: ") + + arg->getType ().getAsString (), arg, ctx->past); + return false; + } + + auto builtin_type = dyn_cast<BuiltinType> (desugared_type); + auto kind = builtin_type->getKind (); + + if (kind != BuiltinType::Kind::LongDouble) { + print_error ( + std::string ("bad long double argument for %F or %G arg: ") + + arg->getType ().getAsString (), arg, ctx->past); + return false; + } + + return true; + } }; |