541 lines
18 KiB
Diff
541 lines
18 KiB
Diff
From dcd52b94bf50f337dc4cfffa24ed86d7dfe03dc0 Mon Sep 17 00:00:00 2001
|
|
From: Florian Weimer <fweimer@redhat.com>
|
|
Date: Tue, 30 Oct 2018 13:11:47 +0100
|
|
Subject: [PATCH 29] stdlib/test-bz22786: Avoid spurious test failures using
|
|
alias mappings
|
|
|
|
On systems without enough random-access memory, stdlib/test-bz22786
|
|
will go deeply into swap and time out, even with a substantial
|
|
TIMEOUTFACTOR. This commit adds a facility to construct repeating
|
|
strings with alias mappings, so that the requirement for physical
|
|
memory, and uses it in stdlib/test-bz22786.
|
|
|
|
(cherry picked from commit f5e7e95921847bd83186bfe621fc2b48c4de5477)
|
|
---
|
|
ChangeLog | 11 ++
|
|
stdlib/test-bz22786.c | 16 +-
|
|
support/Makefile | 2 +
|
|
support/blob_repeat.c | 278 ++++++++++++++++++++++++++++++
|
|
support/blob_repeat.h | 44 +++++
|
|
support/tst-support_blob_repeat.c | 85 +++++++++
|
|
6 files changed, 426 insertions(+), 10 deletions(-)
|
|
create mode 100644 support/blob_repeat.c
|
|
create mode 100644 support/blob_repeat.h
|
|
create mode 100644 support/tst-support_blob_repeat.c
|
|
|
|
diff --git a/ChangeLog b/ChangeLog
|
|
index 645e6607b2..2043b21dde 100644
|
|
--- a/ChangeLog
|
|
+++ b/ChangeLog
|
|
@@ -1,3 +1,14 @@
|
|
+2018-10-30 Florian Weimer <fweimer@redhat.com>
|
|
+
|
|
+ Avoid spurious test failures in stdlib/test-bz22786.
|
|
+ * support/Makefile (libsupport-routines): Add blob_repeat.
|
|
+ (tests): Add tst-support_blob_repeat.
|
|
+ * support/blob_repeat.h: New file.
|
|
+ * support/blob_repeat.c: Likewise.
|
|
+ * support/tst-support_blob_repeat.c: Likewise.
|
|
+ * stdlib/test-bz22786.c (do_test): Replace malloc and memset with
|
|
+ support_blob_repeat_allocate.
|
|
+
|
|
2018-08-30 Stefan Liebler <stli@linux.ibm.com>
|
|
|
|
* stdlib/test-bz22786.c (do_test): Return EXIT_UNSUPPORTED
|
|
diff --git a/stdlib/test-bz22786.c b/stdlib/test-bz22786.c
|
|
index 777bf9180f..bb1e04f2de 100644
|
|
--- a/stdlib/test-bz22786.c
|
|
+++ b/stdlib/test-bz22786.c
|
|
@@ -26,6 +26,7 @@
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
+#include <support/blob_repeat.h>
|
|
#include <support/check.h>
|
|
#include <support/support.h>
|
|
#include <support/temp_file.h>
|
|
@@ -39,17 +40,12 @@ do_test (void)
|
|
const char *lnk = xasprintf ("%s/symlink", dir);
|
|
const size_t path_len = (size_t) INT_MAX + strlen (lnk) + 1;
|
|
|
|
- DIAG_PUSH_NEEDS_COMMENT;
|
|
-#if __GNUC_PREREQ (7, 0)
|
|
- /* GCC 7 warns about too-large allocations; here we need such
|
|
- allocation to succeed for the test to work. */
|
|
- DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
|
|
-#endif
|
|
- char *path = malloc (path_len);
|
|
- DIAG_POP_NEEDS_COMMENT;
|
|
+ struct support_blob_repeat repeat
|
|
+ = support_blob_repeat_allocate ("a", 1, path_len);
|
|
+ char *path = repeat.start;
|
|
if (path == NULL)
|
|
{
|
|
- printf ("malloc (%zu): %m\n", path_len);
|
|
+ printf ("Repeated allocation (%zu bytes): %m\n", path_len);
|
|
/* On 31-bit s390 the malloc will always fail as we do not have
|
|
so much memory, and we want to mark the test unsupported.
|
|
Likewise on systems with little physical memory the test will
|
|
@@ -62,7 +58,6 @@ do_test (void)
|
|
/* Construct very long path = "/tmp/bz22786.XXXX/symlink/aaaa....." */
|
|
char *p = mempcpy (path, lnk, strlen (lnk));
|
|
*(p++) = '/';
|
|
- memset (p, 'a', path_len - (p - path) - 2);
|
|
p[path_len - (p - path) - 1] = '\0';
|
|
|
|
/* This call crashes before the fix for bz22786 on 32-bit platforms. */
|
|
@@ -76,6 +71,7 @@ do_test (void)
|
|
|
|
/* Cleanup. */
|
|
unlink (lnk);
|
|
+ support_blob_repeat_free (&repeat);
|
|
|
|
return 0;
|
|
}
|
|
diff --git a/support/Makefile b/support/Makefile
|
|
index 652d2cdf69..50470fb749 100644
|
|
--- a/support/Makefile
|
|
+++ b/support/Makefile
|
|
@@ -25,6 +25,7 @@ extra-libs-others = $(extra-libs)
|
|
extra-libs-noinstall := $(extra-libs)
|
|
|
|
libsupport-routines = \
|
|
+ blob_repeat \
|
|
check \
|
|
check_addrinfo \
|
|
check_dns_packet \
|
|
@@ -154,6 +155,7 @@ endif
|
|
tests = \
|
|
README-testing \
|
|
tst-support-namespace \
|
|
+ tst-support_blob_repeat \
|
|
tst-support_capture_subprocess \
|
|
tst-support_format_dns_packet \
|
|
tst-support_quote_blob \
|
|
diff --git a/support/blob_repeat.c b/support/blob_repeat.c
|
|
new file mode 100644
|
|
index 0000000000..da4ca83043
|
|
--- /dev/null
|
|
+++ b/support/blob_repeat.c
|
|
@@ -0,0 +1,278 @@
|
|
+/* Repeating a memory blob, with alias mapping optimization.
|
|
+ Copyright (C) 2018 Free Software Foundation, Inc.
|
|
+ This file is part of the GNU C Library.
|
|
+
|
|
+ The GNU C Library is free software; you can 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 GNU C Library 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
|
|
+ Lesser General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU Lesser General Public
|
|
+ License along with the GNU C Library; if not, see
|
|
+ <http://www.gnu.org/licenses/>. */
|
|
+
|
|
+#include <errno.h>
|
|
+#include <fcntl.h>
|
|
+#include <stdbool.h>
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include <support/blob_repeat.h>
|
|
+#include <support/check.h>
|
|
+#include <support/support.h>
|
|
+#include <support/temp_file.h>
|
|
+#include <support/xunistd.h>
|
|
+#include <sys/mman.h>
|
|
+#include <unistd.h>
|
|
+#include <wchar.h>
|
|
+
|
|
+/* Small allocations should use malloc directly instead of the mmap
|
|
+ optimization because mappings carry a lot of overhead. */
|
|
+static const size_t maximum_small_size = 4 * 1024 * 1024;
|
|
+
|
|
+/* Internal helper for fill. */
|
|
+static void
|
|
+fill0 (char *target, const char *element, size_t element_size,
|
|
+ size_t count)
|
|
+{
|
|
+ while (count > 0)
|
|
+ {
|
|
+ memcpy (target, element, element_size);
|
|
+ target += element_size;
|
|
+ --count;
|
|
+ }
|
|
+}
|
|
+
|
|
+/* Fill the buffer at TARGET with COUNT copies of the ELEMENT_SIZE
|
|
+ bytes starting at ELEMENT. */
|
|
+static void
|
|
+fill (char *target, const char *element, size_t element_size,
|
|
+ size_t count)
|
|
+{
|
|
+ if (element_size == 0 || count == 0)
|
|
+ return;
|
|
+ else if (element_size == 1)
|
|
+ memset (target, element[0], count);
|
|
+ else if (element_size == sizeof (wchar_t))
|
|
+ {
|
|
+ wchar_t wc;
|
|
+ memcpy (&wc, element, sizeof (wc));
|
|
+ wmemset ((wchar_t *) target, wc, count);
|
|
+ }
|
|
+ else if (element_size < 1024 && count > 4096)
|
|
+ {
|
|
+ /* Use larger copies for really small element sizes. */
|
|
+ char buffer[8192];
|
|
+ size_t buffer_count = sizeof (buffer) / element_size;
|
|
+ fill0 (buffer, element, element_size, buffer_count);
|
|
+ while (count > 0)
|
|
+ {
|
|
+ size_t copy_count = buffer_count;
|
|
+ if (copy_count > count)
|
|
+ copy_count = count;
|
|
+ size_t copy_bytes = copy_count * element_size;
|
|
+ memcpy (target, buffer, copy_bytes);
|
|
+ target += copy_bytes;
|
|
+ count -= copy_count;
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ fill0 (target, element, element_size, count);
|
|
+}
|
|
+
|
|
+/* Use malloc instead of mmap for small allocations and unusual size
|
|
+ combinations. */
|
|
+static struct support_blob_repeat
|
|
+allocate_malloc (size_t total_size, const void *element, size_t element_size,
|
|
+ size_t count)
|
|
+{
|
|
+ void *buffer = malloc (total_size);
|
|
+ if (buffer == NULL)
|
|
+ return (struct support_blob_repeat) { 0 };
|
|
+ fill (buffer, element, element_size, count);
|
|
+ return (struct support_blob_repeat)
|
|
+ {
|
|
+ .start = buffer,
|
|
+ .size = total_size,
|
|
+ .use_malloc = true
|
|
+ };
|
|
+}
|
|
+
|
|
+/* Return the least common multiple of PAGE_SIZE and ELEMENT_SIZE,
|
|
+ avoiding overflow. This assumes that PAGE_SIZE is a power of
|
|
+ two. */
|
|
+static size_t
|
|
+minimum_stride_size (size_t page_size, size_t element_size)
|
|
+{
|
|
+ TEST_VERIFY_EXIT (page_size > 0);
|
|
+ TEST_VERIFY_EXIT (element_size > 0);
|
|
+
|
|
+ /* Compute the number of trailing zeros common to both sizes. */
|
|
+ unsigned int common_zeros = __builtin_ctzll (page_size | element_size);
|
|
+
|
|
+ /* In the product, this power of two appears twice, but in the least
|
|
+ common multiple, it appears only once. Therefore, shift one
|
|
+ factor. */
|
|
+ size_t multiple;
|
|
+ if (__builtin_mul_overflow (page_size >> common_zeros, element_size,
|
|
+ &multiple))
|
|
+ return 0;
|
|
+ return multiple;
|
|
+}
|
|
+
|
|
+/* Allocations larger than maximum_small_size potentially use mmap
|
|
+ with alias mappings. */
|
|
+static struct support_blob_repeat
|
|
+allocate_big (size_t total_size, const void *element, size_t element_size,
|
|
+ size_t count)
|
|
+{
|
|
+ unsigned long page_size = xsysconf (_SC_PAGESIZE);
|
|
+ size_t stride_size = minimum_stride_size (page_size, element_size);
|
|
+ if (stride_size == 0)
|
|
+ {
|
|
+ errno = EOVERFLOW;
|
|
+ return (struct support_blob_repeat) { 0 };
|
|
+ }
|
|
+
|
|
+ /* Ensure that the stride size is at least maximum_small_size. This
|
|
+ is necessary to reduce the number of distinct mappings. */
|
|
+ if (stride_size < maximum_small_size)
|
|
+ stride_size
|
|
+ = ((maximum_small_size + stride_size - 1) / stride_size) * stride_size;
|
|
+
|
|
+ if (stride_size > total_size)
|
|
+ /* The mmap optimization would not save anything. */
|
|
+ return allocate_malloc (total_size, element, element_size, count);
|
|
+
|
|
+ /* Reserve the memory region. If we cannot create the mapping,
|
|
+ there is no reason to set up the backing file. */
|
|
+ void *target = mmap (NULL, total_size, PROT_NONE,
|
|
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
|
+ if (target == MAP_FAILED)
|
|
+ return (struct support_blob_repeat) { 0 };
|
|
+
|
|
+ /* Create the backing file for the repeated mapping. */
|
|
+ int fd;
|
|
+ {
|
|
+ char *temppath;
|
|
+ fd = create_temp_file ("support_blob_repeat-", &temppath);
|
|
+ if (fd < 0)
|
|
+ FAIL_EXIT1 ("create_temp_file: %m");
|
|
+ xunlink (temppath);
|
|
+ free (temppath);
|
|
+ }
|
|
+
|
|
+ /* Make sure that there is backing storage, so that the fill
|
|
+ operation will not fault. */
|
|
+ if (posix_fallocate (fd, 0, stride_size) != 0)
|
|
+ FAIL_EXIT1 ("posix_fallocate (%zu): %m", stride_size);
|
|
+
|
|
+ /* The stride size must still be a multiple of the page size and
|
|
+ element size. */
|
|
+ TEST_VERIFY_EXIT ((stride_size % page_size) == 0);
|
|
+ TEST_VERIFY_EXIT ((stride_size % element_size) == 0);
|
|
+
|
|
+ /* Fill the backing store. */
|
|
+ {
|
|
+ void *ptr = mmap (target, stride_size, PROT_READ | PROT_WRITE,
|
|
+ MAP_FIXED | MAP_FILE | MAP_SHARED, fd, 0);
|
|
+ if (ptr == MAP_FAILED)
|
|
+ {
|
|
+ int saved_errno = errno;
|
|
+ xmunmap (target, total_size);
|
|
+ xclose (fd);
|
|
+ errno = saved_errno;
|
|
+ return (struct support_blob_repeat) { 0 };
|
|
+ }
|
|
+ if (ptr != target)
|
|
+ FAIL_EXIT1 ("mapping of %zu bytes moved from %p to %p",
|
|
+ stride_size, target, ptr);
|
|
+
|
|
+ /* Write the repeating data. */
|
|
+ fill (target, element, element_size, stride_size / element_size);
|
|
+
|
|
+ /* Return to a PROT_NONE mapping, just to be on the safe side. */
|
|
+ ptr = mmap (target, stride_size, PROT_NONE,
|
|
+ MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
|
+ if (ptr == MAP_FAILED)
|
|
+ FAIL_EXIT1 ("Failed to reinstate PROT_NONE mapping: %m");
|
|
+ if (ptr != target)
|
|
+ FAIL_EXIT1 ("PROT_NONE mapping of %zu bytes moved from %p to %p",
|
|
+ stride_size, target, ptr);
|
|
+ }
|
|
+
|
|
+ /* Create the alias mappings. */
|
|
+ {
|
|
+ size_t remaining_size = total_size;
|
|
+ char *current = target;
|
|
+ int flags = MAP_FIXED | MAP_FILE | MAP_PRIVATE;
|
|
+#ifdef MAP_NORESERVE
|
|
+ flags |= MAP_NORESERVE;
|
|
+#endif
|
|
+ while (remaining_size > 0)
|
|
+ {
|
|
+ size_t to_map = stride_size;
|
|
+ if (to_map > remaining_size)
|
|
+ to_map = remaining_size;
|
|
+ void *ptr = mmap (current, to_map, PROT_READ | PROT_WRITE,
|
|
+ flags, fd, 0);
|
|
+ if (ptr == MAP_FAILED)
|
|
+ {
|
|
+ int saved_errno = errno;
|
|
+ xmunmap (target, total_size);
|
|
+ xclose (fd);
|
|
+ errno = saved_errno;
|
|
+ return (struct support_blob_repeat) { 0 };
|
|
+ }
|
|
+ if (ptr != current)
|
|
+ FAIL_EXIT1 ("MAP_PRIVATE mapping of %zu bytes moved from %p to %p",
|
|
+ to_map, target, ptr);
|
|
+ remaining_size -= to_map;
|
|
+ current += to_map;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ xclose (fd);
|
|
+
|
|
+ return (struct support_blob_repeat)
|
|
+ {
|
|
+ .start = target,
|
|
+ .size = total_size,
|
|
+ .use_malloc = false
|
|
+ };
|
|
+}
|
|
+
|
|
+struct support_blob_repeat
|
|
+support_blob_repeat_allocate (const void *element, size_t element_size,
|
|
+ size_t count)
|
|
+{
|
|
+ size_t total_size;
|
|
+ if (__builtin_mul_overflow (element_size, count, &total_size))
|
|
+ {
|
|
+ errno = EOVERFLOW;
|
|
+ return (struct support_blob_repeat) { 0 };
|
|
+ }
|
|
+ if (total_size <= maximum_small_size)
|
|
+ return allocate_malloc (total_size, element, element_size, count);
|
|
+ else
|
|
+ return allocate_big (total_size, element, element_size, count);
|
|
+}
|
|
+
|
|
+void
|
|
+support_blob_repeat_free (struct support_blob_repeat *blob)
|
|
+{
|
|
+ if (blob->size > 0)
|
|
+ {
|
|
+ int saved_errno = errno;
|
|
+ if (blob->use_malloc)
|
|
+ free (blob->start);
|
|
+ else
|
|
+ xmunmap (blob->start, blob->size);
|
|
+ errno = saved_errno;
|
|
+ }
|
|
+ *blob = (struct support_blob_repeat) { 0 };
|
|
+}
|
|
diff --git a/support/blob_repeat.h b/support/blob_repeat.h
|
|
new file mode 100644
|
|
index 0000000000..8e9d7ff5f1
|
|
--- /dev/null
|
|
+++ b/support/blob_repeat.h
|
|
@@ -0,0 +1,44 @@
|
|
+/* Repeating a memory blob, with alias mapping optimization.
|
|
+ Copyright (C) 2018 Free Software Foundation, Inc.
|
|
+ This file is part of the GNU C Library.
|
|
+
|
|
+ The GNU C Library is free software; you can 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 GNU C Library 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
|
|
+ Lesser General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU Lesser General Public
|
|
+ License along with the GNU C Library; if not, see
|
|
+ <http://www.gnu.org/licenses/>. */
|
|
+
|
|
+#ifndef SUPPORT_BLOB_REPEAT_H
|
|
+#define SUPPORT_BLOB_REPEAT_H
|
|
+
|
|
+#include <stdbool.h>
|
|
+#include <stddef.h>
|
|
+
|
|
+struct support_blob_repeat
|
|
+{
|
|
+ void *start;
|
|
+ size_t size;
|
|
+ bool use_malloc;
|
|
+};
|
|
+
|
|
+/* Return an allocation of COUNT elements, each of ELEMENT_SIZE bytes,
|
|
+ initialized with the bytes starting at ELEMENT. The memory is
|
|
+ writable (and thus counts towards the commit charge). In case of
|
|
+ on error, all members of the return struct are zero-initialized,
|
|
+ and errno is set accordingly. */
|
|
+struct support_blob_repeat support_blob_repeat_allocate (const void *element,
|
|
+ size_t element_size,
|
|
+ size_t count);
|
|
+
|
|
+/* Deallocate the blob created by support_blob_repeat_allocate. */
|
|
+void support_blob_repeat_free (struct support_blob_repeat *);
|
|
+
|
|
+#endif /* SUPPORT_BLOB_REPEAT_H */
|
|
diff --git a/support/tst-support_blob_repeat.c b/support/tst-support_blob_repeat.c
|
|
new file mode 100644
|
|
index 0000000000..1978c14488
|
|
--- /dev/null
|
|
+++ b/support/tst-support_blob_repeat.c
|
|
@@ -0,0 +1,85 @@
|
|
+/* Tests for <support/blob_repeat.h>
|
|
+ Copyright (C) 2018 Free Software Foundation, Inc.
|
|
+ This file is part of the GNU C Library.
|
|
+
|
|
+ The GNU C Library is free software; you can 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 GNU C Library 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
|
|
+ Lesser General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU Lesser General Public
|
|
+ License along with the GNU C Library; if not, see
|
|
+ <http://www.gnu.org/licenses/>. */
|
|
+
|
|
+#include <stdio.h>
|
|
+#include <support/blob_repeat.h>
|
|
+#include <support/check.h>
|
|
+
|
|
+static int
|
|
+do_test (void)
|
|
+{
|
|
+ struct support_blob_repeat repeat
|
|
+ = support_blob_repeat_allocate ("5", 1, 5);
|
|
+ TEST_COMPARE_BLOB (repeat.start, repeat.size, "55555", 5);
|
|
+ support_blob_repeat_free (&repeat);
|
|
+
|
|
+ repeat = support_blob_repeat_allocate ("ABC", 3, 3);
|
|
+ TEST_COMPARE_BLOB (repeat.start, repeat.size, "ABCABCABC", 9);
|
|
+ support_blob_repeat_free (&repeat);
|
|
+
|
|
+ repeat = support_blob_repeat_allocate ("abc", 4, 3);
|
|
+ TEST_COMPARE_BLOB (repeat.start, repeat.size, "abc\0abc\0abc", 12);
|
|
+ support_blob_repeat_free (&repeat);
|
|
+
|
|
+ size_t gigabyte = 1U << 30;
|
|
+ repeat = support_blob_repeat_allocate ("X", 1, gigabyte + 1);
|
|
+ if (repeat.start == NULL)
|
|
+ puts ("warning: not enough memory for 1 GiB mapping");
|
|
+ else
|
|
+ {
|
|
+ TEST_COMPARE (repeat.size, gigabyte + 1);
|
|
+ {
|
|
+ unsigned char *p = repeat.start;
|
|
+ for (size_t i = 0; i < gigabyte + 1; ++i)
|
|
+ if (p[i] != 'X')
|
|
+ FAIL_EXIT1 ("invalid byte 0x%02x at %zu", p[i], i);
|
|
+
|
|
+ /* Check that there is no sharing across the mapping. */
|
|
+ p[0] = 'Y';
|
|
+ p[1U << 24] = 'Z';
|
|
+ for (size_t i = 0; i < gigabyte + 1; ++i)
|
|
+ if (i == 0)
|
|
+ TEST_COMPARE (p[i], 'Y');
|
|
+ else if (i == 1U << 24)
|
|
+ TEST_COMPARE (p[i], 'Z');
|
|
+ else if (p[i] != 'X')
|
|
+ FAIL_EXIT1 ("invalid byte 0x%02x at %zu", p[i], i);
|
|
+ }
|
|
+ }
|
|
+ support_blob_repeat_free (&repeat);
|
|
+
|
|
+ repeat = support_blob_repeat_allocate ("012345678", 9, 10 * 1000 * 1000);
|
|
+ if (repeat.start == NULL)
|
|
+ puts ("warning: not enough memory for large mapping");
|
|
+ else
|
|
+ {
|
|
+ unsigned char *p = repeat.start;
|
|
+ for (int i = 0; i < 10 * 1000 * 1000; ++i)
|
|
+ for (int j = 0; j <= 8; ++j)
|
|
+ if (p[i * 9 + j] != '0' + j)
|
|
+ {
|
|
+ printf ("error: element %d index %d\n", i, j);
|
|
+ TEST_COMPARE (p[i * 9 + j], '0' + j);
|
|
+ }
|
|
+ }
|
|
+ support_blob_repeat_free (&repeat);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#include <support/test-driver.c>
|
|
|