aboutsummaryrefslogtreecommitdiffstats
path: root/clang-plugin/printf_check.cc
diff options
context:
space:
mode:
Diffstat (limited to 'clang-plugin/printf_check.cc')
-rw-r--r--clang-plugin/printf_check.cc214
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;
+ }
};