aboutsummaryrefslogtreecommitdiff
path: root/gdb/unittests
diff options
context:
space:
mode:
authorLancelot SIX <lsix@lancelotsix.com>2021-10-19 21:51:40 +0000
committerLancelot SIX <lsix@lancelotsix.com>2021-11-08 21:55:36 +0000
commite92f2b5eef008a8617bcd6d878b09848adf6ea7f (patch)
treeca1ddafb398545629ba0974847d2624b7545322c /gdb/unittests
parent8b4195d8d1d1a7c328f9b0dc48cdbf3d8abb6fe6 (diff)
downloadgdb-e92f2b5eef008a8617bcd6d878b09848adf6ea7f.zip
gdb-e92f2b5eef008a8617bcd6d878b09848adf6ea7f.tar.gz
gdb-e92f2b5eef008a8617bcd6d878b09848adf6ea7f.tar.bz2
Improve gdb::array_view ctor from contiguous containers
While reading the interface of gdb::array_view, I realized that the constructor that builds an array_view on top of a contiguous container (such as std::vector, std::array or even gdb::array_view) can be missused. Lets consider the following code sample: struct Parent { Parent (int a): a { a } {} int a; }; std::ostream &operator<< (std::ostream& os, const Parent & p) { os << "Parent {a=" << p.a << "}"; return os; } struct Child : public Parent { Child (int a, int b): Parent { a }, b { b } {} int b; }; std::ostream &operator<< (std::ostream& os, const Child & p) { os << "Child {a=" << p.a << ", b=" << p.b << "}"; return os; } template <typename T> void print (const gdb::array_view<const T> &p) { std::for_each (p.begin (), p.end (), [](const T &p) { std::cout << p << '\n'; }); } Then with the current interface nothinng prevents this usage of array_view to be done: const std::array<Child, 3> elts = { Child {1, 2}, Child {3, 4}, Child {5, 6} }; print_all<Parent> (elts); This compiles fine and produces the following output: Parent {a=1} Parent {a=2} Parent {a=3} which is obviously wrong. There is nowhere in memory a Parent-like object for which the A member is 2 and this call to print_all<Parent> shold not compile at all (calling print_all<Child> is however fine). This comes down to the fact that a Child* is convertible into a Parent*, and that an array view is constructed to a pointer to the first element and a size. The valid type pointed to that can be used with this constructor are restricted using SFINAE, which requires that a pointer to a member into the underlying container can be converted into a pointer the array_view's data type. This patch proposes to change the constraints on the gdb::array_view ctor which accepts a container now requires that the (decayed) type of the elements in the container match the (decayed) type of the array_view being constructed. Applying this change required minimum adjustment in GDB codebase, which are also included in this patch. Tested by rebuilding.
Diffstat (limited to 'gdb/unittests')
-rw-r--r--gdb/unittests/array-view-selftests.c25
1 files changed, 23 insertions, 2 deletions
diff --git a/gdb/unittests/array-view-selftests.c b/gdb/unittests/array-view-selftests.c
index b62369b..43b7434 100644
--- a/gdb/unittests/array-view-selftests.c
+++ b/gdb/unittests/array-view-selftests.c
@@ -21,6 +21,7 @@
#include "gdbsupport/selftest.h"
#include "gdbsupport/array-view.h"
#include <array>
+#include <vector>
namespace selftests {
namespace array_view_tests {
@@ -86,8 +87,8 @@ struct A { int i; };
struct B : A { int j; };
struct C : A { int l; };
-/* Check that there's no array->view conversion for arrays of derived
- types or subclasses. */
+/* Check that there's no array->view conversion for arrays of derived types or
+ subclasses. */
static constexpr bool
check ()
{
@@ -116,9 +117,29 @@ check ()
&& !is_convertible <C, array_view<B>> ());
}
+/* Check that there's no container->view conversion for containers of derived
+ types or subclasses. */
+
+template<template<typename ...> typename Container>
+static constexpr bool
+check_ctor_from_container ()
+{
+ using gdb::array_view;
+
+ return ( is_convertible <Container<A>, array_view<A>> ()
+ && !is_convertible <Container<B>, array_view<A>> ()
+ && !is_convertible <Container<C>, array_view<A>> ()
+
+ && !is_convertible <Container<A>, array_view<B>> ()
+ && is_convertible <Container<B>, array_view<B>> ()
+ && !is_convertible <Container<C>, array_view<B>> ());
+}
+
} /* namespace no_slicing */
static_assert (no_slicing::check (), "");
+static_assert (no_slicing::check_ctor_from_container<std::vector> (), "");
+static_assert (no_slicing::check_ctor_from_container<gdb::array_view> (), "");
/* Check that array_view implicitly converts from std::vector. */