[6/6] Add simple_search_memory unit tests

Message ID 20200723201216.3932150-7-tromey@adacore.com
State New
Headers show
Series
  • Share memory searching code between gdb and gdbserver
Related show

Commit Message

Tom Tromey July 23, 2020, 8:12 p.m.
This adds some unit tests for simple_search_memory.  I tried here to
reproduce some bugs (PR gdb/11158 and PR gdb/17756), but was unable
to.

2020-07-23  Tom Tromey  <tromey@adacore.com>

	* unittests/search-memory-selftests.c: New file.
	* Makefile.in (SELFTESTS_SRCS): Add
	unittests/search-memory-selftests.c.
---
 gdb/ChangeLog                           |   6 ++
 gdb/Makefile.in                         |   1 +
 gdb/unittests/search-memory-selftests.c | 102 ++++++++++++++++++++++++
 3 files changed, 109 insertions(+)
 create mode 100644 gdb/unittests/search-memory-selftests.c

-- 
2.26.2

Comments

Simon Marchi July 30, 2020, 1:12 p.m. | #1
On 2020-07-23 4:12 p.m., Tom Tromey wrote:
> This adds some unit tests for simple_search_memory.  I tried here to

> reproduce some bugs (PR gdb/11158 and PR gdb/17756), but was unable

> to.

> 

> 2020-07-23  Tom Tromey  <tromey@adacore.com>

> 

> 	* unittests/search-memory-selftests.c: New file.

> 	* Makefile.in (SELFTESTS_SRCS): Add

> 	unittests/search-memory-selftests.c.

> ---

>  gdb/ChangeLog                           |   6 ++

>  gdb/Makefile.in                         |   1 +

>  gdb/unittests/search-memory-selftests.c | 102 ++++++++++++++++++++++++

>  3 files changed, 109 insertions(+)

>  create mode 100644 gdb/unittests/search-memory-selftests.c

> 

> diff --git a/gdb/Makefile.in b/gdb/Makefile.in

> index 8feb5e39ff5..e279b8d944a 100644

> --- a/gdb/Makefile.in

> +++ b/gdb/Makefile.in

> @@ -450,6 +450,7 @@ SELFTESTS_SRCS = \

>  	unittests/scoped_fd-selftests.c \

>  	unittests/scoped_mmap-selftests.c \

>  	unittests/scoped_restore-selftests.c \

> +	unittests/search-memory-selftests.c \

>  	unittests/string_view-selftests.c \

>  	unittests/style-selftests.c \

>  	unittests/tracepoint-selftests.c \

> diff --git a/gdb/unittests/search-memory-selftests.c b/gdb/unittests/search-memory-selftests.c

> new file mode 100644

> index 00000000000..4bf93756ed6

> --- /dev/null

> +++ b/gdb/unittests/search-memory-selftests.c

> @@ -0,0 +1,102 @@

> +/* Self tests for simple_search_memory for GDB, the GNU debugger.

> +

> +   Copyright (C) 2020 Free Software Foundation, Inc.

> +

> +   This file is part of GDB.

> +

> +   This program is free software; you can redistribute it and/or modify

> +   it under the terms of the GNU General Public License as published by

> +   the Free Software Foundation; either version 3 of the License, or

> +   (at your option) any later version.

> +

> +   This program is distributed in the hope that it will be useful,

> +   but WITHOUT ANY WARRANTY; without even the implied warranty of

> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

> +   GNU General Public License for more details.

> +

> +   You should have received a copy of the GNU General Public License

> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

> +

> +#include "gdbsupport/common-defs.h"

> +#include "gdbsupport/selftest.h"

> +#include "target/target.h"

> +

> +namespace selftests {

> +namespace search_memory_tests {

> +

> +/* Note: Also defined in target/search.c.  */

> +#define SEARCH_CHUNK_SIZE 16000


I wonder if this should be defined in target/target.h instead.

> +

> +static void

> +run_tests ()

> +{

> +  size_t size = 2 * SEARCH_CHUNK_SIZE + 1;

> +

> +  std::vector<gdb_byte> data (size);

> +  data[size - 1] = 'x';

> +

> +  bool read_fully = false;

> +  bool read_off_end = false;

> +  auto read_memory = [&] (CORE_ADDR from, gdb_byte *out, size_t len)

> +    {

> +      if (from + len > data.size ())

> +	read_off_end = true;

> +      else

> +	memcpy (out, &data[from], len);

> +      if (from + len == data.size ())

> +	read_fully = true;

> +      return true;

> +    };

> +

> +  gdb_byte pattern = 'x';

> +

> +  CORE_ADDR addr = 0;

> +  int result = simple_search_memory (read_memory, 0, data.size (),

> +				     &pattern, 1, &addr);

> +  /* In this case we don't care if read_fully was set or not.  */

> +  SELF_CHECK (result == 1);

> +  SELF_CHECK (!read_off_end);

> +  SELF_CHECK (addr == size - 1);

> +

> +  addr = 0;

> +  read_fully = false;

> +  read_off_end = false;

> +  pattern = 'q';

> +  result = simple_search_memory (read_memory, 0, data.size (),

> +				 &pattern, 1, &addr);

> +  SELF_CHECK (result == 0);

> +  SELF_CHECK (!read_off_end);

> +  SELF_CHECK (read_fully);

> +  SELF_CHECK (addr == 0);

> +

> +  /* Setup from PR gdb/17756.  */

> +  size = 0x7bb00;

> +  data = std::vector<gdb_byte> (size);

> +  const CORE_ADDR base_addr = 0x08370000;

> +  const gdb_byte wpattern[] = { 0x90, 0x8b, 0x98, 0x8 };

> +  const CORE_ADDR found_addr = 0x837bac8;

> +  memcpy (&data[found_addr - base_addr], wpattern, sizeof (wpattern));

> +

> +  auto read_memory_2 = [&] (CORE_ADDR from, gdb_byte *out, size_t len)

> +    {

> +      memcpy (out, &data[from - base_addr], len);

> +      return true;

> +    };

> +

> +  result = simple_search_memory (read_memory_2, base_addr, data.size (),

> +				 wpattern, sizeof (wpattern), &addr);

> +  SELF_CHECK (result == 1);

> +  SELF_CHECK (addr == found_addr);

> +}


I compile with -D_GLIBCXX_DEBUG=1, and it aborts when running this test:

Running selftest search_memory.
/usr/include/c++/10.1.0/debug/vector:427:
In function:
    std::__debug::vector<_Tp, _Allocator>::reference
    std::__debug::vector<_Tp,
    _Allocator>::operator[](std::__debug::vector<_Tp,
    _Allocator>::size_type) [with _Tp = unsigned char; _Allocator =
    gdb::default_init_allocator<unsigned char, std::allocator<unsigned char>
    >; std::__debug::vector<_Tp, _Allocator>::reference = unsigned char&;

    std::__debug::vector<_Tp, _Allocator>::size_type = long unsigned int]

Error: attempt to subscript container with out-of-bounds index 16000, but
container only holds 16000 elements.

Objects involved in the operation:
    sequence "this" @ 0x0x7ffc6e54f870 {
      type = std::__debug::vector<unsigned char, gdb::default_init_allocator<unsigned char, std::allocator<unsigned char> > >;
    }

Simon

Patch

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 8feb5e39ff5..e279b8d944a 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -450,6 +450,7 @@  SELFTESTS_SRCS = \
 	unittests/scoped_fd-selftests.c \
 	unittests/scoped_mmap-selftests.c \
 	unittests/scoped_restore-selftests.c \
+	unittests/search-memory-selftests.c \
 	unittests/string_view-selftests.c \
 	unittests/style-selftests.c \
 	unittests/tracepoint-selftests.c \
diff --git a/gdb/unittests/search-memory-selftests.c b/gdb/unittests/search-memory-selftests.c
new file mode 100644
index 00000000000..4bf93756ed6
--- /dev/null
+++ b/gdb/unittests/search-memory-selftests.c
@@ -0,0 +1,102 @@ 
+/* Self tests for simple_search_memory for GDB, the GNU debugger.
+
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "gdbsupport/common-defs.h"
+#include "gdbsupport/selftest.h"
+#include "target/target.h"
+
+namespace selftests {
+namespace search_memory_tests {
+
+/* Note: Also defined in target/search.c.  */
+#define SEARCH_CHUNK_SIZE 16000
+
+static void
+run_tests ()
+{
+  size_t size = 2 * SEARCH_CHUNK_SIZE + 1;
+
+  std::vector<gdb_byte> data (size);
+  data[size - 1] = 'x';
+
+  bool read_fully = false;
+  bool read_off_end = false;
+  auto read_memory = [&] (CORE_ADDR from, gdb_byte *out, size_t len)
+    {
+      if (from + len > data.size ())
+	read_off_end = true;
+      else
+	memcpy (out, &data[from], len);
+      if (from + len == data.size ())
+	read_fully = true;
+      return true;
+    };
+
+  gdb_byte pattern = 'x';
+
+  CORE_ADDR addr = 0;
+  int result = simple_search_memory (read_memory, 0, data.size (),
+				     &pattern, 1, &addr);
+  /* In this case we don't care if read_fully was set or not.  */
+  SELF_CHECK (result == 1);
+  SELF_CHECK (!read_off_end);
+  SELF_CHECK (addr == size - 1);
+
+  addr = 0;
+  read_fully = false;
+  read_off_end = false;
+  pattern = 'q';
+  result = simple_search_memory (read_memory, 0, data.size (),
+				 &pattern, 1, &addr);
+  SELF_CHECK (result == 0);
+  SELF_CHECK (!read_off_end);
+  SELF_CHECK (read_fully);
+  SELF_CHECK (addr == 0);
+
+  /* Setup from PR gdb/17756.  */
+  size = 0x7bb00;
+  data = std::vector<gdb_byte> (size);
+  const CORE_ADDR base_addr = 0x08370000;
+  const gdb_byte wpattern[] = { 0x90, 0x8b, 0x98, 0x8 };
+  const CORE_ADDR found_addr = 0x837bac8;
+  memcpy (&data[found_addr - base_addr], wpattern, sizeof (wpattern));
+
+  auto read_memory_2 = [&] (CORE_ADDR from, gdb_byte *out, size_t len)
+    {
+      memcpy (out, &data[from - base_addr], len);
+      return true;
+    };
+
+  result = simple_search_memory (read_memory_2, base_addr, data.size (),
+				 wpattern, sizeof (wpattern), &addr);
+  SELF_CHECK (result == 1);
+  SELF_CHECK (addr == found_addr);
+}
+
+} /* namespace search_memory_tests */
+} /* namespace selftests */
+
+
+void _initialize_search_memory_selftests ();
+void
+_initialize_search_memory_selftests ()
+{
+  selftests::register_test ("search_memory",
+			    selftests::search_memory_tests::run_tests);
+}