diff mbox series

[libbacktrace] Add allocfail.sh test-case

Message ID 20181128124956.GA4743@delia
State New
Headers show
Series [libbacktrace] Add allocfail.sh test-case | expand

Commit Message

Tom de Vries Nov. 28, 2018, 12:49 p.m. UTC
Hi,

Add test-case that forces alloc.c functions to fail, and check whether fail
handling is robust.

This is the test-case for "[libbacktrace] Fix segfault upon allocation
failure".  Without that patch, this test-case fails like this:
...
allocfail.sh: line 71: 26041 Segmentation fault      (core dumped) \
  ./allocfail $i > /dev/null 2>&1
Unallowed fail found: 13
FAIL allocfail.sh (exit status: 1)
...

This is a seperate patch because the test-case is nontrivial.

Bootstrapped and reg-tested on x86_64.

OK for trunk?

Thanks,
- Tom

[libbacktrace] Add allocfail.sh test-case

2018-11-27  Tom de Vries  <tdevries@suse.de>

	* Makefile.am (TESTS): Add allocfail.sh.
	(check_PROGRAMS): Add allocfail.
	* Makefile.in: Regenerate.
	* instrumented_alloc.c: New file.  Redefine malloc and realloc.
	Include alloc.c.
	* allocfail.c: New file.
	* allocfail.sh: New file.

---
 libbacktrace/Makefile.am          |  15 +++++
 libbacktrace/Makefile.in          |  60 +++++++++++++----
 libbacktrace/allocfail.c          | 136 ++++++++++++++++++++++++++++++++++++++
 libbacktrace/allocfail.sh         | 105 +++++++++++++++++++++++++++++
 libbacktrace/instrumented_alloc.c | 114 ++++++++++++++++++++++++++++++++
 5 files changed, 418 insertions(+), 12 deletions(-)

Comments

Li, Pan2 via Gcc-patches Dec. 11, 2018, 5:59 p.m. UTC | #1
On Wed, Nov 28, 2018 at 4:50 AM Tom de Vries <tdevries@suse.de> wrote:
>
> Add test-case that forces alloc.c functions to fail, and check whether fail
> handling is robust.
>
> This is the test-case for "[libbacktrace] Fix segfault upon allocation
> failure".  Without that patch, this test-case fails like this:
> ...
> allocfail.sh: line 71: 26041 Segmentation fault      (core dumped) \
>   ./allocfail $i > /dev/null 2>&1
> Unallowed fail found: 13
> FAIL allocfail.sh (exit status: 1)
> ...
>
> This is a seperate patch because the test-case is nontrivial.
>
> Bootstrapped and reg-tested on x86_64.
>
> OK for trunk?
>
> Thanks,
> - Tom
>
> [libbacktrace] Add allocfail.sh test-case
>
> 2018-11-27  Tom de Vries  <tdevries@suse.de>
>
>         * Makefile.am (TESTS): Add allocfail.sh.
>         (check_PROGRAMS): Add allocfail.
>         * Makefile.in: Regenerate.
>         * instrumented_alloc.c: New file.  Redefine malloc and realloc.
>         Include alloc.c.
>         * allocfail.c: New file.
>         * allocfail.sh: New file.

Can you redo this without using GNU make features like $(filter-out) ?

Ian
Tom de Vries Dec. 12, 2018, 7:03 a.m. UTC | #2
On 11-12-18 18:59, Ian Lance Taylor wrote:
> On Wed, Nov 28, 2018 at 4:50 AM Tom de Vries <tdevries@suse.de> wrote:
>>
>> Add test-case that forces alloc.c functions to fail, and check whether fail
>> handling is robust.
>>
>> This is the test-case for "[libbacktrace] Fix segfault upon allocation
>> failure".  Without that patch, this test-case fails like this:
>> ...
>> allocfail.sh: line 71: 26041 Segmentation fault      (core dumped) \
>>   ./allocfail $i > /dev/null 2>&1
>> Unallowed fail found: 13
>> FAIL allocfail.sh (exit status: 1)
>> ...
>>
>> This is a seperate patch because the test-case is nontrivial.
>>
>> Bootstrapped and reg-tested on x86_64.
>>
>> OK for trunk?
>>
>> Thanks,
>> - Tom
>>
>> [libbacktrace] Add allocfail.sh test-case
>>
>> 2018-11-27  Tom de Vries  <tdevries@suse.de>
>>
>>         * Makefile.am (TESTS): Add allocfail.sh.
>>         (check_PROGRAMS): Add allocfail.
>>         * Makefile.in: Regenerate.
>>         * instrumented_alloc.c: New file.  Redefine malloc and realloc.
>>         Include alloc.c.
>>         * allocfail.c: New file.
>>         * allocfail.sh: New file.
> 
> Can you redo this without using GNU make features like $(filter-out) ?

Hi,

Done, and re-bootstrapped-and-regtested.

OK for trunk?

Thanks,
- Tom
Tom de Vries Dec. 12, 2018, 7:04 a.m. UTC | #3
[ Fixed ENOPATCH ]

On 12-12-18 08:03, Tom de Vries wrote:
> On 11-12-18 18:59, Ian Lance Taylor wrote:
>> On Wed, Nov 28, 2018 at 4:50 AM Tom de Vries <tdevries@suse.de> wrote:
>>>
>>> Add test-case that forces alloc.c functions to fail, and check whether fail
>>> handling is robust.
>>>
>>> This is the test-case for "[libbacktrace] Fix segfault upon allocation
>>> failure".  Without that patch, this test-case fails like this:
>>> ...
>>> allocfail.sh: line 71: 26041 Segmentation fault      (core dumped) \
>>>   ./allocfail $i > /dev/null 2>&1
>>> Unallowed fail found: 13
>>> FAIL allocfail.sh (exit status: 1)
>>> ...
>>>
>>> This is a seperate patch because the test-case is nontrivial.
>>>
>>> Bootstrapped and reg-tested on x86_64.
>>>
>>> OK for trunk?
>>>
>>> Thanks,
>>> - Tom
>>>
>>> [libbacktrace] Add allocfail.sh test-case
>>>
>>> 2018-11-27  Tom de Vries  <tdevries@suse.de>
>>>
>>>         * Makefile.am (TESTS): Add allocfail.sh.
>>>         (check_PROGRAMS): Add allocfail.
>>>         * Makefile.in: Regenerate.
>>>         * instrumented_alloc.c: New file.  Redefine malloc and realloc.
>>>         Include alloc.c.
>>>         * allocfail.c: New file.
>>>         * allocfail.sh: New file.
>>
>> Can you redo this without using GNU make features like $(filter-out) ?
> 
> Hi,
> 
> Done, and re-bootstrapped-and-regtested.
> 
> OK for trunk?
> 
> Thanks,
> - Tom
>
[libbacktrace] Add allocfail.sh test-case

Add test-case that forces alloc.c functions to fail, and check whether fail
handling is robust.

This is the test-case for "[libbacktrace] Fix segfault upon allocation
failure".  Without that patch, this test-case fails like this:
...
allocfail.sh: line 71: 26041 Segmentation fault      (core dumped) \
  ./allocfail $i > /dev/null 2>&1
Unallowed fail found: 13
FAIL allocfail.sh (exit status: 1)
...

This is a seperate patch because the test-case is nontrivial.

Bootstrapped and reg-tested on x86_64.

2018-11-27  Tom de Vries  <tdevries@suse.de>

	* Makefile.am (TESTS): Add allocfail.sh.
	(check_PROGRAMS): Add allocfail.
	* Makefile.in: Regenerate.
	* instrumented_alloc.c: New file.  Redefine malloc and realloc.
	Include alloc.c.
	* allocfail.c: New file.
	* allocfail.sh: New file.

---
 libbacktrace/Makefile.am          |  20 ++++++
 libbacktrace/Makefile.in          |  81 ++++++++++++++++++-----
 libbacktrace/allocfail.c          | 136 ++++++++++++++++++++++++++++++++++++++
 libbacktrace/allocfail.sh         | 105 +++++++++++++++++++++++++++++
 libbacktrace/instrumented_alloc.c | 114 ++++++++++++++++++++++++++++++++
 5 files changed, 439 insertions(+), 17 deletions(-)

diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am
index 1a3680bc98c..9d489f7b418 100644
--- a/libbacktrace/Makefile.am
+++ b/libbacktrace/Makefile.am
@@ -145,6 +145,26 @@ unittest_alloc_LDADD = libbacktrace_alloc.la
 
 check_PROGRAMS += unittest_alloc
 
+check_LTLIBRARIES += libbacktrace_instrumented_alloc.la
+
+libbacktrace_instrumented_alloc_la_SOURCES = $(libbacktrace_la_SOURCES)
+libbacktrace_instrumented_alloc_la_LIBADD = $(BACKTRACE_FILE) $(FORMAT_FILE) \
+	read.lo instrumented_alloc.lo
+
+libbacktrace_instrumented_alloc_la_DEPENDENCIES = \
+	$(libbacktrace_instrumented_alloc_la_LIBADD)
+
+instrumented_alloc.lo: alloc.c
+
+allocfail_SOURCES = allocfail.c testlib.c
+allocfail_LDADD = libbacktrace_instrumented_alloc.la
+
+check_PROGRAMS += allocfail
+
+allocfail.sh: allocfail
+
+TESTS += allocfail.sh
+
 btest_SOURCES = btest.c testlib.c
 btest_CFLAGS = $(AM_CFLAGS) -g -O
 btest_LDADD = libbacktrace.la
diff --git a/libbacktrace/Makefile.in b/libbacktrace/Makefile.in
index 6eaa1e28c01..7b18b9834e0 100644
--- a/libbacktrace/Makefile.in
+++ b/libbacktrace/Makefile.in
@@ -123,13 +123,14 @@ target_triplet = @target@
 check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3)
 @NATIVE_TRUE@am__append_1 = test_elf test_xcoff_32 test_xcoff_64 \
 @NATIVE_TRUE@	test_pecoff test_unknown unittest unittest_alloc \
-@NATIVE_TRUE@	btest btest_alloc stest stest_alloc ztest \
-@NATIVE_TRUE@	ztest_alloc edtest edtest_alloc
-@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_2 = -lz
+@NATIVE_TRUE@	allocfail btest btest_alloc stest stest_alloc \
+@NATIVE_TRUE@	ztest ztest_alloc edtest edtest_alloc
+@NATIVE_TRUE@am__append_2 = allocfail.sh
 @HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_3 = -lz
-@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__append_4 = ttest ttest_alloc
-@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_5 = dtest
-@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__append_6 = ctestg ctesta \
+@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_4 = -lz
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__append_5 = ttest ttest_alloc
+@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_6 = dtest
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__append_7 = ctestg ctesta \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctestg_alloc \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctesta_alloc
 subdir = .
@@ -169,6 +170,11 @@ am__objects_1 = atomic.lo dwarf.lo fileline.lo posix.lo print.lo \
 @NATIVE_TRUE@am_libbacktrace_alloc_la_OBJECTS = $(am__objects_1)
 libbacktrace_alloc_la_OBJECTS = $(am_libbacktrace_alloc_la_OBJECTS)
 @NATIVE_TRUE@am_libbacktrace_alloc_la_rpath =
+@NATIVE_TRUE@am_libbacktrace_instrumented_alloc_la_OBJECTS =  \
+@NATIVE_TRUE@	$(am__objects_1)
+libbacktrace_instrumented_alloc_la_OBJECTS =  \
+	$(am_libbacktrace_instrumented_alloc_la_OBJECTS)
+@NATIVE_TRUE@am_libbacktrace_instrumented_alloc_la_rpath =
 @NATIVE_TRUE@am_libbacktrace_noformat_la_OBJECTS = $(am__objects_1)
 libbacktrace_noformat_la_OBJECTS =  \
 	$(am_libbacktrace_noformat_la_OBJECTS)
@@ -176,11 +182,11 @@ libbacktrace_noformat_la_OBJECTS =  \
 @NATIVE_TRUE@am__EXEEXT_1 = test_elf$(EXEEXT) test_xcoff_32$(EXEEXT) \
 @NATIVE_TRUE@	test_xcoff_64$(EXEEXT) test_pecoff$(EXEEXT) \
 @NATIVE_TRUE@	test_unknown$(EXEEXT) unittest$(EXEEXT) \
-@NATIVE_TRUE@	unittest_alloc$(EXEEXT) btest$(EXEEXT) \
-@NATIVE_TRUE@	btest_alloc$(EXEEXT) stest$(EXEEXT) \
-@NATIVE_TRUE@	stest_alloc$(EXEEXT) ztest$(EXEEXT) \
-@NATIVE_TRUE@	ztest_alloc$(EXEEXT) edtest$(EXEEXT) \
-@NATIVE_TRUE@	edtest_alloc$(EXEEXT)
+@NATIVE_TRUE@	unittest_alloc$(EXEEXT) allocfail$(EXEEXT) \
+@NATIVE_TRUE@	btest$(EXEEXT) btest_alloc$(EXEEXT) \
+@NATIVE_TRUE@	stest$(EXEEXT) stest_alloc$(EXEEXT) \
+@NATIVE_TRUE@	ztest$(EXEEXT) ztest_alloc$(EXEEXT) \
+@NATIVE_TRUE@	edtest$(EXEEXT) edtest_alloc$(EXEEXT)
 @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__EXEEXT_2 = ttest$(EXEEXT) \
 @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@	ttest_alloc$(EXEEXT)
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__EXEEXT_3 =  \
@@ -188,6 +194,11 @@ libbacktrace_noformat_la_OBJECTS =  \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctesta$(EXEEXT) \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctestg_alloc$(EXEEXT) \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctesta_alloc$(EXEEXT)
+@NATIVE_TRUE@am_allocfail_OBJECTS = allocfail.$(OBJEXT) \
+@NATIVE_TRUE@	testlib.$(OBJEXT)
+allocfail_OBJECTS = $(am_allocfail_OBJECTS)
+@NATIVE_TRUE@allocfail_DEPENDENCIES =  \
+@NATIVE_TRUE@	libbacktrace_instrumented_alloc.la
 @NATIVE_TRUE@am_btest_OBJECTS = btest-btest.$(OBJEXT) \
 @NATIVE_TRUE@	btest-testlib.$(OBJEXT)
 btest_OBJECTS = $(am_btest_OBJECTS)
@@ -356,8 +367,9 @@ am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
 SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \
 	$(libbacktrace_alloc_la_SOURCES) \
-	$(libbacktrace_noformat_la_SOURCES) $(btest_SOURCES) \
-	$(btest_alloc_SOURCES) $(ctesta_SOURCES) \
+	$(libbacktrace_instrumented_alloc_la_SOURCES) \
+	$(libbacktrace_noformat_la_SOURCES) $(allocfail_SOURCES) \
+	$(btest_SOURCES) $(btest_alloc_SOURCES) $(ctesta_SOURCES) \
 	$(ctesta_alloc_SOURCES) $(ctestg_SOURCES) \
 	$(ctestg_alloc_SOURCES) $(edtest_SOURCES) \
 	$(edtest_alloc_SOURCES) $(stest_SOURCES) \
@@ -774,9 +786,10 @@ libbacktrace_la_LIBADD = \
 	$(ALLOC_FILE)
 
 libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD)
-TESTS = $(check_PROGRAMS) $(am__append_5)
+TESTS = $(check_PROGRAMS) $(am__append_2) $(am__append_6)
 @NATIVE_TRUE@check_LTLIBRARIES = libbacktrace_alloc.la \
-@NATIVE_TRUE@	libbacktrace_noformat.la
+@NATIVE_TRUE@	libbacktrace_noformat.la \
+@NATIVE_TRUE@	libbacktrace_instrumented_alloc.la
 @NATIVE_TRUE@libbacktrace_alloc_la_SOURCES = $(libbacktrace_la_SOURCES)
 @NATIVE_TRUE@libbacktrace_alloc_la_LIBADD = $(BACKTRACE_FILE) $(FORMAT_FILE) read.lo alloc.lo
 @NATIVE_TRUE@libbacktrace_alloc_la_DEPENDENCIES = $(libbacktrace_alloc_la_LIBADD)
@@ -797,6 +810,15 @@ TESTS = $(check_PROGRAMS) $(am__append_5)
 @NATIVE_TRUE@unittest_LDADD = libbacktrace.la
 @NATIVE_TRUE@unittest_alloc_SOURCES = $(unittest_SOURCES)
 @NATIVE_TRUE@unittest_alloc_LDADD = libbacktrace_alloc.la
+@NATIVE_TRUE@libbacktrace_instrumented_alloc_la_SOURCES = $(libbacktrace_la_SOURCES)
+@NATIVE_TRUE@libbacktrace_instrumented_alloc_la_LIBADD = $(BACKTRACE_FILE) $(FORMAT_FILE) \
+@NATIVE_TRUE@	read.lo instrumented_alloc.lo
+
+@NATIVE_TRUE@libbacktrace_instrumented_alloc_la_DEPENDENCIES = \
+@NATIVE_TRUE@	$(libbacktrace_instrumented_alloc_la_LIBADD)
+
+@NATIVE_TRUE@allocfail_SOURCES = allocfail.c testlib.c
+@NATIVE_TRUE@allocfail_LDADD = libbacktrace_instrumented_alloc.la
 @NATIVE_TRUE@btest_SOURCES = btest.c testlib.c
 @NATIVE_TRUE@btest_CFLAGS = $(AM_CFLAGS) -g -O
 @NATIVE_TRUE@btest_LDADD = libbacktrace.la
@@ -809,9 +831,9 @@ TESTS = $(check_PROGRAMS) $(am__append_5)
 @NATIVE_TRUE@stest_alloc_LDADD = libbacktrace_alloc.la
 @NATIVE_TRUE@ztest_SOURCES = ztest.c testlib.c
 @NATIVE_TRUE@ztest_CFLAGS = -DSRCDIR=\"$(srcdir)\"
-@NATIVE_TRUE@ztest_LDADD = libbacktrace.la $(am__append_2) \
+@NATIVE_TRUE@ztest_LDADD = libbacktrace.la $(am__append_3) \
 @NATIVE_TRUE@	$(CLOCK_GETTIME_LINK)
-@NATIVE_TRUE@ztest_alloc_LDADD = libbacktrace_alloc.la $(am__append_3) \
+@NATIVE_TRUE@ztest_alloc_LDADD = libbacktrace_alloc.la $(am__append_4) \
 @NATIVE_TRUE@	$(CLOCK_GETTIME_LINK)
 @NATIVE_TRUE@ztest_alloc_SOURCES = $(ztest_SOURCES)
 @NATIVE_TRUE@ztest_alloc_CFLAGS = $(ztest_CFLAGS)
@@ -945,6 +967,9 @@ libbacktrace.la: $(libbacktrace_la_OBJECTS) $(libbacktrace_la_DEPENDENCIES) $(EX
 libbacktrace_alloc.la: $(libbacktrace_alloc_la_OBJECTS) $(libbacktrace_alloc_la_DEPENDENCIES) $(EXTRA_libbacktrace_alloc_la_DEPENDENCIES) 
 	$(AM_V_CCLD)$(LINK) $(am_libbacktrace_alloc_la_rpath) $(libbacktrace_alloc_la_OBJECTS) $(libbacktrace_alloc_la_LIBADD) $(LIBS)
 
+libbacktrace_instrumented_alloc.la: $(libbacktrace_instrumented_alloc_la_OBJECTS) $(libbacktrace_instrumented_alloc_la_DEPENDENCIES) $(EXTRA_libbacktrace_instrumented_alloc_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(LINK) $(am_libbacktrace_instrumented_alloc_la_rpath) $(libbacktrace_instrumented_alloc_la_OBJECTS) $(libbacktrace_instrumented_alloc_la_LIBADD) $(LIBS)
+
 libbacktrace_noformat.la: $(libbacktrace_noformat_la_OBJECTS) $(libbacktrace_noformat_la_DEPENDENCIES) $(EXTRA_libbacktrace_noformat_la_DEPENDENCIES) 
 	$(AM_V_CCLD)$(LINK) $(am_libbacktrace_noformat_la_rpath) $(libbacktrace_noformat_la_OBJECTS) $(libbacktrace_noformat_la_LIBADD) $(LIBS)
 
@@ -957,6 +982,10 @@ clean-checkPROGRAMS:
 	echo " rm -f" $$list; \
 	rm -f $$list
 
+allocfail$(EXEEXT): $(allocfail_OBJECTS) $(allocfail_DEPENDENCIES) $(EXTRA_allocfail_DEPENDENCIES) 
+	@rm -f allocfail$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(allocfail_OBJECTS) $(allocfail_LDADD) $(LIBS)
+
 btest$(EXEEXT): $(btest_OBJECTS) $(btest_DEPENDENCIES) $(EXTRA_btest_DEPENDENCIES) 
 	@rm -f btest$(EXEEXT)
 	$(AM_V_CCLD)$(btest_LINK) $(btest_OBJECTS) $(btest_LDADD) $(LIBS)
@@ -1434,6 +1463,13 @@ unittest_alloc.log: unittest_alloc$(EXEEXT)
 	--log-file $$b.log --trs-file $$b.trs \
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
 	"$$tst" $(AM_TESTS_FD_REDIRECT)
+allocfail.log: allocfail$(EXEEXT)
+	@p='allocfail$(EXEEXT)'; \
+	b='allocfail'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
 btest.log: btest$(EXEEXT)
 	@p='btest$(EXEEXT)'; \
 	b='btest'; \
@@ -1532,6 +1568,13 @@ ctesta_alloc.log: ctesta_alloc$(EXEEXT)
 	--log-file $$b.log --trs-file $$b.trs \
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
 	"$$tst" $(AM_TESTS_FD_REDIRECT)
+allocfail.sh.log: allocfail.sh
+	@p='allocfail.sh'; \
+	b='allocfail.sh'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
 dtest.log: dtest
 	@p='dtest'; \
 	b='dtest'; \
@@ -1695,6 +1738,10 @@ uninstall-am:
 @NATIVE_TRUE@		$(srcdir)/xcoff.c \
 @NATIVE_TRUE@		> $@
 
+@NATIVE_TRUE@instrumented_alloc.lo: alloc.c
+
+@NATIVE_TRUE@allocfail.sh: allocfail
+
 @NATIVE_TRUE@edtest2_build.c: gen_edtest2_build; @true
 @NATIVE_TRUE@gen_edtest2_build: $(srcdir)/edtest2.c
 @NATIVE_TRUE@	cat $(srcdir)/edtest2.c > tmp-edtest2_build.c
diff --git a/libbacktrace/allocfail.c b/libbacktrace/allocfail.c
new file mode 100644
index 00000000000..e9149ab977d
--- /dev/null
+++ b/libbacktrace/allocfail.c
@@ -0,0 +1,136 @@
+/* allocfail.c -- Test for libbacktrace library
+   Copyright (C) 2018 Free Software Foundation, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "filenames.h"
+
+#include "backtrace.h"
+#include "backtrace-supported.h"
+
+#include "testlib.h"
+
+extern uint64_t get_nr_allocs (void);
+extern void set_fail_at_alloc (uint64_t);
+extern int at_fail_alloc_p (void);
+
+static int test1 (void) __attribute__ ((noinline, unused));
+static int f2 (int) __attribute__ ((noinline));
+static int f3 (int, int) __attribute__ ((noinline));
+
+static unsigned callback_errors = 0;
+
+static void
+error_callback_full (void *vdata ATTRIBUTE_UNUSED,
+		     const char *msg ATTRIBUTE_UNUSED,
+		     int errnum ATTRIBUTE_UNUSED)
+{
+  if (at_fail_alloc_p ())
+    {
+      set_fail_at_alloc (0);
+      return;
+    }
+
+  callback_errors++;
+}
+
+static int
+callback_full (void *vdata ATTRIBUTE_UNUSED, uintptr_t pc ATTRIBUTE_UNUSED,
+	      const char *filename ATTRIBUTE_UNUSED,
+	      int lineno ATTRIBUTE_UNUSED,
+	      const char *function ATTRIBUTE_UNUSED)
+{
+
+  return 0;
+}
+
+static int
+test1 (void)
+{
+  return f2 (__LINE__) + 1;
+}
+
+static int
+f2 (int f1line)
+{
+  return f3 (f1line, __LINE__) + 2;
+}
+
+static int
+f3 (int f1line ATTRIBUTE_UNUSED, int f2line ATTRIBUTE_UNUSED)
+{
+  int i;
+
+  i = backtrace_full (state, 0, callback_full, error_callback_full, NULL);
+
+  if (i != 0)
+    {
+      fprintf (stderr, "test1: unexpected return value %d\n", i);
+      ++failures;
+    }
+
+  if (callback_errors)
+      ++failures;
+
+  return failures;
+}
+
+/* Run all the tests.  */
+
+int
+main (int argc, char **argv)
+{
+  uint64_t fail_at = 0;
+
+  if (argc == 2)
+    {
+      fail_at = atoi (argv[1]);
+      set_fail_at_alloc (fail_at);
+    }
+
+  state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
+				  error_callback_full, NULL);
+  if (state == NULL)
+    exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
+
+#if BACKTRACE_SUPPORTED
+  test1 ();
+#endif
+
+  if (argc == 1)
+    fprintf (stderr, "%lu\n", get_nr_allocs ());
+
+  exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
+}
diff --git a/libbacktrace/allocfail.sh b/libbacktrace/allocfail.sh
new file mode 100755
index 00000000000..91bc7a3e73d
--- /dev/null
+++ b/libbacktrace/allocfail.sh
@@ -0,0 +1,105 @@
+#!/bin/sh
+
+# allocfail.sh -- Test for libbacktrace library.
+# Copyright (C) 2018 Free Software Foundation, Inc.
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+
+#     (1) Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+
+#     (2) Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in
+#     the documentation and/or other materials provided with the
+#     distribution.
+
+#     (3) The name of the author may not be used to
+#     endorse or promote products derived from this software without
+#     specific prior written permission.
+
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+set -e
+set -o pipefail
+
+if [ ! -f ./allocfail ]; then
+    # Hard failure.
+    exit 99
+fi
+
+allocs=$(./allocfail 2>&1)
+if [ "$allocs" = "" ]; then
+    # Hard failure.
+    exit 99
+fi
+
+# This generates the following output:
+# ...
+# $ allocfail.sh
+# allocs: 80495
+# Status changed to 0 at 1
+# Status changed to 1 at 3
+# Status changed to 0 at 11
+# Status changed to 1 at 12
+# Status changed to 0 at 845
+# ...
+#
+# We have status 0 for an allocation failure at:
+# - 1 because backtrace_create_state handles failure robustly
+# - 2 because the fail switches backtrace_full to !can_alloc mode.
+# - 11 because failure of elf_open_debugfile_by_buildid does not generate an
+#   error callback beyond the one for the allocation failure itself.
+
+echo "allocs: $allocs"
+
+step=1
+i=1
+passes=0
+prev_status=-1
+while [ $i -le $allocs ]; do
+    if ./allocfail $i >/dev/null 2>&1; status=$?; then
+	true
+    fi
+    if [ $status -gt 1 ]; then
+	echo "Unallowed fail found: $i"
+	# Failure.
+	exit 1
+    fi
+
+    # The test-case would run too long if we would excercise all allocs.
+    # So, run with step 1 initially, and increase the step once we have 10
+    # subsequent passes, and drop back to step 1 once we encounter another
+    # failure.  This takes ~2.6 seconds on an i7-6600U CPU @ 2.60GHz.
+    if [ $status -eq 0 ]; then
+	passes=$(($passes + 1))
+	if [ $passes -ge 10 ]; then
+	    step=$((step * 10))
+	    passes=0
+	fi
+    elif [ $status -eq 1 ]; then
+	passes=0
+	step=1
+    fi
+
+    if [ $status -ne $prev_status ]; then
+	echo "Status changed to $status at $i"
+    fi
+    prev_status=$status
+
+    i=$(($i + $step))
+done
+
+# Success.
+exit 0
diff --git a/libbacktrace/instrumented_alloc.c b/libbacktrace/instrumented_alloc.c
new file mode 100644
index 00000000000..ba42ea65a04
--- /dev/null
+++ b/libbacktrace/instrumented_alloc.c
@@ -0,0 +1,114 @@
+/* instrumented_alloc.c -- Memory allocation instrumented to fail when
+   requested, for testing purposes.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+/* Include all the header files of alloc here, to make sure they're not
+   processed when including alloc.c below, such that the redefinitions of malloc
+   and realloc are only effective in alloc.c itself.  This does not work for
+   config.h, because it's not wrapped in "#ifndef CONFIG_H\n#define CONFIG_H"
+   and "#endif" but that does not seem to be harmful.  */
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <inttypes.h>
+
+#include "backtrace.h"
+#include "internal.h"
+
+extern void *instrumented_malloc (size_t size);
+extern void *instrumented_realloc (void *ptr, size_t size);
+
+#define malloc instrumented_malloc
+#define realloc instrumented_realloc
+#include "alloc.c"
+#undef malloc
+#undef realloc
+
+static uint64_t nr_allocs = 0;
+static uint64_t fail_at_alloc = 0;
+
+extern int at_fail_alloc_p (void);
+extern uint64_t get_nr_allocs (void);
+extern void set_fail_at_alloc (uint64_t);
+
+void *
+instrumented_malloc (size_t size)
+{
+  void *res;
+
+  if (at_fail_alloc_p ())
+    return NULL;
+
+  res = malloc (size);
+  if (res != NULL)
+    nr_allocs++;
+
+  return res;
+}
+
+void *
+instrumented_realloc (void *ptr, size_t size)
+{
+  void *res;
+
+  if (size != 0)
+    {
+      if (at_fail_alloc_p ())
+	return NULL;
+    }
+
+  res = realloc (ptr, size);
+  if (res != NULL)
+    nr_allocs++;
+
+  return res;
+}
+
+int
+at_fail_alloc_p (void)
+{
+  return fail_at_alloc == nr_allocs + 1;
+}
+
+uint64_t
+get_nr_allocs (void)
+{
+  return nr_allocs;
+}
+
+void
+set_fail_at_alloc (uint64_t nr)
+{
+  fail_at_alloc = nr;
+}
Li, Pan2 via Gcc-patches Dec. 12, 2018, 1:40 p.m. UTC | #4
On Tue, Dec 11, 2018 at 11:04 PM Tom de Vries <tdevries@suse.de> wrote:
>
> [ Fixed ENOPATCH ]
>
> On 12-12-18 08:03, Tom de Vries wrote:
> > On 11-12-18 18:59, Ian Lance Taylor wrote:
> >> On Wed, Nov 28, 2018 at 4:50 AM Tom de Vries <tdevries@suse.de> wrote:
> >>>
> >>> Add test-case that forces alloc.c functions to fail, and check whether fail
> >>> handling is robust.
> >>>
> >>> This is the test-case for "[libbacktrace] Fix segfault upon allocation
> >>> failure".  Without that patch, this test-case fails like this:
> >>> ...
> >>> allocfail.sh: line 71: 26041 Segmentation fault      (core dumped) \
> >>>   ./allocfail $i > /dev/null 2>&1
> >>> Unallowed fail found: 13
> >>> FAIL allocfail.sh (exit status: 1)
> >>> ...
> >>>
> >>> This is a seperate patch because the test-case is nontrivial.
> >>>
> >>> Bootstrapped and reg-tested on x86_64.
> >>>
> >>> OK for trunk?
> >>>
> >>> Thanks,
> >>> - Tom
> >>>
> >>> [libbacktrace] Add allocfail.sh test-case
> >>>
> >>> 2018-11-27  Tom de Vries  <tdevries@suse.de>
> >>>
> >>>         * Makefile.am (TESTS): Add allocfail.sh.
> >>>         (check_PROGRAMS): Add allocfail.
> >>>         * Makefile.in: Regenerate.
> >>>         * instrumented_alloc.c: New file.  Redefine malloc and realloc.
> >>>         Include alloc.c.
> >>>         * allocfail.c: New file.
> >>>         * allocfail.sh: New file.
> >>
> >> Can you redo this without using GNU make features like $(filter-out) ?
> >
> > Hi,
> >
> > Done, and re-bootstrapped-and-regtested.
> >
> > OK for trunk?

This is OK.

Thanks.

Ian
diff mbox series

Patch

diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am
index 13e94f27aef..fdda769f18b 100644
--- a/libbacktrace/Makefile.am
+++ b/libbacktrace/Makefile.am
@@ -94,6 +94,21 @@  unittest_LDADD = libbacktrace.la
 
 check_PROGRAMS += unittest
 
+libbacktrace_without_alloc = $(libbacktrace_la_OBJECTS) \
+	$(filter-out alloc.lo read.lo mmap.lo mmapio.lo, \
+		$(libbacktrace_la_LIBADD))
+
+instrumented_alloc.lo: alloc.c
+
+allocfail_SOURCES = allocfail.c testlib.c
+allocfail_LDADD = $(libbacktrace_without_alloc) instrumented_alloc.lo read.lo
+
+check_PROGRAMS += allocfail
+
+allocfail.sh: allocfail
+
+TESTS += allocfail.sh
+
 btest_SOURCES = btest.c testlib.c
 btest_CFLAGS = $(AM_CFLAGS) -g -O
 btest_LDADD = libbacktrace.la
diff --git a/libbacktrace/Makefile.in b/libbacktrace/Makefile.in
index 2d62ce20b9a..49f28395686 100644
--- a/libbacktrace/Makefile.in
+++ b/libbacktrace/Makefile.in
@@ -121,11 +121,13 @@  build_triplet = @build@
 host_triplet = @host@
 target_triplet = @target@
 check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3)
-@NATIVE_TRUE@am__append_1 = unittest btest stest ztest edtest
-@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_2 = -lz
-@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__append_3 = ttest
-@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_4 = dtest
-@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__append_5 = ctestg ctesta
+@NATIVE_TRUE@am__append_1 = unittest allocfail btest stest ztest \
+@NATIVE_TRUE@	edtest
+@NATIVE_TRUE@am__append_2 = allocfail.sh
+@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_3 = -lz
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__append_4 = ttest
+@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_5 = dtest
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__append_6 = ctestg ctesta
 subdir = .
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/../config/cet.m4 \
@@ -158,12 +160,18 @@  AM_V_lt = $(am__v_lt_@AM_V@)
 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
 am__v_lt_0 = --silent
 am__v_lt_1 = 
-@NATIVE_TRUE@am__EXEEXT_1 = unittest$(EXEEXT) btest$(EXEEXT) \
-@NATIVE_TRUE@	stest$(EXEEXT) ztest$(EXEEXT) edtest$(EXEEXT)
+@NATIVE_TRUE@am__EXEEXT_1 = unittest$(EXEEXT) allocfail$(EXEEXT) \
+@NATIVE_TRUE@	btest$(EXEEXT) stest$(EXEEXT) ztest$(EXEEXT) \
+@NATIVE_TRUE@	edtest$(EXEEXT)
 @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__EXEEXT_2 = ttest$(EXEEXT)
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__EXEEXT_3 =  \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctestg$(EXEEXT) \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctesta$(EXEEXT)
+@NATIVE_TRUE@am_allocfail_OBJECTS = allocfail.$(OBJEXT) \
+@NATIVE_TRUE@	testlib.$(OBJEXT)
+allocfail_OBJECTS = $(am_allocfail_OBJECTS)
+@NATIVE_TRUE@allocfail_DEPENDENCIES = $(libbacktrace_without_alloc) \
+@NATIVE_TRUE@	instrumented_alloc.lo read.lo
 @NATIVE_TRUE@am_btest_OBJECTS = btest-btest.$(OBJEXT) \
 @NATIVE_TRUE@	btest-testlib.$(OBJEXT)
 btest_OBJECTS = $(am_btest_OBJECTS)
@@ -248,9 +256,9 @@  am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
 am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
 SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \
-	$(btest_SOURCES) $(ctesta_SOURCES) $(ctestg_SOURCES) \
-	$(edtest_SOURCES) $(stest_SOURCES) $(ttest_SOURCES) \
-	$(unittest_SOURCES) $(ztest_SOURCES)
+	$(allocfail_SOURCES) $(btest_SOURCES) $(ctesta_SOURCES) \
+	$(ctestg_SOURCES) $(edtest_SOURCES) $(stest_SOURCES) \
+	$(ttest_SOURCES) $(unittest_SOURCES) $(ztest_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -658,9 +666,15 @@  libbacktrace_la_LIBADD = \
 	$(ALLOC_FILE)
 
 libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD)
-TESTS = $(check_PROGRAMS) $(am__append_4)
+TESTS = $(check_PROGRAMS) $(am__append_2) $(am__append_5)
 @NATIVE_TRUE@unittest_SOURCES = unittest.c testlib.c
 @NATIVE_TRUE@unittest_LDADD = libbacktrace.la
+@NATIVE_TRUE@libbacktrace_without_alloc = $(libbacktrace_la_OBJECTS) \
+@NATIVE_TRUE@	$(filter-out alloc.lo read.lo mmap.lo mmapio.lo, \
+@NATIVE_TRUE@		$(libbacktrace_la_LIBADD))
+
+@NATIVE_TRUE@allocfail_SOURCES = allocfail.c testlib.c
+@NATIVE_TRUE@allocfail_LDADD = $(libbacktrace_without_alloc) instrumented_alloc.lo read.lo
 @NATIVE_TRUE@btest_SOURCES = btest.c testlib.c
 @NATIVE_TRUE@btest_CFLAGS = $(AM_CFLAGS) -g -O
 @NATIVE_TRUE@btest_LDADD = libbacktrace.la
@@ -668,7 +682,7 @@  TESTS = $(check_PROGRAMS) $(am__append_4)
 @NATIVE_TRUE@stest_LDADD = libbacktrace.la
 @NATIVE_TRUE@ztest_SOURCES = ztest.c testlib.c
 @NATIVE_TRUE@ztest_CFLAGS = -DSRCDIR=\"$(srcdir)\"
-@NATIVE_TRUE@ztest_LDADD = libbacktrace.la $(am__append_2) \
+@NATIVE_TRUE@ztest_LDADD = libbacktrace.la $(am__append_3) \
 @NATIVE_TRUE@	$(CLOCK_GETTIME_LINK)
 @NATIVE_TRUE@edtest_SOURCES = edtest.c edtest2_build.c testlib.c
 @NATIVE_TRUE@edtest_LDADD = libbacktrace.la
@@ -782,6 +796,10 @@  clean-checkPROGRAMS:
 	echo " rm -f" $$list; \
 	rm -f $$list
 
+allocfail$(EXEEXT): $(allocfail_OBJECTS) $(allocfail_DEPENDENCIES) $(EXTRA_allocfail_DEPENDENCIES) 
+	@rm -f allocfail$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(allocfail_OBJECTS) $(allocfail_LDADD) $(LIBS)
+
 btest$(EXEEXT): $(btest_OBJECTS) $(btest_DEPENDENCIES) $(EXTRA_btest_DEPENDENCIES) 
 	@rm -f btest$(EXEEXT)
 	$(AM_V_CCLD)$(btest_LINK) $(btest_OBJECTS) $(btest_LDADD) $(LIBS)
@@ -1105,6 +1123,13 @@  unittest.log: unittest$(EXEEXT)
 	--log-file $$b.log --trs-file $$b.trs \
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
 	"$$tst" $(AM_TESTS_FD_REDIRECT)
+allocfail.log: allocfail$(EXEEXT)
+	@p='allocfail$(EXEEXT)'; \
+	b='allocfail'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
 btest.log: btest$(EXEEXT)
 	@p='btest$(EXEEXT)'; \
 	b='btest'; \
@@ -1154,6 +1179,13 @@  ctesta.log: ctesta$(EXEEXT)
 	--log-file $$b.log --trs-file $$b.trs \
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
 	"$$tst" $(AM_TESTS_FD_REDIRECT)
+allocfail.sh.log: allocfail.sh
+	@p='allocfail.sh'; \
+	b='allocfail.sh'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
 dtest.log: dtest
 	@p='dtest'; \
 	b='dtest'; \
@@ -1309,6 +1341,10 @@  uninstall-am:
 .PRECIOUS: Makefile
 
 
+@NATIVE_TRUE@instrumented_alloc.lo: alloc.c
+
+@NATIVE_TRUE@allocfail.sh: allocfail
+
 @NATIVE_TRUE@edtest2_build.c: gen_edtest2_build; @true
 @NATIVE_TRUE@gen_edtest2_build: $(srcdir)/edtest2.c
 @NATIVE_TRUE@	cat $(srcdir)/edtest2.c > tmp-edtest2_build.c
diff --git a/libbacktrace/allocfail.c b/libbacktrace/allocfail.c
new file mode 100644
index 00000000000..e9149ab977d
--- /dev/null
+++ b/libbacktrace/allocfail.c
@@ -0,0 +1,136 @@ 
+/* allocfail.c -- Test for libbacktrace library
+   Copyright (C) 2018 Free Software Foundation, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "filenames.h"
+
+#include "backtrace.h"
+#include "backtrace-supported.h"
+
+#include "testlib.h"
+
+extern uint64_t get_nr_allocs (void);
+extern void set_fail_at_alloc (uint64_t);
+extern int at_fail_alloc_p (void);
+
+static int test1 (void) __attribute__ ((noinline, unused));
+static int f2 (int) __attribute__ ((noinline));
+static int f3 (int, int) __attribute__ ((noinline));
+
+static unsigned callback_errors = 0;
+
+static void
+error_callback_full (void *vdata ATTRIBUTE_UNUSED,
+		     const char *msg ATTRIBUTE_UNUSED,
+		     int errnum ATTRIBUTE_UNUSED)
+{
+  if (at_fail_alloc_p ())
+    {
+      set_fail_at_alloc (0);
+      return;
+    }
+
+  callback_errors++;
+}
+
+static int
+callback_full (void *vdata ATTRIBUTE_UNUSED, uintptr_t pc ATTRIBUTE_UNUSED,
+	      const char *filename ATTRIBUTE_UNUSED,
+	      int lineno ATTRIBUTE_UNUSED,
+	      const char *function ATTRIBUTE_UNUSED)
+{
+
+  return 0;
+}
+
+static int
+test1 (void)
+{
+  return f2 (__LINE__) + 1;
+}
+
+static int
+f2 (int f1line)
+{
+  return f3 (f1line, __LINE__) + 2;
+}
+
+static int
+f3 (int f1line ATTRIBUTE_UNUSED, int f2line ATTRIBUTE_UNUSED)
+{
+  int i;
+
+  i = backtrace_full (state, 0, callback_full, error_callback_full, NULL);
+
+  if (i != 0)
+    {
+      fprintf (stderr, "test1: unexpected return value %d\n", i);
+      ++failures;
+    }
+
+  if (callback_errors)
+      ++failures;
+
+  return failures;
+}
+
+/* Run all the tests.  */
+
+int
+main (int argc, char **argv)
+{
+  uint64_t fail_at = 0;
+
+  if (argc == 2)
+    {
+      fail_at = atoi (argv[1]);
+      set_fail_at_alloc (fail_at);
+    }
+
+  state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
+				  error_callback_full, NULL);
+  if (state == NULL)
+    exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
+
+#if BACKTRACE_SUPPORTED
+  test1 ();
+#endif
+
+  if (argc == 1)
+    fprintf (stderr, "%lu\n", get_nr_allocs ());
+
+  exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
+}
diff --git a/libbacktrace/allocfail.sh b/libbacktrace/allocfail.sh
new file mode 100755
index 00000000000..91bc7a3e73d
--- /dev/null
+++ b/libbacktrace/allocfail.sh
@@ -0,0 +1,105 @@ 
+#!/bin/sh
+
+# allocfail.sh -- Test for libbacktrace library.
+# Copyright (C) 2018 Free Software Foundation, Inc.
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+
+#     (1) Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+
+#     (2) Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in
+#     the documentation and/or other materials provided with the
+#     distribution.
+
+#     (3) The name of the author may not be used to
+#     endorse or promote products derived from this software without
+#     specific prior written permission.
+
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+set -e
+set -o pipefail
+
+if [ ! -f ./allocfail ]; then
+    # Hard failure.
+    exit 99
+fi
+
+allocs=$(./allocfail 2>&1)
+if [ "$allocs" = "" ]; then
+    # Hard failure.
+    exit 99
+fi
+
+# This generates the following output:
+# ...
+# $ allocfail.sh
+# allocs: 80495
+# Status changed to 0 at 1
+# Status changed to 1 at 3
+# Status changed to 0 at 11
+# Status changed to 1 at 12
+# Status changed to 0 at 845
+# ...
+#
+# We have status 0 for an allocation failure at:
+# - 1 because backtrace_create_state handles failure robustly
+# - 2 because the fail switches backtrace_full to !can_alloc mode.
+# - 11 because failure of elf_open_debugfile_by_buildid does not generate an
+#   error callback beyond the one for the allocation failure itself.
+
+echo "allocs: $allocs"
+
+step=1
+i=1
+passes=0
+prev_status=-1
+while [ $i -le $allocs ]; do
+    if ./allocfail $i >/dev/null 2>&1; status=$?; then
+	true
+    fi
+    if [ $status -gt 1 ]; then
+	echo "Unallowed fail found: $i"
+	# Failure.
+	exit 1
+    fi
+
+    # The test-case would run too long if we would excercise all allocs.
+    # So, run with step 1 initially, and increase the step once we have 10
+    # subsequent passes, and drop back to step 1 once we encounter another
+    # failure.  This takes ~2.6 seconds on an i7-6600U CPU @ 2.60GHz.
+    if [ $status -eq 0 ]; then
+	passes=$(($passes + 1))
+	if [ $passes -ge 10 ]; then
+	    step=$((step * 10))
+	    passes=0
+	fi
+    elif [ $status -eq 1 ]; then
+	passes=0
+	step=1
+    fi
+
+    if [ $status -ne $prev_status ]; then
+	echo "Status changed to $status at $i"
+    fi
+    prev_status=$status
+
+    i=$(($i + $step))
+done
+
+# Success.
+exit 0
diff --git a/libbacktrace/instrumented_alloc.c b/libbacktrace/instrumented_alloc.c
new file mode 100644
index 00000000000..ba42ea65a04
--- /dev/null
+++ b/libbacktrace/instrumented_alloc.c
@@ -0,0 +1,114 @@ 
+/* instrumented_alloc.c -- Memory allocation instrumented to fail when
+   requested, for testing purposes.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+/* Include all the header files of alloc here, to make sure they're not
+   processed when including alloc.c below, such that the redefinitions of malloc
+   and realloc are only effective in alloc.c itself.  This does not work for
+   config.h, because it's not wrapped in "#ifndef CONFIG_H\n#define CONFIG_H"
+   and "#endif" but that does not seem to be harmful.  */
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <inttypes.h>
+
+#include "backtrace.h"
+#include "internal.h"
+
+extern void *instrumented_malloc (size_t size);
+extern void *instrumented_realloc (void *ptr, size_t size);
+
+#define malloc instrumented_malloc
+#define realloc instrumented_realloc
+#include "alloc.c"
+#undef malloc
+#undef realloc
+
+static uint64_t nr_allocs = 0;
+static uint64_t fail_at_alloc = 0;
+
+extern int at_fail_alloc_p (void);
+extern uint64_t get_nr_allocs (void);
+extern void set_fail_at_alloc (uint64_t);
+
+void *
+instrumented_malloc (size_t size)
+{
+  void *res;
+
+  if (at_fail_alloc_p ())
+    return NULL;
+
+  res = malloc (size);
+  if (res != NULL)
+    nr_allocs++;
+
+  return res;
+}
+
+void *
+instrumented_realloc (void *ptr, size_t size)
+{
+  void *res;
+
+  if (size != 0)
+    {
+      if (at_fail_alloc_p ())
+	return NULL;
+    }
+
+  res = realloc (ptr, size);
+  if (res != NULL)
+    nr_allocs++;
+
+  return res;
+}
+
+int
+at_fail_alloc_p (void)
+{
+  return fail_at_alloc == nr_allocs + 1;
+}
+
+uint64_t
+get_nr_allocs (void)
+{
+  return nr_allocs;
+}
+
+void
+set_fail_at_alloc (uint64_t nr)
+{
+  fail_at_alloc = nr;
+}