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);
}
signature.asc
Description: This is a digitally signed message part
------------------------------------------------------------------------------
