Skip to content

Commit

Permalink
Prevent default-construction of function pointers.
Browse files Browse the repository at this point in the history
Default- and value-constructed pointers to functions are not callable,
and therefore are not accepted as default-constructible condition
function objects and deleters.

Closes #14.
  • Loading branch information
Lastique committed Dec 17, 2023
1 parent ad4005f commit 80d26d6
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 7 deletions.
66 changes: 66 additions & 0 deletions include/boost/scope/detail/is_nonnull_default_constructible.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* https://www.boost.org/LICENSE_1_0.txt)
*
* Copyright (c) 2023 Andrey Semashev
*/
/*!
* \file scope/detail/is_nonnull_default_constructible.hpp
*
* This header contains definition of \c is_nonnull_default_constructible
* and \c is_nothrow_nonnull_default_constructible type traits. The type
* traits are useful for preventing default-construction of pointers to
* functions where a default-constructed function object is expected.
* Without it, default- or value-constructing a pointer to function would
* produce a function object that is not callable.
*/

#ifndef BOOST_SCOPE_DETAIL_IS_NONNULL_DEFAULT_CONSTRUCTIBLE_HPP_INCLUDED_
#define BOOST_SCOPE_DETAIL_IS_NONNULL_DEFAULT_CONSTRUCTIBLE_HPP_INCLUDED_

#include <type_traits>
#include <boost/scope/detail/config.hpp>
#include <boost/scope/detail/header.hpp>

#ifdef BOOST_HAS_PRAGMA_ONCE
#pragma once
#endif

namespace boost {
namespace scope {
namespace detail {

//! The type trait checks if \c T is not a pointer and is default-constructible
template< typename T >
struct is_nonnull_default_constructible :
public std::is_default_constructible< T >
{
};

template< typename T >
struct is_nonnull_default_constructible< T* > :
public std::false_type
{
};

//! The type trait checks if \c T is not a pointer and is nothrow-default-constructible
template< typename T >
struct is_nothrow_nonnull_default_constructible :
public std::is_nothrow_default_constructible< T >
{
};

template< typename T >
struct is_nothrow_nonnull_default_constructible< T* > :
public std::false_type
{
};

} // namespace detail
} // namespace scope
} // namespace boost

#include <boost/scope/detail/footer.hpp>

#endif // BOOST_SCOPE_DETAIL_IS_NONNULL_DEFAULT_CONSTRUCTIBLE_HPP_INCLUDED_
6 changes: 4 additions & 2 deletions include/boost/scope/scope_exit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <boost/scope/detail/is_not_like.hpp>
#include <boost/scope/detail/compact_storage.hpp>
#include <boost/scope/detail/move_or_copy_construct_ref.hpp>
#include <boost/scope/detail/is_nonnull_default_constructible.hpp>
#include <boost/scope/detail/type_traits/conjunction.hpp>
#include <boost/scope/detail/type_traits/is_invocable.hpp>
#include <boost/scope/detail/type_traits/is_nothrow_invocable.hpp>
Expand Down Expand Up @@ -275,7 +276,8 @@ class scope_exit
/*!
* \brief Constructs a scope guard with a given callable action function object.
*
* **Requires:** \c Func is constructible from \a func. \c Cond is nothrow default-constructible.
* **Requires:** \c Func is constructible from \a func. \c Cond is nothrow default-constructible
* and is not a pointer to function.
*
* \note The requirement for \c Cond default constructor to be non-throwing is to allow for
* the condition function object to be called in case if constructing either function
Expand All @@ -295,7 +297,7 @@ class scope_exit
typename F
//! \cond
, typename = typename std::enable_if< detail::conjunction<
std::is_nothrow_default_constructible< Cond >,
detail::is_nothrow_nonnull_default_constructible< Cond >,
std::is_constructible<
data,
typename detail::move_or_copy_construct_ref< F, Func >::type,
Expand Down
13 changes: 8 additions & 5 deletions include/boost/scope/unique_resource.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <boost/scope/detail/compact_storage.hpp>
#include <boost/scope/detail/move_or_copy_assign_ref.hpp>
#include <boost/scope/detail/move_or_copy_construct_ref.hpp>
#include <boost/scope/detail/is_nonnull_default_constructible.hpp>
#include <boost/scope/detail/type_traits/is_swappable.hpp>
#include <boost/scope/detail/type_traits/is_nothrow_swappable.hpp>
#include <boost/scope/detail/type_traits/is_nothrow_invocable.hpp>
Expand Down Expand Up @@ -302,10 +303,10 @@ class deleter_holder :

public:
template<
bool Requires = std::is_default_constructible< internal_deleter_type >::value,
bool Requires = detail::is_nonnull_default_constructible< internal_deleter_type >::value,
typename = typename std::enable_if< Requires >::type
>
constexpr deleter_holder() noexcept(std::is_nothrow_default_constructible< internal_deleter_type >::value) :
constexpr deleter_holder() noexcept(detail::is_nothrow_nonnull_default_constructible< internal_deleter_type >::value) :
deleter_base()
{
}
Expand Down Expand Up @@ -1064,7 +1065,8 @@ class unique_resource
/*!
* \brief Constructs an unallocated unique resource guard.
*
* **Requires:** Default \c Resource value can be constructed and \c Deleter is default-constructible.
* **Requires:** Default \c Resource value can be constructed. \c Deleter is default-constructible
* and is not a pointer to function.
*
* **Effects:** Initializes the \c Resource object with the default resource value. Default-constructs
* the \c Deleter object.
Expand Down Expand Up @@ -1126,7 +1128,8 @@ class unique_resource
/*!
* \brief Constructs a unique resource guard with the given resource and a default-constructed deleter.
*
* **Requires:** \c Resource is constructible from \a res and \c Deleter is default-constructible.
* **Requires:** \c Resource is constructible from \a res. \c Deleter is default-constructible and
* is not a pointer to function.
*
* **Effects:** Constructs the unique resource object as if by calling
* `unique_resource(std::forward< R >(res), Deleter())`.
Expand All @@ -1139,7 +1142,7 @@ class unique_resource
typename R
//! \cond
, typename = typename std::enable_if< detail::conjunction<
std::is_nothrow_default_constructible< deleter_type >,
detail::is_nothrow_nonnull_default_constructible< deleter_type >,
std::is_constructible< data, typename detail::move_or_copy_construct_ref< R, resource_type >::type, typename detail::move_or_copy_construct_ref< deleter_type >::type >,
detail::disjunction< detail::negation< std::is_reference< resource_type > >, std::is_reference< R > > // prevent binding lvalue-reference resource to an rvalue
>::value >::type
Expand Down
25 changes: 25 additions & 0 deletions test/compile_fail/scope_exit_cond_def_cted_fptr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* https://www.boost.org/LICENSE_1_0.txt)
*
* Copyright (c) 2023 Andrey Semashev
*/
/*!
* \file scope_exit_cond_def_cted_fptr.cpp
* \author Andrey Semashev
*
* \brief This file tests that \c scope_exit with a function pointer
* condition function object cannot be default-constructed.
*/

#include <boost/scope/scope_exit.hpp>
#include "function_types.hpp"

int main()
{
int n = 0;
boost::scope::scope_exit< normal_func, bool (*)() > guard{ normal_func(n) };

return 0;
}
23 changes: 23 additions & 0 deletions test/compile_fail/unique_resource_del_def_cted_fptr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* https://www.boost.org/LICENSE_1_0.txt)
*
* Copyright (c) 2023 Andrey Semashev
*/
/*!
* \file unique_resource_del_def_cted_fptr.cpp
* \author Andrey Semashev
*
* \brief This file tests that \c unique_resource with a function pointer
* deleter cannot be default-constructed.
*/

#include <boost/scope/unique_resource.hpp>

int main()
{
boost::scope::unique_resource< int, void (*)(int) > ur;

return 0;
}

0 comments on commit 80d26d6

Please sign in to comment.