Here are the programs to reproduce this bug.

mprotect.c is based on Xavier's program, but changed to take a path
from the command line and to run an infinite loop.

madvise.c is roughly based on Xavier's program, but it exercises the ma
dvise(MADV_REMOVE) case.  As this operation is only implemented by
tmpfs, you need to give it the path to a file on a tmpfs, or on a union
filesystem where the rw branch is a tmpfs.

On an SMP system they should trigger the bug in under a minute.

Ben.

-- 
Ben Hutchings
Nothing is ever a complete failure; it can always serve as a bad example.
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/limits.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>

#define handle_error_en(en, msg) \
    do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)

#define handle_error(msg) \
    do { perror(msg); exit(EXIT_FAILURE); } while (0)

static char *open_map(const char *path, int no, int size)
{
    int fd = -1;
    int flags = MAP_SHARED;
    char *addr;

    fd = open(path, O_CREAT|O_RDWR, 0600);
    if (fd < 0) {
        handle_error("open");
    }
    if (ftruncate(fd, size) < 0) {
        handle_error("ftruncate");
    }

    /* Allocate a buffer aligned on a page boundary;
       initial protection is PROT_READ | PROT_WRITE */
    addr = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, fd, 0);
    if (addr == MAP_FAILED) {
        handle_error("mmap");
    }
    close(fd);

    return addr;
}

int len = 1 << 12;

static void *thread_msync(void *arg)
{
    char *p = arg;

    if (msync(p, len, MS_SYNC) < 0) {
        handle_error("msync");
    }
    return NULL;
}

#define NB_THREADS 10000

int main(int argc, char *argv[])
{
    char *addr;
    pthread_t threads[NB_THREADS];

    addr = open_map(argv[1], 0, 256 << 12);
    printf("Start of region: 0x%lx\n", (long)addr);

    for (;;) {
	for (int i = 0; i < NB_THREADS; i++) {
	    int s;
	    int page = rand() % 256;
	    char *p  = addr + (page << 12);

	    if (mprotect(p, len, PROT_READ | PROT_WRITE) == -1) {
		handle_error("mprotect");
	    }
	    memset(p, 'a', len / 2);
	    memset(p + len / 2, 'b', len / 2);
	    if (mprotect(p, len, PROT_READ) == -1) {
		handle_error("mprotect");
	    }

	    s = pthread_create(&threads[i], NULL, &thread_msync, p);
	    if (s) {
		handle_error_en(s, "pthread_create");
	    }
	}
	for (int i = 0; i < NB_THREADS; i++) {
	    pthread_join(threads[i], NULL);
	}
    }
}
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/fcntl.h>
#include <sys/mman.h>
#include <unistd.h>

#define handle_error_en(en, msg) \
    do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)

#define handle_error(msg) \
    do { perror(msg); exit(EXIT_FAILURE); } while (0)

#define PAGE_SIZE (1 << 12)
#define MAP_SIZE (PAGE_SIZE << 8)
#define NB_THREADS 2

static int fd;
static char *addr;

static void *thread1(void *arg)
{
    for (;;) {
	int page = rand() % 256;
	char *p  = addr + page * PAGE_SIZE;

	madvise(p, PAGE_SIZE, MADV_REMOVE);
    }

    return NULL;
}

static void *thread2(void *arg)
{
    for (unsigned int i = 0; ; i++) {
	if (i & 1)
	    munmap(addr, MAP_SIZE);
	else
	    mmap(addr, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    }
    return NULL;
}

int main(int argc, char **argv)
{
    pthread_t threads[NB_THREADS];
    int s;

    fd = open(argv[1], O_CREAT|O_RDWR, 0600);
    if (fd < 0) {
        handle_error("open");
    }
    if (ftruncate(fd, MAP_SIZE) < 0) {
        handle_error("ftruncate");
    }
    addr = mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (addr == MAP_FAILED) {
        handle_error("mmap");
    }

    s = pthread_create(&threads[0], NULL, &thread1, NULL);
    if (s) {
	handle_error_en(s, "pthread_create");
    }
    s = pthread_create(&threads[1], NULL, &thread2, NULL);
    if (s) {
	handle_error_en(s, "pthread_create");
    }
    for (int i = 0; i < NB_THREADS; i++) {
        pthread_join(threads[i], NULL);
    }
    if (munmap(addr, MAP_SIZE) == -1) {
        handle_error("munmap");
    }
    printf("Closed region: 0x%lx\n", (long)addr);

    exit(EXIT_SUCCESS);    
}

Attachment: signature.asc
Description: This is a digitally signed message part

------------------------------------------------------------------------------

Reply via email to