#include <pthread.h>
#endif
+#if defined(openbsd_HOST_OS) || defined(linux_HOST_OS)
+#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
+#endif
+
+#if defined(_WIN32)
+#include <windows.h>
+#endif
+
/* -----------------------------------------------------------------------------
Result-checking malloc wrappers.
-------------------------------------------------------------------------- */
void *
stgCallocBytes (int n, int m, char *msg)
{
- int i;
- int sz = n * m;
- char* p = stgMallocBytes(sz, msg);
- for (i = 0; i < sz; i++) p[i] = 0;
- return p;
+ char *space;
+
+ if ((space = (char *) calloc((size_t) n, (size_t) m)) == NULL) {
+ /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
+ MallocFailHook((W_) n*m, msg); /*msg*/
+ stg_exit(EXIT_INTERNAL_ERROR);
+ }
+ return space;
}
/* To simplify changing the underlying allocator used
free(p);
}
-void
-_stgAssert (char *filename, unsigned int linenum)
-{
- fflush(stdout);
- fprintf(stderr, "ASSERTION FAILED: file %s, line %u\n", filename, linenum);
- fflush(stderr);
- abort();
-}
-
/* -----------------------------------------------------------------------------
Stack overflow
if (now == 0) {
time(&now);
+#if HAVE_CTIME_R
+ ctime_r(&now, nowstr);
+#else
strcpy(nowstr, ctime(&now));
- strcpy(nowstr+16,nowstr+19);
- nowstr[21] = '\0';
+#endif
+ memmove(nowstr+16,nowstr+19,7);
+ nowstr[21] = '\0'; // removes the \n
}
return nowstr;
}
return raise(sig);
#endif
}
+
+/* -----------------------------------------------------------------------------
+ Allocating executable memory
+ -------------------------------------------------------------------------- */
+
+/* Heavily arch-specific, I'm afraid.. */
+
+/*
+ * Allocate len bytes which are readable, writable, and executable.
+ *
+ * ToDo: If this turns out to be a performance bottleneck, one could
+ * e.g. cache the last VirtualProtect/mprotect-ed region and do
+ * nothing in case of a cache hit.
+ */
+void*
+stgMallocBytesRWX(int len)
+{
+ void *addr = stgMallocBytes(len, "mallocBytesRWX");
+#if defined(i386_HOST_ARCH) && defined(_WIN32)
+ /* This could be necessary for processors which distinguish between READ and
+ EXECUTE memory accesses, e.g. Itaniums. */
+ DWORD dwOldProtect = 0;
+ if (VirtualProtect (addr, len, PAGE_EXECUTE_READWRITE, &dwOldProtect) == 0) {
+ barf("mallocBytesRWX: failed to protect 0x%p; error=%lu; old protection: %lu\n",
+ addr, (unsigned long)GetLastError(), (unsigned long)dwOldProtect);
+ }
+#elif defined(openbsd_HOST_OS) || defined(linux_HOST_OS)
+ /* malloced memory isn't executable by default on OpenBSD */
+ my_uintptr_t pageSize = sysconf(_SC_PAGESIZE);
+ my_uintptr_t mask = ~(pageSize - 1);
+ my_uintptr_t startOfFirstPage = ((my_uintptr_t)addr ) & mask;
+ my_uintptr_t startOfLastPage = ((my_uintptr_t)addr + len - 1) & mask;
+ my_uintptr_t size = startOfLastPage - startOfFirstPage + pageSize;
+ if (mprotect((void*)startOfFirstPage, (size_t)size, PROT_EXEC | PROT_READ | PROT_WRITE) != 0) {
+ barf("mallocBytesRWX: failed to protect 0x%p\n", addr);
+ }
+#endif
+ return addr;
+}