summaryrefslogtreecommitdiff
path: root/compilerplugins/clang
diff options
context:
space:
mode:
authorNoel Grandin <noel.grandin@collabora.co.uk>2019-03-11 11:06:57 +0200
committerNoel Grandin <noel.grandin@collabora.co.uk>2019-03-25 07:19:13 +0100
commitb1cfdb7bee4f7af97af54e6abbc5d04aed4ba082 (patch)
tree8211ea564e36152b9eeb7be7212342d9e82800c6 /compilerplugins/clang
parent26b81b23f0ad061b6d44fcea3e07ae4b18a63f94 (diff)
new loplugin:unoquery
look for places we are doing code like: Reference<XProperty>(model, css::uno::UNO_QUERY)->getAsProperty() which might result in a SIGSEGV is the query fails Change-Id: I5cbdbc9e64bd0bed588297c512bf60cbacb9442e Reviewed-on: https://gerrit.libreoffice.org/69044 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Diffstat (limited to 'compilerplugins/clang')
-rw-r--r--compilerplugins/clang/test/unoquery.cxx19
-rw-r--r--compilerplugins/clang/unoquery.cxx87
2 files changed, 106 insertions, 0 deletions
diff --git a/compilerplugins/clang/test/unoquery.cxx b/compilerplugins/clang/test/unoquery.cxx
new file mode 100644
index 000000000000..a80786a176c3
--- /dev/null
+++ b/compilerplugins/clang/test/unoquery.cxx
@@ -0,0 +1,19 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "sal/config.h"
+#include "com/sun/star/beans/XProperty.hpp"
+
+void foo(css::uno::Reference<css::uno::XInterface> model)
+{
+ css::uno::Reference<css::beans::XProperty>(model, css::uno::UNO_QUERY)->getAsProperty();
+ // expected-error@-1 {{calling UNO_QUERY followed by unconditional method call might result in SIGSEGV, rather use UNO_QUERY_THROW [loplugin:unoquery]}}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/compilerplugins/clang/unoquery.cxx b/compilerplugins/clang/unoquery.cxx
new file mode 100644
index 000000000000..ad9d2aada4e9
--- /dev/null
+++ b/compilerplugins/clang/unoquery.cxx
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "check.hxx"
+#include "plugin.hxx"
+
+// TODO it would be better if we were running some kind of nullability analysis here, where we marked
+// the results of expressions like Reference(..UNO_QUERY) as being nullable, and then looked for
+// places where we unconditionally deference the results of that expression.
+
+namespace
+{
+class UnoQuery : public loplugin::FilteringPlugin<UnoQuery>
+{
+public:
+ explicit UnoQuery(loplugin::InstantiationData const& data)
+ : FilteringPlugin(data)
+ {
+ }
+
+ void run() override { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); }
+ bool VisitCXXMemberCallExpr(CXXMemberCallExpr const*);
+};
+
+bool UnoQuery::VisitCXXMemberCallExpr(CXXMemberCallExpr const* memberCallExpr)
+{
+ if (ignoreLocation(memberCallExpr))
+ return true;
+
+ memberCallExpr->dump();
+
+ auto isXInterface = [](Decl const* decl) -> bool {
+ return bool(loplugin::DeclCheck(decl)
+ .Class("XInterface")
+ .Namespace("uno")
+ .Namespace("star")
+ .Namespace("sun")
+ .Namespace("com")
+ .GlobalNamespace());
+ };
+ if (!loplugin::isDerivedFrom(memberCallExpr->getRecordDecl(), isXInterface))
+ return true;
+ auto operatorCallExpr = dyn_cast<CXXOperatorCallExpr>(
+ memberCallExpr->getImplicitObjectArgument()->IgnoreImplicit());
+ if (!operatorCallExpr)
+ return true;
+
+ Expr const* expr = operatorCallExpr->getArg(0)->IgnoreImplicit();
+ // depending on the version of clang, the IgnoreImplicit may or may not look through these nodes
+ if (auto matTemp = dyn_cast<MaterializeTemporaryExpr>(expr))
+ expr = matTemp->GetTemporaryExpr();
+ if (auto bindTemp = dyn_cast<CXXBindTemporaryExpr>(expr))
+ expr = bindTemp->getSubExpr();
+
+ auto temporaryExpr = dyn_cast<CXXTemporaryObjectExpr>(expr);
+ if (!temporaryExpr)
+ return true;
+ if (temporaryExpr->getNumArgs() < 2)
+ return true;
+ auto declRefExpr = dyn_cast<DeclRefExpr>(temporaryExpr->getArg(1)->IgnoreImplicit());
+ if (!declRefExpr)
+ return true;
+ auto enumConstant = dyn_cast<EnumConstantDecl>(declRefExpr->getDecl());
+ if (!enumConstant)
+ return true;
+ if (enumConstant->getName() != "UNO_QUERY")
+ return true;
+
+ report(DiagnosticsEngine::Warning,
+ "calling UNO_QUERY followed by unconditional method call might result in SIGSEGV, "
+ "rather use UNO_QUERY_THROW",
+ memberCallExpr->getExprLoc())
+ << memberCallExpr->getSourceRange();
+
+ return true;
+}
+
+loplugin::Plugin::Registration<UnoQuery> unoquery("unoquery", true);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */