Skip to content

Commit 84ccd0a

Browse files
committed
Change any and all sqMakeMemory...Executable... prototypes and implementations
to use usqInt for address arguments (sqInt must be used for teh delta arg). IMO we should use usqInt where it makes sense (our APIs rather than OS APIs). I'm not interested in supporting 64-bit oops in 32-bit hosts, or 32-bit oops in 64-bit hosts, so I think it safe to assume that usqInt is equiavlent to usqIntptr_t, & sqInt to sqIntptr_t, and they're shorter. I'm open to persuasion so if I'm wrong please correct me (and the source).
1 parent 0876850 commit 84ccd0a

File tree

13 files changed

+166
-35
lines changed

13 files changed

+166
-35
lines changed

platforms/Cross/vm/sq.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ extern void sqDeallocateMemorySegmentAtOfSize(void *addr, sqInt sz);
102102
#endif /* SPURVM */
103103
#if COGVM
104104
extern void sqMakeMemoryExecutableFromToCodeToDataDelta(usqInt, usqInt, sqInt*);
105-
extern void sqMakeMemoryNotExecutableFromTo(usqIntptr_t, usqIntptr_t);
105+
extern void sqMakeMemoryNotExecutableFromTo(usqInt, usqInt);
106106
#endif
107107

108108
/* Platform-dependent memory size adjustment macro. */

platforms/Mac OS/vm/sqMacMemory.c

Lines changed: 68 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,26 +121,89 @@ sqMacMemoryFree()
121121
}
122122

123123
#if COGVM
124+
# if DUAL_MAPPED_CODE_ZONE
125+
/* We are indebted to Chris Wellons who designed this elegant API for dual
126+
* mapping which we depend on for fine-grained code modification (classical
127+
* Deutsch/Schiffman style inline cacheing and derivatives). Chris's code is:
128+
https://nullprogram.com/blog/2016/04/10/
129+
*
130+
* To cope with modern OSs that disallow executing code in writable memory we
131+
* dual-map the code zone, one mapping with read/write permissions and the other
132+
* with read/execute permissions. In such a configuration the code zone has
133+
* already been alloated and is not included in (what is no longer) the initial
134+
* alloc.
135+
*/
136+
static void
137+
memory_alias_map(size_t size, size_t naddr, void **addrs)
138+
{
139+
extern char *exeName;
140+
char path[128];
141+
snprintf(path, sizeof(path), "/%s(%lu,%p)",
142+
exeName ? exeName : __FUNCTION__, (long)getpid(), addrs);
143+
int fd = shm_open(path, O_RDWR | O_CREAT | O_EXCL, 0600);
144+
if (fd == -1) {
145+
perror("memory_alias_map: shm_open");
146+
exit(0666);
147+
}
148+
shm_unlink(path);
149+
ftruncate(fd, size);
150+
for (size_t i = 0; i < naddr; i++) {
151+
addrs[i] = mmap(addrs[i], size, PROT_READ | PROT_WRITE,
152+
addrs[i] ? MAP_FIXED | MAP_SHARED : MAP_SHARED,
153+
fd, 0);
154+
if (addrs[i] == MAP_FAILED) {
155+
perror("memory_alias_map: mmap(addrs[i]...");
156+
exit(0667);
157+
}
158+
}
159+
close(fd);
160+
return;
161+
}
162+
# endif /* DUAL_MAPPED_CODE_ZONE */
124163
void
125-
sqMakeMemoryExecutableFromTo(unsigned long startAddr, unsigned long endAddr)
164+
sqMakeMemoryExecutableFromToCodeToDataDelta(usqInt startAddr,
165+
usqInt endAddr,
166+
sqInt *codeToDataDelta)
126167
{
127-
unsigned long firstPage = roundDownToPage(startAddr);
168+
usqInt firstPage = roundDownToPage(startAddr);
169+
usqInt size = endAddr - firstPage;
170+
171+
# if DUAL_MAPPED_CODE_ZONE
172+
usqInt mappings[2];
173+
174+
mappings[0] = firstPage;
175+
mappings[1] = 0;
176+
177+
memory_alias_map(size, 2, (void **)mappings);
178+
assert(mappings[0] == firstPage);
179+
*codeToDataDelta = mappings[1] - startAddr;
180+
128181
if (mprotect((void *)firstPage,
129-
endAddr - firstPage + 1,
182+
size,
183+
PROT_READ | PROT_EXEC) < 0)
184+
perror("mprotect(x,y,PROT_READ | PROT_EXEC)");
185+
186+
# else /* DUAL_MAPPED_CODE_ZONE */
187+
188+
if (mprotect((void *)firstPage,
189+
size,
130190
PROT_READ | PROT_WRITE | PROT_EXEC) < 0)
131191
perror("mprotect(x,y,PROT_READ | PROT_WRITE | PROT_EXEC)");
192+
193+
*codeToDataDelta = 0;
194+
# endif
132195
}
133196

134197
void
135-
sqMakeMemoryNotExecutableFromTo(unsigned long startAddr, unsigned long endAddr)
198+
sqMakeMemoryNotExecutableFromTo(usqInt startAddr, usqInt endAddr)
136199
{
137200
# if 0
138201
/* We get EACCESS on 10.6.3 when trying to disable exec perm; Why? */
139202
/* Arguably this is pointless since allocated memory always does include
140203
* write permission. Annoyingly the mprotect call fails on both linux &
141204
* mac os x. So make the whole thing a nop.
142205
*/
143-
unsigned long firstPage = roundDownToPage(startAddr);
206+
usqInt firstPage = roundDownToPage(startAddr);
144207
if (mprotect((void *)firstPage,
145208
endAddr - firstPage + 1,
146209
PROT_READ | PROT_WRITE) < 0

platforms/iOS/vm/Common/sqMacV2Memory.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,19 +188,20 @@ sqImageFileReadEntireImage(void *ptr, size_t elementSize, size_t count, sqImageF
188188
# define roundUpToPage(v) (((v)+pageSize-1)&pageMask)
189189
#if COGVM || defined(HAVE_NATIVEBOOST)
190190
void
191-
sqMakeMemoryExecutableFromTo(unsigned long startAddr, unsigned long endAddr)
191+
sqMakeMemoryExecutableFromToCodeToDataDelta(usqInt startAddr, usqInt endAddr, sqInt *codeToDataDelta)
192192
{
193-
unsigned long firstPage = roundDownToPage(startAddr);
193+
usqInt firstPage = roundDownToPage(startAddr);
194194
if (mprotect((void *)firstPage,
195195
roundUpToPage(endAddr - firstPage),
196196
PROT_READ | PROT_WRITE | PROT_EXEC) < 0)
197197
perror("mprotect(x,y,PROT_READ | PROT_WRITE | PROT_EXEC)");
198+
*codeToDataDelta = 0;
198199
}
199200

200201
void
201-
sqMakeMemoryNotExecutableFromTo(unsigned long startAddr, unsigned long endAddr)
202+
sqMakeMemoryNotExecutableFromTo(usqInt startAddr, usqInt endAddr)
202203
{
203-
unsigned long firstPage = roundDownToPage(startAddr);
204+
usqInt firstPage = roundDownToPage(startAddr);
204205
if (mprotect((void *)firstPage,
205206
roundUpToPage(endAddr - firstPage),
206207
PROT_READ | PROT_WRITE) < 0)

platforms/minheadless/unix/sqPlatformSpecific-Unix.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,6 @@ extern sqInt sqGrowMemoryBy(sqInt oldLimit, sqInt delta);
4242
extern sqInt sqShrinkMemoryBy(sqInt oldLimit, sqInt delta);
4343
extern sqInt sqMemoryExtraBytesLeft(sqInt includingSwap);
4444
#if COGVM
45-
extern void sqMakeMemoryExecutableFromTo(unsigned long, unsigned long);
46-
extern void sqMakeMemoryNotExecutableFromTo(unsigned long, unsigned long);
47-
4845
extern int osCogStackPageHeadroom(void);
4946
extern void reportMinimumUnusedHeadroom(void);
5047
#endif

platforms/minheadless/unix/sqUnixMemory.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -322,17 +322,20 @@ sqInt sqMemoryExtraBytesLeft(sqInt includingSwap) { return uxMemoryExtraBytesL
322322
#define roundUpToPage(v) (((v)+pageSize-1)&pageMask)
323323
#if COGVM
324324
void
325-
sqMakeMemoryExecutableFromTo(unsigned long startAddr, unsigned long endAddr)
325+
sqMakeMemoryExecutableFromToCodeToDataDelta(usqInt startAddr,
326+
usqInt endAddr,
327+
sqInt *codeToDataDelta)
326328
{
327-
unsigned long firstPage = roundDownToPage(startAddr);
329+
usqInt firstPage = roundDownToPage(startAddr);
328330
if (mprotect((void *)firstPage,
329331
endAddr - firstPage + 1,
330332
PROT_READ | PROT_WRITE | PROT_EXEC) < 0)
331333
perror("mprotect(x,y,PROT_READ | PROT_WRITE | PROT_EXEC)");
334+
*codeToDataDelta = 0;
332335
}
333336

334337
void
335-
sqMakeMemoryNotExecutableFromTo(unsigned long startAddr, unsigned long endAddr)
338+
sqMakeMemoryNotExecutableFromTo(usqInt startAddr, usqInt endAddr)
336339
{
337340
# if 0
338341
unsigned long firstPage = roundDownToPage(startAddr);

platforms/minheadless/unix/sqUnixSpurMemory.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,10 +240,10 @@ sqMakeMemoryExecutableFromToCodeToDataDelta(usqInt startAddr,
240240
}
241241

242242
void
243-
sqMakeMemoryNotExecutableFromTo(unsigned long startAddr, unsigned long endAddr)
243+
sqMakeMemoryNotExecutableFromTo(usqInt startAddr, usqInt endAddr)
244244
{
245-
unsigned long firstPage = roundDownToPage(startAddr);
246-
unsigned long size = endAddr - firstPage;
245+
usqInt firstPage = roundDownToPage(startAddr);
246+
usqInt size = endAddr - firstPage;
247247
/* Arguably this is pointless since allocated memory always includes write
248248
* permission by default. Annoyingly the mprotect call fails on both linux
249249
* and mac os x. So make the whole thing a nop.

platforms/minheadless/windows/sqPlatformSpecific-Win32.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,6 @@ sqInt ioSetCursorARGB(sqInt bitsIndex, sqInt w, sqInt h, sqInt x, sqInt y);
134134
#define PROF_THREAD_PRIORITY THREAD_PRIORITY_TIME_CRITICAL
135135

136136
#if COGVM
137-
extern void sqMakeMemoryExecutableFromTo(usqIntptr_t, usqIntptr_t);
138-
extern void sqMakeMemoryNotExecutableFromTo(usqIntptr_t, usqIntptr_t);
139-
140137
extern int osCogStackPageHeadroom(void);
141138
extern void reportMinimumUnusedHeadroom(void);
142139
#endif

platforms/minheadless/windows/sqWin32Alloc.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ sqMemoryExtraBytesLeft(int includingSwap) {
181181

182182
# if COGVM
183183
void
184-
sqMakeMemoryExecutableFromTo(usqIntptr_t startAddr, usqIntptr_t endAddr)
184+
sqMakeMemoryExecutableFromToCodeToDataDelta(usqInt startAddr, usqInt endAddr, sqInt *codeToDataDelta)
185185
{
186186
DWORD previous;
187187

@@ -190,10 +190,11 @@ sqMakeMemoryExecutableFromTo(usqIntptr_t startAddr, usqIntptr_t endAddr)
190190
PAGE_EXECUTE_READWRITE,
191191
&previous))
192192
sqWin32PrintLastError("VirtualProtect(x,y,PAGE_EXECUTE_READWRITE)");
193+
*codeToDataDelta = 0;
193194
}
194195

195196
void
196-
sqMakeMemoryNotExecutableFromTo(usqIntptr_t startAddr, usqIntptr_t endAddr)
197+
sqMakeMemoryNotExecutableFromTo(usqInt startAddr, usqInt endAddr)
197198
{
198199
DWORD previous;
199200

platforms/minheadless/windows/sqWin32SpurAlloc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ sqMakeMemoryExecutableFromToCodeToDataDelta(usqInt startAddr,
214214
}
215215

216216
void
217-
sqMakeMemoryNotExecutableFromTo(usqIntptr_t startAddr, usqIntptr_t endAddr)
217+
sqMakeMemoryNotExecutableFromTo(usqInt startAddr, usqInt endAddr)
218218
{
219219
DWORD previous;
220220
SIZE_T size;

platforms/unix/vm/sqUnixMemory.c

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -320,22 +320,87 @@ sqInt sqMemoryExtraBytesLeft(sqInt includingSwap) { return uxMemoryExtraBytesL
320320

321321
#define roundDownToPage(v) ((v)&pageMask)
322322
#define roundUpToPage(v) (((v)+pageSize-1)&pageMask)
323+
323324
#if COGVM
325+
# if DUAL_MAPPED_CODE_ZONE
326+
/* We are indebted to Chris Wellons who designed this elegant API for dual
327+
* mapping which we depend on for fine-grained code modification (classical
328+
* Deutsch/Schiffman style inline cacheing and derivatives). Chris's code is:
329+
https://nullprogram.com/blog/2016/04/10/
330+
*
331+
* To cope with modern OSs that disallow executing code in writable memory we
332+
* dual-map the code zone, one mapping with read/write permissions and the other
333+
* with read/execute permissions. In such a configuration the code zone has
334+
* already been alloated and is not included in (what is no longer) the initial
335+
* alloc.
336+
*/
337+
static void
338+
memory_alias_map(size_t size, size_t naddr, void **addrs)
339+
{
340+
extern char *exeName;
341+
char path[128];
342+
snprintf(path, sizeof(path), "/%s(%lu,%p)",
343+
exeName ? exeName : __FUNCTION__, (long)getpid(), addrs);
344+
int fd = shm_open(path, O_RDWR | O_CREAT | O_EXCL, 0600);
345+
if (fd == -1) {
346+
perror("memory_alias_map: shm_open");
347+
exit(0666);
348+
}
349+
shm_unlink(path);
350+
ftruncate(fd, size);
351+
for (size_t i = 0; i < naddr; i++) {
352+
addrs[i] = mmap(addrs[i], size, PROT_READ | PROT_WRITE,
353+
addrs[i] ? MAP_FIXED | MAP_SHARED : MAP_SHARED,
354+
fd, 0);
355+
if (addrs[i] == MAP_FAILED) {
356+
perror("memory_alias_map: mmap(addrs[i]...");
357+
exit(0667);
358+
}
359+
}
360+
close(fd);
361+
return;
362+
}
363+
# endif /* DUAL_MAPPED_CODE_ZONE */
364+
324365
void
325-
sqMakeMemoryExecutableFromTo(unsigned long startAddr, unsigned long endAddr)
366+
sqMakeMemoryExecutableFromToCodeToDataDelta(usqInt startAddr,
367+
usqInt endAddr,
368+
sqInt *codeToDataDelta)
326369
{
327-
unsigned long firstPage = roundDownToPage(startAddr);
370+
usqInt firstPage = roundDownToPage(startAddr);
371+
usqInt size = endAddr - firstPage;
372+
373+
# if DUAL_MAPPED_CODE_ZONE
374+
usqInt mappings[2];
375+
376+
mappings[0] = firstPage;
377+
mappings[1] = 0;
378+
379+
memory_alias_map(size, 2, (void **)mappings);
380+
assert(mappings[0] == firstPage);
381+
*codeToDataDelta = mappings[1] - startAddr;
382+
328383
if (mprotect((void *)firstPage,
329-
endAddr - firstPage + 1,
384+
size,
385+
PROT_READ | PROT_EXEC) < 0)
386+
perror("mprotect(x,y,PROT_READ | PROT_EXEC)");
387+
388+
# else /* DUAL_MAPPED_CODE_ZONE */
389+
390+
if (mprotect((void *)firstPage,
391+
size,
330392
PROT_READ | PROT_WRITE | PROT_EXEC) < 0)
331393
perror("mprotect(x,y,PROT_READ | PROT_WRITE | PROT_EXEC)");
394+
395+
*codeToDataDelta = 0;
396+
# endif
332397
}
333398

334399
void
335-
sqMakeMemoryNotExecutableFromTo(unsigned long startAddr, unsigned long endAddr)
400+
sqMakeMemoryNotExecutableFromTo(usqInt startAddr, usqInt endAddr)
336401
{
337402
# if 0
338-
unsigned long firstPage = roundDownToPage(startAddr);
403+
usqInt firstPage = roundDownToPage(startAddr);
339404
/* Arguably this is pointless since allocated memory always does include
340405
* write permission. Annoyingly the mprotect call fails on both linux &
341406
* mac os x. So make the whole thing a nop.
@@ -352,7 +417,8 @@ sqMakeMemoryNotExecutableFromTo(unsigned long startAddr, unsigned long endAddr)
352417

353418
# define MBytes *1024*1024
354419

355-
int main()
420+
int
421+
main()
356422
{
357423
char *mem= sqAllocateMemory(4 MBytes, 40 MBytes);
358424
printf("memory allocated at %p\n", mem);

0 commit comments

Comments
 (0)