1 /*
2  *    Stack-less Just-In-Time compiler
3  *
4  *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without modification, are
7  * permitted provided that the following conditions are met:
8  *
9  *   1. Redistributions of source code must retain the above copyright notice, this list of
10  *      conditions and the following disclaimer.
11  *
12  *   2. Redistributions in binary form must reproduce the above copyright notice, this list
13  *      of conditions and the following disclaimer in the documentation and/or other materials
14  *      provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
19  * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
22  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #define SLJIT_HAS_CHUNK_HEADER
28 #define SLJIT_HAS_EXECUTABLE_OFFSET
29 
30 struct sljit_chunk_header {
31 	void *executable;
32 };
33 
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <stdio.h>
37 #include <string.h>
38 
39 #ifndef O_NOATIME
40 #define O_NOATIME 0
41 #endif
42 
43 /* this is a linux extension available since kernel 3.11 */
44 #ifndef O_TMPFILE
45 #define O_TMPFILE 0x404000
46 #endif
47 
48 #ifndef _GNU_SOURCE
49 char *secure_getenv(const char *name);
50 int mkostemp(char *template, int flags);
51 #endif
52 
create_tempfile(void)53 static SLJIT_INLINE int create_tempfile(void)
54 {
55 	int fd;
56 	char tmp_name[256];
57 	size_t tmp_name_len = 0;
58 	char *dir;
59 	struct stat st;
60 #if defined(SLJIT_SINGLE_THREADED) && SLJIT_SINGLE_THREADED
61 	mode_t mode;
62 #endif
63 
64 #ifdef HAVE_MEMFD_CREATE
65 	/* this is a GNU extension, make sure to use -D_GNU_SOURCE */
66 	fd = memfd_create("sljit", MFD_CLOEXEC);
67 	if (fd != -1) {
68 		fchmod(fd, 0);
69 		return fd;
70 	}
71 #endif
72 
73 	dir = secure_getenv("TMPDIR");
74 
75 	if (dir) {
76 		size_t len = strlen(dir);
77 		if (len > 0 && len < sizeof(tmp_name)) {
78 			if ((stat(dir, &st) == 0) && S_ISDIR(st.st_mode)) {
79 				memcpy(tmp_name, dir, len + 1);
80 				tmp_name_len = len;
81 			}
82 		}
83 	}
84 
85 #ifdef P_tmpdir
86 	if (!tmp_name_len) {
87 		tmp_name_len = strlen(P_tmpdir);
88 		if (tmp_name_len > 0 && tmp_name_len < sizeof(tmp_name))
89 			strcpy(tmp_name, P_tmpdir);
90 	}
91 #endif
92 	if (!tmp_name_len) {
93 		strcpy(tmp_name, "/tmp");
94 		tmp_name_len = 4;
95 	}
96 
97 	SLJIT_ASSERT(tmp_name_len > 0 && tmp_name_len < sizeof(tmp_name));
98 
99 	if (tmp_name_len > 1 && tmp_name[tmp_name_len - 1] == '/')
100 		tmp_name[--tmp_name_len] = '\0';
101 
102 	fd = open(tmp_name, O_TMPFILE | O_EXCL | O_RDWR | O_NOATIME | O_CLOEXEC, 0);
103 	if (fd != -1)
104 		return fd;
105 
106 	if (tmp_name_len >= sizeof(tmp_name) - 7)
107 		return -1;
108 
109 	strcpy(tmp_name + tmp_name_len, "/XXXXXX");
110 #if defined(SLJIT_SINGLE_THREADED) && SLJIT_SINGLE_THREADED
111 	mode = umask(0777);
112 #endif
113 	fd = mkostemp(tmp_name, O_CLOEXEC | O_NOATIME);
114 #if defined(SLJIT_SINGLE_THREADED) && SLJIT_SINGLE_THREADED
115 	umask(mode);
116 #else
117 	fchmod(fd, 0);
118 #endif
119 
120 	if (fd == -1)
121 		return -1;
122 
123 	if (unlink(tmp_name)) {
124 		close(fd);
125 		return -1;
126 	}
127 
128 	return fd;
129 }
130 
alloc_chunk(sljit_uw size)131 static SLJIT_INLINE struct sljit_chunk_header* alloc_chunk(sljit_uw size)
132 {
133 	struct sljit_chunk_header *retval;
134 	int fd;
135 
136 	fd = create_tempfile();
137 	if (fd == -1)
138 		return NULL;
139 
140 	if (ftruncate(fd, (off_t)size)) {
141 		close(fd);
142 		return NULL;
143 	}
144 
145 	retval = (struct sljit_chunk_header *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
146 
147 	if (retval == MAP_FAILED) {
148 		close(fd);
149 		return NULL;
150 	}
151 
152 	retval->executable = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_SHARED, fd, 0);
153 
154 	if (retval->executable == MAP_FAILED) {
155 		munmap((void *)retval, size);
156 		close(fd);
157 		return NULL;
158 	}
159 
160 	close(fd);
161 	return retval;
162 }
163 
free_chunk(void * chunk,sljit_uw size)164 static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
165 {
166 	struct sljit_chunk_header *header = ((struct sljit_chunk_header *)chunk) - 1;
167 
168 	munmap(header->executable, size);
169 	munmap((void *)header, size);
170 }
171 
172 #include "sljitExecAllocatorCore.c"
173