From 2c2d43580f7cfc06e8551b88de783eeec70fb6df Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Thu, 14 Feb 2019 13:12:06 -0600 Subject: [PATCH] lac/linear_operator.h: Prevent users from creating LinearOperators with temoporaries --- include/deal.II/lac/linear_operator.h | 119 ++++++++++++++++++++++++++ tests/lac/linear_operator_18.cc | 55 ++++++++++++ tests/lac/linear_operator_18.output | 6 ++ 3 files changed, 180 insertions(+) create mode 100644 tests/lac/linear_operator_18.cc create mode 100644 tests/lac/linear_operator_18.output diff --git a/include/deal.II/lac/linear_operator.h b/include/deal.II/lac/linear_operator.h index f0115ff257..64dff9a099 100644 --- a/include/deal.II/lac/linear_operator.h +++ b/include/deal.II/lac/linear_operator.h @@ -1473,6 +1473,125 @@ linear_operator(const LinearOperator &operator_exemplar, //@} +#ifndef DOXYGEN + +// +// Ensure that we never capture a reference to a temporary by accident. +// This ensures that instead of silently allowing a "stack use after free", +// we at least bail out with a runtime error message that is slightly more +// understandable. +// + +template < + typename Range = Vector, + typename Domain = Range, + typename Payload = internal::LinearOperatorImplementation::EmptyPayload, + typename OperatorExemplar, + typename Matrix, + typename = + typename std::enable_if::value>::type> +LinearOperator +linear_operator(const OperatorExemplar &, Matrix &&) +{ + Assert(false, + ExcMessage( + "You are trying to construct a linear operator from a temporary " + "matrix object.")); +} + +template < + typename Range = Vector, + typename Domain = Range, + typename Payload = internal::LinearOperatorImplementation::EmptyPayload, + typename OperatorExemplar, + typename Matrix, + typename = typename std::enable_if< + !std::is_lvalue_reference::value>::type> +LinearOperator +linear_operator(OperatorExemplar &&, const Matrix &) +{ + Assert(false, + ExcMessage( + "You are trying to construct a linear operator with a temporary " + "operator_exemplar object.")); +} + +template < + typename Range = Vector, + typename Domain = Range, + typename Payload = internal::LinearOperatorImplementation::EmptyPayload, + typename OperatorExemplar, + typename Matrix, + typename = + typename std::enable_if::value>::type, + typename = typename std::enable_if< + !std::is_lvalue_reference::value>::type> +LinearOperator +linear_operator(OperatorExemplar &&, Matrix &&) +{ + Assert(false, + ExcMessage( + "You are trying to construct a linear operator from a temporary " + "matrix object.")); +} + + +template < + typename Range = Vector, + typename Domain = Range, + typename Payload = internal::LinearOperatorImplementation::EmptyPayload, + typename Matrix, + typename = + typename std::enable_if::value>::type> +LinearOperator +linear_operator(const LinearOperator &, Matrix &&) +{ + Assert(false, + ExcMessage( + "You are trying to construct a linear operator from a temporary " + "matrix object.")); +} + +template < + typename Range = Vector, + typename Domain = Range, + typename Payload = internal::LinearOperatorImplementation::EmptyPayload, + typename Matrix, + typename = + typename std::enable_if::value>::type> +LinearOperator +linear_operator(Matrix &&) +{ + Assert(false, + ExcMessage( + "You are trying to construct a linear operator from a temporary " + "matrix object.")); +} + +template ::value>::type, + typename = typename std::enable_if< + !std::is_same::value>::type, + typename = typename std::enable_if< + !std::is_same>::value>::type> +LinearOperator +inverse_operator(const LinearOperator &, + Solver &, + Preconditioner &&) +{ + Assert(false, + ExcMessage( + "You are trying to construct an inverse operator with a temporary " + "preconditioner object.")); +} + +#endif // DOXYGEN DEAL_II_NAMESPACE_CLOSE diff --git a/tests/lac/linear_operator_18.cc b/tests/lac/linear_operator_18.cc new file mode 100644 index 0000000000..08fbfb1801 --- /dev/null +++ b/tests/lac/linear_operator_18.cc @@ -0,0 +1,55 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2015 - 2018 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE.md at +// the top level directory of deal.II. +// +// --------------------------------------------------------------------- + +// Test that we cannot accidentally create a linear operator from a +// temporary object + +#include +#include +#include + +#include "../tests.h" + +#define CATCH(call) \ + try \ + { \ + call; \ + deallog << "Error: Something went wrong!" << std::endl; \ + } \ + catch (ExceptionBase & e) \ + { \ + deallog << e.get_exc_name() << std::endl; \ + } + +using namespace dealii; + +int +main() +{ + initlog(); + deal_II_exceptions::disable_abort_on_exception(); + + SparseMatrix A; + const auto op_A = linear_operator(A); + + CATCH(linear_operator(SparseMatrix())) + CATCH(linear_operator(SparseMatrix(), A)) + CATCH(linear_operator(A, SparseMatrix())) + CATCH(linear_operator(SparseMatrix(), SparseMatrix())) + + SolverControl solver_control; + SolverCG> solver(solver_control); + CATCH(inverse_operator(op_A, solver, SparseMatrix())) +} diff --git a/tests/lac/linear_operator_18.output b/tests/lac/linear_operator_18.output new file mode 100644 index 0000000000..8aad5753bc --- /dev/null +++ b/tests/lac/linear_operator_18.output @@ -0,0 +1,6 @@ + +DEAL::ExcMessage( "You are trying to construct a linear operator from a temporary " "matrix object.") +DEAL::ExcMessage( "You are trying to construct a linear operator with a temporary " "operator_exemplar object.") +DEAL::ExcMessage( "You are trying to construct a linear operator from a temporary " "matrix object.") +DEAL::ExcMessage( "You are trying to construct a linear operator from a temporary " "matrix object.") +DEAL::ExcMessage( "You are trying to construct an inverse operator with a temporary " "preconditioner object.") -- 2.39.5