qemu/linux-user
vincent 4d1de87c75 linux-user: Fix the computation of the requested heap size
There were several remaining bugs in the previous implementation of
do_brk():

    1. the value of "new_alloc_size" was one page too large when the
       requested brk was aligned on a host page boundary.

    2. no new pages should be (re-)allocated when the requested brk is
       in the range of the pages that were already allocated
       previsouly (for the same purpose).  Technically these pages are
       never unmapped in the current implementation.

The problem/fix can be reproduced/validated with the test-suite above:

    #include <unistd.h>       /* syscall(2),      */
    #include <sys/syscall.h>  /* SYS_brk,         */
    #include <stdio.h>        /* puts(3),         */
    #include <stdlib.h>       /* exit(3), EXIT_*, */
    #include <stdint.h>       /* uint*_t,         */
    #include <sys/mman.h>     /* mmap(2), MAP_*,  */
    #include <string.h>       /* memset(3), */

    int main()
    {
        int exit_status = EXIT_SUCCESS;
        uint8_t *current_brk = 0;
        uint8_t *initial_brk;
        uint8_t *new_brk;
        uint8_t *old_brk;
        int failure = 0;
        int i;

        void test_brk(int increment, int expected_result) {
            new_brk = (uint8_t *)syscall(SYS_brk, current_brk + increment);
            if ((new_brk == current_brk) == expected_result)
                failure = 1;
            current_brk = (uint8_t *)syscall(SYS_brk, 0);
        }

        void test_result() {
            if (!failure)
                puts("OK");
            else {
                puts("failure");
                exit_status = EXIT_FAILURE;
            }
        }

        void test_title(const char *title) {
            failure = 0;
            printf("%-45s : ", title);
            fflush(stdout);
        }

        test_title("Initialization");
        test_brk(0, 1);
        initial_brk = current_brk;
        test_result();

        test_title("Don't overlap \"brk\" pages");
        test_brk(HOST_PAGE_SIZE, 1);
        test_brk(HOST_PAGE_SIZE, 1);
        test_result();

        /* Preparation for the test "Re-allocated heap is initialized".  */
        old_brk = current_brk - HOST_PAGE_SIZE;
        memset(old_brk, 0xFF, HOST_PAGE_SIZE);

        test_title("Don't allocate the same \"brk\" page twice");
        test_brk(-HOST_PAGE_SIZE, 1);
        test_brk(HOST_PAGE_SIZE, 1);
        test_result();

        test_title("Re-allocated \"brk\" pages are initialized");
        for (i = 0; i < HOST_PAGE_SIZE; i++) {
            if (old_brk[i] != 0) {
                printf("(index = %d, value = 0x%x) ", i, old_brk[i]);
                failure = 1;
                break;
            }
        }
        test_result();

        test_title("Don't allocate \"brk\" pages over \"mmap\" pages");
        new_brk = mmap(current_brk, HOST_PAGE_SIZE / 2, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
        if (new_brk == (void *) -1)
            puts("unknown");
        else {
            test_brk(HOST_PAGE_SIZE, 0);
            test_result();
        }

        test_title("All \"brk\" pages are writable (please wait)");
        if (munmap(current_brk, HOST_PAGE_SIZE / 2) != 0)
            puts("unknown");
        else {
            while (current_brk - initial_brk < 2*1024*1024*1024UL) {
                old_brk = current_brk;

                test_brk(HOST_PAGE_SIZE, -1);
                if (old_brk == current_brk)
                    break;

                for (i = 0; i < HOST_PAGE_SIZE; i++)
                    old_brk[i] = 0xAA;
            }
            puts("OK");
        }

        test_title("Maximum size of the heap > 16MB");
        failure = (current_brk - initial_brk) < 16*1024*1024;
        test_result();

        exit(exit_status);
    }

Changes introduced in patch v2:

    * extend the "brk" test-suite embedded within the commit message;

    * heap contents have to be initialized to zero, this bug was
      exposed by "tst-calloc.c" from the GNU C library;

    * don't [try to] allocate a new host page if the new "brk" is
      equal to the latest allocated host page ("brk_page"); and

    * print some debug information when DEBUGF_BRK is defined.

Signed-off-by: Cédric VINCENT <cedric.vincent@st.com>
Reviewed-by: Christophe Guillon <christophe.guillon@st.com>
Cc: Riku Voipio <riku.voipio@iki.fi>
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
2011-06-21 20:30:09 +03:00
..
alpha linux-user: untie syscalls from UID16 2011-04-26 10:15:41 +03:00
arm linux-user/arm/nwfpe: rename REG_PC to ARM_REG_PC 2011-04-25 22:15:31 +02:00
cris Revert "Get rid of _t suffix" 2009-10-01 16:12:16 -05:00
i386 Revert "Get rid of _t suffix" 2009-10-01 16:12:16 -05:00
m68k Revert "Get rid of _t suffix" 2009-10-01 16:12:16 -05:00
microblaze Revert "Get rid of _t suffix" 2009-10-01 16:12:16 -05:00
mips linux-user: fix mips and ppc to use UID16 2010-12-03 15:10:08 +02:00
mips64 Revert "Get rid of _t suffix" 2009-10-01 16:12:16 -05:00
mipsn32 Revert "Get rid of _t suffix" 2009-10-01 16:12:16 -05:00
ppc linux-user: fix mips and ppc to use UID16 2010-12-03 15:10:08 +02:00
s390x s390x: s390x-linux-user support 2011-05-20 17:35:12 +02:00
sh4 Revert "Get rid of _t suffix" 2009-10-01 16:12:16 -05:00
sparc Revert "Get rid of _t suffix" 2009-10-01 16:12:16 -05:00
sparc64 Revert "Get rid of _t suffix" 2009-10-01 16:12:16 -05:00
unicore32 unicore32: add necessry headers in linux-user/unicore32 for unicore32 support 2011-04-12 18:48:43 +00:00
x86_64 Revert "Get rid of _t suffix" 2009-10-01 16:12:16 -05:00
cpu-uname.c linux-user: adapt uname machine to emulated CPU 2010-02-06 17:19:43 +01:00
cpu-uname.h linux-user: adapt uname machine to emulated CPU 2010-02-06 17:19:43 +01:00
elfload.c linux-user: Handle images where lowest vaddr is not page aligned 2011-06-21 20:29:01 +03:00
errno_defs.h Remove unnecessary trailing newlines 2008-12-13 09:32:43 +00:00
flat.h Support for 32 bit ABI on 64 bit targets (only enabled Sparc64) 2007-10-14 16:27:31 +00:00
flatload.c linux-user/FLAT: allow targets to override FLAT processing 2011-02-09 10:33:54 +02:00
ioctls.h linux-user: add ioctl(SIOCGIWNAME, ...) support. 2011-04-26 10:15:41 +03:00
linux_loop.h Fix build failure with old kernel headers (loop.h is incompatible with 2008-05-23 16:06:43 +00:00
linuxload.c Remove dead code for ARM semihosting commandline handling 2011-01-07 18:20:57 +02:00
m68k-sim.c linux-user: Fix typo m86k -> m68k 2010-10-05 13:53:56 -05:00
main.c Command line support for altering the log file location 2011-06-15 16:51:24 +00:00
mmap.c Fix typo in comment (truely -> truly) 2011-05-08 10:02:18 +01:00
qemu-types.h linux-user: Move abi_* typedefs into qemu-types.h 2008-12-08 18:12:04 +00:00
qemu.h Fix typos in comments (neccessary -> necessary) 2011-05-08 10:02:18 +01:00
signal.c Don't translate pointer when in restore_sigcontext 2011-06-20 17:00:18 +03:00
socket.h Various linux-user structures and definitions fixes for PowerPC targets. 2007-12-10 08:24:59 +00:00
strace.c linux-user: Fix compilation for "old" linux versions 2011-05-02 10:00:01 +03:00
strace.list linux-user: improve traces 2011-04-26 10:15:40 +03:00
syscall_defs.h s390x: s390x-linux-user support 2011-05-20 17:35:12 +02:00
syscall_types.h linux-user: Implement FS_IOC_FIEMAP ioctl 2011-01-07 17:20:58 +02:00
syscall.c linux-user: Fix the computation of the requested heap size 2011-06-21 20:30:09 +03:00
target_flat.h linux-user/FLAT: allow targets to override FLAT processing 2011-02-09 10:33:54 +02:00
uaccess.c Fix missing strnlen problems 2009-07-01 18:24:44 +00:00
vm86.c Update to a hopefully more future proof FSF address 2009-07-16 20:47:01 +00:00