mmap bug?
Giorgos Keramidas
keramida at freebsd.org
Sun Jul 31 14:20:20 GMT 2005
The following program can be used to mmap() a region outside of the
current size of a file and then write to it. Should this ``expand''
the current file size? If not, should writes on this area fail?
What's more interesting is that after running it on -CURRENT, I can
write data that is "attached" to the file but this doesn't affect the
current size of the file.
The test program I used was:
# #include <sys/mman.h>
# #include <sys/stat.h>
#
# #include <err.h>
# #include <errno.h>
# #include <fcntl.h>
# #include <stdio.h>
# #include <stdlib.h>
# #include <unistd.h>
#
# static int mmap_test(char *fname, size_t offset, size_t len);
# static int mmap_dump(unsigned char *, size_t);
# static int mmap_write_test(unsigned char *, size_t);
# static void usage(void);
#
# int
# main(int argc, char *argv[])
# {
# char *fname, *errp;
# long val;
# size_t offset, len;
#
# if (argc != 4)
# usage();
#
# fname = argv[1];
#
# errno = 0;
# errp = NULL;
# val = strtol(argv[2], &errp, 0);
# if ((errp != NULL && *errp != '\0') || errno != 0)
# err(1, "strtol: %s", argv[2]);
# offset = (size_t)val;
#
# errno = 0;
# errp = NULL;
# val = strtol(argv[3], &errp, 0);
# if ((errp != NULL && *errp != '\0') || errno != 0)
# err(1, "strtol: %s", argv[3]);
# len = (size_t)val;
#
# if (mmap_test(fname, offset, len) != 0)
# exit(EXIT_FAILURE);
#
# return (0);
# }
#
# static void
# usage()
# {
# fprintf(stderr, "usage: foo file offset len\n");
# exit(EXIT_FAILURE);
# }
#
# static int
# mmap_test(char *fname, size_t offset, size_t len)
# {
# int fd;
# void *ptr;
#
# fd = open(fname, O_CREAT | O_RDWR, S_IREAD | S_IWRITE);
# if (fd == -1)
# err(1, "open: %s", fname);
#
# ptr = mmap(NULL, len, PROT_READ | PROT_WRITE,
# MAP_SHARED, fd, offset);
# if (ptr == NULL)
# err(1, "mmap");
#
# mmap_dump((unsigned char *)ptr, len);
# mmap_write_test((unsigned char *)ptr, len);
# mmap_dump((unsigned char *)ptr, len);
#
# if (munmap(ptr, len) != 0)
# err(1, "munmap");
#
# close(fd);
# return (0);
# }
#
# static int
# mmap_dump(unsigned char *p, size_t len)
# {
# size_t k;
#
# for (k = 0; k < len; k++) {
# if ((k % 16) == 0)
# printf("%08lx: ", (unsigned long)k);
# printf(" %02x", p[k]);
# if ((k % 16) == 15)
# printf("\n");
# }
# if ((k % 16) != 15)
# printf("\n");
# return (0);
# }
#
# static int
# mmap_write_test(unsigned char *p, size_t len)
# {
# size_t k;
#
# for (k = 0; k < len; k++)
# p[k] = (unsigned char)(k % 256);
# return (0);
# }
Here's a sample run:
# gothmog:/tmp/foo$ dd if=/dev/zero of=tempfile bs=512 count=10
# 10+0 records in
# 10+0 records out
# 5120 bytes transferred in 0.000575 secs (8903332 bytes/sec)
# gothmog:/tmp/foo$ ls -l tempfile
# -rw-rw-r-- 1 giorgos wheel - 5120 Jul 31 17:12 tempfile
ok, the file has been created with the right size.
# gothmog:/tmp/foo$ ./foo tempfile 5120 60
# 00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
# 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
# 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
# 00000030: 00 00 00 00 00 00 00 00 00 00 00 00
# 00000000: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
# 00000010: 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
# 00000020: 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
# 00000030: 30 31 32 33 34 35 36 37 38 39 3a 3b
mmap() succeeded and wrote after the previous end of the file.
# gothmog:/tmp/foo$ ls -l tempfile
# -rw-rw-r-- 1 giorgos wheel - 5120 Jul 31 17:12 tempfile
# gothmog:/tmp/foo$ hd tempfile
# 00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
# *
# 00001400
The size of the file is still the same!
# gothmog:/tmp/foo$ ./foo tempfile 5120 60
# 00000000: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
# 00000010: 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
# 00000020: 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
# 00000030: 30 31 32 33 34 35 36 37 38 39 3a 3b
# 00000000: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
# 00000010: 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
# 00000020: 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
# 00000030: 30 31 32 33 34 35 36 37 38 39 3a 3b
Somehow, the data written by the first mmap() is still there, but is not
visible as part of the file size or by using ``normal'' commands that
access its contents.
More information about the freebsd-current
mailing list