summaryrefslogtreecommitdiff
path: root/rts/posix/OSMem.c
diff options
context:
space:
mode:
authorSimon Marlow <simonmar@microsoft.com>2006-05-30 10:02:11 +0000
committerSimon Marlow <simonmar@microsoft.com>2006-05-30 10:02:11 +0000
commite3c55aebd4f9ce7a5b4390d4726612865fd207f2 (patch)
tree87a1e86bc77f2c1d8d4dba8757e14fce324fe736 /rts/posix/OSMem.c
parent6b36d8ad3bfd1890583f3bcab96559f05bff332b (diff)
downloadhaskell-e3c55aebd4f9ce7a5b4390d4726612865fd207f2.tar.gz
replace stgMallocBytesRWX() with our own allocator
See bug #738 Allocating executable memory is getting more difficult these days. In particular, the default SELinux policy on Fedora Core 5 disallows making the heap (i.e. malloc()'d memory) executable, although it does apparently allow mmap()'ing anonymous executable memory by default. Previously, stgMallocBytesRWX() used malloc() underneath, and then tried to make the page holding the memory executable. This was rather hacky and fails with Fedora Core 5. This patch adds a mini-allocator for executable memory, based on the block allocator. We grab page-sized blocks and make them executable, then allocate small objects from the page. There's a simple free function, that will free whole pages back to the system when they are empty.
Diffstat (limited to 'rts/posix/OSMem.c')
-rw-r--r--rts/posix/OSMem.c52
1 files changed, 52 insertions, 0 deletions
diff --git a/rts/posix/OSMem.c b/rts/posix/OSMem.c
new file mode 100644
index 0000000000..6e8337bdc6
--- /dev/null
+++ b/rts/posix/OSMem.c
@@ -0,0 +1,52 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The University of Glasgow 2006
+ *
+ * OS-specific memory management
+ *
+ * ---------------------------------------------------------------------------*/
+
+#include "Rts.h"
+#include "OSMem.h"
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+/* no C99 header stdint.h on OpenBSD? */
+#if defined(openbsd_HOST_OS)
+typedef unsigned long my_uintptr_t;
+#else
+#include <stdint.h>
+typedef uintptr_t my_uintptr_t;
+#endif
+
+lnat getPageSize (void)
+{
+ static lnat pageSize = 0;
+ if (pageSize) {
+ return pageSize;
+ } else {
+ long ret;
+ ret = sysconf(_SC_PAGESIZE);
+ if (ret == -1) {
+ barf("getPageSize: cannot get page size");
+ }
+ return ret;
+ }
+}
+
+void setExecutable (void *p, lnat len, rtsBool exec)
+{
+ my_uintptr_t pageSize = getPageSize();
+
+ /* malloced memory isn't executable by default on OpenBSD */
+ my_uintptr_t mask = ~(pageSize - 1);
+ my_uintptr_t startOfFirstPage = ((my_uintptr_t)p ) & mask;
+ my_uintptr_t startOfLastPage = ((my_uintptr_t)p + len - 1) & mask;
+ my_uintptr_t size = startOfLastPage - startOfFirstPage + pageSize;
+ if (mprotect((void*)startOfFirstPage, (size_t)size,
+ (exec ? PROT_EXEC : 0) | PROT_READ | PROT_WRITE) != 0) {
+ barf("makeExecutable: failed to protect 0x%p\n", p);
+ }
+}