summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan C. Underwood <nemesis@icequake.net>2018-03-18 07:00:42 -0700
committerAnthony Green <green@moxielogic.com>2018-03-18 10:00:42 -0400
commitd46406088d28b038a0a0f7396d9621f431482f6a (patch)
tree5a69e20824fa22b1bd37580efc116bc0297599ce
parent247e44b3ef653f210de614a749b71449b8c70764 (diff)
downloadlibffi-d46406088d28b038a0a0f7396d9621f431482f6a.tar.gz
Fully allocate file backing writable maps (#389)
When ftruncate() is used on a filesystem supporting sparse files, space in the file is not actually allocated. Then, when the file is mmap'd and libffi writes to the mapping, SIGBUS is thrown to the calling application. Instead, always fully allocate the file that will back writable maps.
-rw-r--r--src/closures.c32
1 files changed, 31 insertions, 1 deletions
diff --git a/src/closures.c b/src/closures.c
index 59ce828..15e6e0f 100644
--- a/src/closures.c
+++ b/src/closures.c
@@ -723,6 +723,36 @@ open_temp_exec_file (void)
return fd;
}
+/* We need to allocate space in a file that will be backing a writable
+ mapping. Several problems exist with the usual approaches:
+ - fallocate() is Linux-only
+ - posix_fallocate() is not available on all platforms
+ - ftruncate() does not allocate space on filesystems with sparse files
+ Failure to allocate the space will cause SIGBUS to be thrown when
+ the mapping is subsequently written to. */
+static int
+allocate_space (int fd, off_t offset, off_t len)
+{
+ static size_t page_size;
+
+ /* Obtain system page size. */
+ if (!page_size)
+ page_size = sysconf(_SC_PAGESIZE);
+
+ unsigned char buf[page_size];
+ memset (buf, 0, page_size);
+
+ while (len > 0)
+ {
+ off_t to_write = (len < page_size) ? len : page_size;
+ if (write (fd, buf, to_write) < to_write)
+ return -1;
+ len -= to_write;
+ }
+
+ return 0;
+}
+
/* Map in a chunk of memory from the temporary exec file into separate
locations in the virtual memory address space, one writable and one
executable. Returns the address of the writable portion, after
@@ -744,7 +774,7 @@ dlmmap_locked (void *start, size_t length, int prot, int flags, off_t offset)
offset = execsize;
- if (ftruncate (execfd, offset + length))
+ if (allocate_space (execfd, offset, length))
return MFAIL;
flags &= ~(MAP_PRIVATE | MAP_ANONYMOUS);