diff options
Diffstat (limited to 'clang-plugin')
-rw-r--r-- | clang-plugin/CMakeLists.txt | 2 | ||||
-rw-r--r-- | clang-plugin/plugin.cc | 75 | ||||
-rw-r--r-- | clang-plugin/printf_check.cc | 114 | ||||
-rw-r--r-- | clang-plugin/printf_check.h | 47 |
4 files changed, 167 insertions, 71 deletions
diff --git a/clang-plugin/CMakeLists.txt b/clang-plugin/CMakeLists.txt index 02ffdc173..eae764235 100644 --- a/clang-plugin/CMakeLists.txt +++ b/clang-plugin/CMakeLists.txt @@ -8,7 +8,7 @@ IF (ENABLE_CLANG_PLUGIN MATCHES "ON") ENABLE_LANGUAGE(CXX) FIND_PACKAGE(LLVM REQUIRED) - SET(CLANGPLUGINSRC plugin.cc) + SET(CLANGPLUGINSRC plugin.cc printf_check.cc) ADD_LIBRARY(rspamd-clang SHARED ${CLANGPLUGINSRC}) SET_TARGET_PROPERTIES(rspamd-clang PROPERTIES diff --git a/clang-plugin/plugin.cc b/clang-plugin/plugin.cc index 1d80ba231..324e5169b 100644 --- a/clang-plugin/plugin.cc +++ b/clang-plugin/plugin.cc @@ -26,17 +26,16 @@ #include "clang/Frontend/FrontendPluginRegistry.h" #include "clang/AST/AST.h" -#include "clang/AST/Expr.h" #include "clang/AST/ASTConsumer.h" -#include "clang/AST/RecursiveASTVisitor.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Sema/Sema.h" #include "llvm/Support/raw_ostream.h" -#include <unordered_map> +#include "printf_check.h" + using namespace clang; -namespace { +namespace rspamd { class RspamdASTConsumer : public ASTConsumer { CompilerInstance &Instance; @@ -49,71 +48,7 @@ namespace { void HandleTranslationUnit (ASTContext &context) override { - struct Visitor : public RecursiveASTVisitor<Visitor> { - std::unordered_map<std::string, int> printf_functions; - ASTContext *pcontext; - - Visitor (void) - { - /* name -> format string position */ - printf_functions = { - {"rspamd_printf", 0}, - {"rspamd_default_log_function", 4}, - {"rspamd_snprintf", 2}, - {"rspamd_fprintf", 1} - }; - }; - - bool VisitCallExpr (CallExpr *E) - { - auto callee = dyn_cast<NamedDecl> (E->getCalleeDecl ()); - if (callee == NULL) { - llvm::errs () << "Bad callee\n"; - return false; - } - - auto fname = callee->getNameAsString (); - - auto pos_it = printf_functions.find (fname); - - if (pos_it != printf_functions.end ()) { - const auto args = E->getArgs (); - auto pos = pos_it->second; - auto query = args[pos]; - - if (!query->isEvaluatable(*pcontext)) { - llvm::errs () << "Cannot evaluate query\n"; - return false; - } - - clang::Expr::EvalResult r; - - if (!query->EvaluateAsRValue (r, *pcontext)) { - llvm::errs () << "Cannot evaluate query\n"; - return false; - } - - auto qval = dyn_cast<StringLiteral> ( - r.Val.getLValueBase ().get<const Expr *> ()); - if (qval) { - llvm::errs () << "query string: " - << qval->getString () << "\n"; - } - - for (auto i = pos + 1; i < E->getNumArgs (); i ++) { - auto arg = args[i]; - - if (arg) { - arg->dump (); - } - } - } - - return true; - } - - } v; - v.pcontext = &context; + rspamd::PrintfCheckVisitor v(&context); v.TraverseDecl (context.getTranslationUnitDecl ()); } }; @@ -141,5 +76,5 @@ namespace { } -static FrontendPluginRegistry::Add <RspamdASTAction> +static FrontendPluginRegistry::Add <rspamd::RspamdASTAction> X ("rspamd-ast", "rspamd ast checker"); diff --git a/clang-plugin/printf_check.cc b/clang-plugin/printf_check.cc new file mode 100644 index 000000000..4c0e8edd8 --- /dev/null +++ b/clang-plugin/printf_check.cc @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2015, Vsevolod Stakhov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "printf_check.h" +#include "clang/AST/AST.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include <unordered_map> + +using namespace clang; + +namespace rspamd { + class PrintfCheckVisitor::impl { + std::unordered_map<std::string, int> printf_functions; + ASTContext *pcontext; + + public: + impl (ASTContext *_ctx) : pcontext(_ctx) + { + /* name -> format string position */ + printf_functions = { + {"rspamd_printf", 0}, + {"rspamd_default_log_function", 4}, + {"rspamd_snprintf", 2}, + {"rspamd_fprintf", 1} + }; + }; + + bool VisitCallExpr (CallExpr *E) + { + auto callee = dyn_cast<NamedDecl> (E->getCalleeDecl ()); + if (callee == NULL) { + llvm::errs () << "Bad callee\n"; + return false; + } + + auto fname = callee->getNameAsString (); + + auto pos_it = printf_functions.find (fname); + + if (pos_it != printf_functions.end ()) { + const auto args = E->getArgs (); + auto pos = pos_it->second; + auto query = args[pos]; + + if (!query->isEvaluatable (*pcontext)) { + llvm::errs () << "Cannot evaluate query\n"; + return false; + } + + clang::Expr::EvalResult r; + + if (!query->EvaluateAsRValue (r, *pcontext)) { + llvm::errs () << "Cannot evaluate query\n"; + return false; + } + + auto qval = dyn_cast<StringLiteral> ( + r.Val.getLValueBase ().get<const Expr *> ()); + if (qval) { + llvm::errs () << "query string: " + << qval->getString () << "\n"; + } + + for (auto i = pos + 1; i < E->getNumArgs (); i++) { + auto arg = args[i]; + + if (arg) { + auto type = arg->getType ().split ().Ty; + type->dump (); + } + } + } + + return true; + } + }; + + PrintfCheckVisitor::PrintfCheckVisitor (ASTContext *ctx) : + pimpl { new impl(ctx) } + { + } + + PrintfCheckVisitor::~PrintfCheckVisitor () + { + } + + bool PrintfCheckVisitor::VisitCallExpr (clang::CallExpr *E) + { + return pimpl->VisitCallExpr (E); + } +}; diff --git a/clang-plugin/printf_check.h b/clang-plugin/printf_check.h new file mode 100644 index 000000000..13e1ca86c --- /dev/null +++ b/clang-plugin/printf_check.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, Vsevolod Stakhov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RSPAMD_PRINTF_CHECK_H +#define RSPAMD_PRINTF_CHECK_H + +#include <memory> +#include "clang/AST/AST.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/Expr.h" + +namespace rspamd { + + class PrintfCheckVisitor : public clang::RecursiveASTVisitor<PrintfCheckVisitor> { + class impl; + std::unique_ptr<impl> pimpl; + + public: + PrintfCheckVisitor (clang::ASTContext *ctx); + virtual ~PrintfCheckVisitor (void); + bool VisitCallExpr (clang::CallExpr *E); + }; + +} + +#endif |