Thanks: Dan Berrangé for identifying the problem.
---
.gitignore | 1 +
src/command.c | 11 +++++++
tests/regressions/Makefile.am | 13 +++++++-
tests/regressions/test-big-heap.c | 69 +++++++++++++++++++++++++++++++++++++++
4 files changed, 93 insertions(+), 1 deletion(-)
create mode 100644 tests/regressions/test-big-heap.c
diff --git a/.gitignore b/.gitignore
index cb5bc49..2f571a3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -582,6 +582,7 @@ Makefile.in
/tests/regressions/rhbz914931
/tests/regressions/rhbz1044014.out
/tests/regressions/rhbz1055452
+/tests/regressions/test-big-heap
/tests/rsync/rsyncd.pid
/tests/syslinux/extlinux-guest.img
/tests/syslinux/syslinux-guest.img
diff --git a/src/command.c b/src/command.c
index 0547111..e9f357a 100644
--- a/src/command.c
+++ b/src/command.c
@@ -558,6 +558,17 @@ run_child (struct command *cmd)
}
#endif /* HAVE_SETRLIMIT */
+ /* NB: If the main process (which we have forked a copy of) uses
+ * more heap than the RLIMIT_AS we set above, then any call to
+ * malloc or any extension of the stack will fail with ENOMEM or
+ * SIGSEGV respectively. Luckily we only use RLIMIT_AS followed by
+ * execvp below, so we get away with it, but adding any code here
+ * could cause a failure.
+ *
+ * There is a regression test for this. See:
+ * tests/regressions/test-big-heap.c
+ */
+
/* Run the command. */
switch (cmd->style) {
case COMMAND_STYLE_EXECV:
diff --git a/tests/regressions/Makefile.am b/tests/regressions/Makefile.am
index 74f23dd..c4f60ae 100644
--- a/tests/regressions/Makefile.am
+++ b/tests/regressions/Makefile.am
@@ -71,6 +71,7 @@ TESTS = \
rhbz1091803.sh \
rhbz1175196.sh \
rhbz1232192.sh \
+ test-big-heap \
test-noexec-stack.pl
if HAVE_LIBVIRT
@@ -89,7 +90,8 @@ check_PROGRAMS = \
rhbz501893 \
rhbz790721 \
rhbz914931 \
- rhbz1055452
+ rhbz1055452 \
+ test-big-heap
rhbz501893_SOURCES = rhbz501893.c
rhbz501893_CPPFLAGS = \
@@ -130,5 +132,14 @@ rhbz1055452_CFLAGS = \
rhbz1055452_LDADD = \
$(top_builddir)/src/libguestfs.la
+test_big_heap_SOURCES = test-big-heap.c
+test_big_heap_CPPFLAGS = \
+ -I$(top_srcdir)/src -I$(top_builddir)/src \
+ -DGUESTFS_PRIVATE=1
+test_big_heap_CFLAGS = \
+ $(WARN_CFLAGS) $(WERROR_CFLAGS)
+test_big_heap_LDADD = \
+ $(top_builddir)/src/libguestfs.la
+
check-slow:
$(MAKE) TESTS="rhbz909624.sh" check
diff --git a/tests/regressions/test-big-heap.c b/tests/regressions/test-big-heap.c
new file mode 100644
index 0000000..ddce270
--- /dev/null
+++ b/tests/regressions/test-big-heap.c
@@ -0,0 +1,69 @@
+/* libguestfs
+ * Copyright (C) 2015 Red Hat Inc.
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* Test that allocating lots of heap in the main program doesn't cause
+ * libguestfs to fail when it runs qemu-img. When we call qemu-img,
+ * after forking but before execing, we set RLIMIT_AS to 1 GB. If the
+ * main program is using more than 1 GB, then any malloc or stack
+ * extension will fail. We get away with this by calling exec
+ * immediately after setting the rlimit, but it only just works, and
+ * this test is designed to catch any regressions.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "guestfs.h"
+#include "guestfs-internal-frontend.h"
+
+int
+main (int argc, char *argv[])
+{
+ guestfs_h *g = guestfs_create ();
+ char *mem, *fmt;
+
+ /* Make sure we're using > 1GB in the main process. */
+ mem = calloc (2 * 1024, 1024 * 1024);
+ assert (mem != NULL);
+
+ /* Do something which forks qemu-img subprocess. */
+ fmt = guestfs_disk_format (g, "/dev/null");
+ if (fmt == NULL) {
+ /* Test failed. */
+ fprintf (stderr, "%s: unexpected failure of test, see earlier messages\n",
+ argv[0]);
+ exit (EXIT_FAILURE);
+ }
+
+ if (STRNEQ (fmt, "raw")) {
+ /* Test failed. */
+ fprintf (stderr, "%s: unexpected output: expected 'raw' actual
'%s'\n",
+ argv[0], fmt);
+ exit (EXIT_FAILURE);
+ }
+
+ /* Test successful. */
+
+ free (fmt);
+ free (mem);
+ exit (EXIT_SUCCESS);
+}
--
2.5.0