Skip to content

Commit a94519d

Browse files
ereslibreassambar
andcommitted
Add support for building to the wasm32-wasi target
This change performs initial adaptations allowing the PHP interpreter to be compiled for the wasm32-wasi target. Challenges found: - `setjmp`/`longjmp` not available in this platform: can be worked around by using Asyncify; this is work in progress to be presented at a later stage. - Processes: WebAssembly has no concept of processes, so many process-related operations had to be emulated, or are no-ops. `getpid` and clocks are emulated. Signal handling has minimal emulation. `uid`, `gid`, and related concepts that do not map well to a WebAssembly sandbox are also removed. - `mmap` implementation is a minimal emulation that allows to allocate memory or map file contents to it. - Filesystem: many filesystem operations cannot be mapped to WASI, and so these operations are no-ops. - `S_IFSOCK` matches `S_IFIFO` in current `wasi-libc`; removed the `S_IFIFO` case, because `clang` will fail building due to a duplicated constant in `switch` statements. - File locks are also stubbed and always return success. - Networking: given the WebAssembly sandbox and capability-based security, it is not possible to open a socket as of today. Although the host is able to open a socket and forward a file descriptor, leaving the `accept()` syscall to the WebAssembly module, we have removed networking syscalls at this time. The only binary that builds with this change is `php-cgi` at this time. It's possible to adapt the change so that `php` builds and is able to run scripts and programs in the filesystem in a CLI fashion. However, starting a PHP server to listen on a socket using the CLI is a more contrived situation, given it's not possible to open a listening socket from within the sandbox; however it would be possible to create the socket on the host side, and forward the file descriptor to the module. Co-Authored-By: Asen Alexandrov <[email protected]>
1 parent 48db342 commit a94519d

37 files changed

+458
-29
lines changed

Zend/zend.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -834,7 +834,9 @@ static void executor_globals_ctor(zend_executor_globals *executor_globals) /* {{
834834
#endif
835835
executor_globals->saved_fpu_cw_ptr = NULL;
836836
executor_globals->active = 0;
837+
#ifndef __wasi__
837838
executor_globals->bailout = NULL;
839+
#endif // __wasi__
838840
executor_globals->error_handling = EH_NORMAL;
839841
executor_globals->exception_class = NULL;
840842
executor_globals->exception = NULL;
@@ -1223,6 +1225,7 @@ ZEND_COLD void zenderror(const char *error) /* {{{ */
12231225
ZEND_API ZEND_COLD ZEND_NORETURN void _zend_bailout(const char *filename, uint32_t lineno) /* {{{ */
12241226
{
12251227

1228+
#ifndef __wasi__
12261229
if (!EG(bailout)) {
12271230
zend_output_debug_string(1, "%s(%d) : Bailed out without a bailout address!", filename, lineno);
12281231
exit(-1);
@@ -1233,6 +1236,7 @@ ZEND_API ZEND_COLD ZEND_NORETURN void _zend_bailout(const char *filename, uint32
12331236
CG(in_compilation) = 0;
12341237
EG(current_execute_data) = NULL;
12351238
LONGJMP(*EG(bailout), FAILURE);
1239+
#endif // __wasi__
12361240
}
12371241
/* }}} */
12381242

Zend/zend.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ typedef size_t (*zend_write_func_t)(const char *str, size_t str_length);
256256

257257
#define zend_bailout() _zend_bailout(__FILE__, __LINE__)
258258

259+
#ifndef __wasi__
259260
#define zend_try \
260261
{ \
261262
JMP_BUF *__orig_bailout = EG(bailout); \
@@ -272,6 +273,19 @@ typedef size_t (*zend_write_func_t)(const char *str, size_t str_length);
272273
}
273274
#define zend_first_try EG(bailout)=NULL; zend_try
274275

276+
#else // __wasi__
277+
#define zend_try \
278+
{ \
279+
if (1) {
280+
#define zend_catch \
281+
} else {
282+
#define zend_end_try() \
283+
} \
284+
}
285+
#define zend_first_try zend_try
286+
#endif // __wasi__
287+
288+
275289
BEGIN_EXTERN_C()
276290
void zend_startup(zend_utility_functions *utility_functions);
277291
void zend_shutdown(void);

Zend/zend_alloc.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080
#include <fcntl.h>
8181
#include <errno.h>
8282

83-
#ifndef _WIN32
83+
#if !defined(_WIN32) && HAVE_MMAP
8484
# include <sys/mman.h>
8585
# ifndef MAP_ANON
8686
# ifdef MAP_ANONYMOUS
@@ -445,6 +445,8 @@ static void zend_mm_munmap(void *addr, size_t size)
445445
#endif
446446
}
447447
}
448+
#elif ! HAVE_MMAP
449+
free(addr);
448450
#else
449451
if (munmap(addr, size) != 0) {
450452
#if ZEND_MM_ERROR
@@ -472,6 +474,8 @@ static void *zend_mm_mmap_fixed(void *addr, size_t size)
472474
}
473475
ZEND_ASSERT(ptr == addr);
474476
return ptr;
477+
#elif ! HAVE_MMAP
478+
return NULL;
475479
#else
476480
int flags = MAP_PRIVATE | MAP_ANON;
477481
#if defined(MAP_EXCL)
@@ -508,6 +512,10 @@ static void *zend_mm_mmap(size_t size)
508512
return NULL;
509513
}
510514
return ptr;
515+
#elif ! HAVE_MMAP
516+
void* ptr = malloc(size);
517+
memset(ptr, 0, size);
518+
return ptr;
511519
#else
512520
void *ptr;
513521

@@ -717,6 +725,11 @@ static zend_always_inline void zend_mm_hugepage(void* ptr, size_t size)
717725

718726
static void *zend_mm_chunk_alloc_int(size_t size, size_t alignment)
719727
{
728+
#if ! HAVE_MMAP
729+
void* ptr = aligned_alloc(alignment, size);
730+
memset(ptr, 0, size);
731+
return ptr;
732+
#else
720733
void *ptr = zend_mm_mmap(size);
721734

722735
if (ptr == NULL) {
@@ -767,6 +780,7 @@ static void *zend_mm_chunk_alloc_int(size_t size, size_t alignment)
767780
#endif
768781
return ptr;
769782
}
783+
#endif
770784
}
771785

772786
static void *zend_mm_chunk_alloc(zend_mm_heap *heap, size_t size, size_t alignment)
@@ -2932,7 +2946,7 @@ ZEND_API void start_memory_manager(void)
29322946
#else
29332947
alloc_globals_ctor(&alloc_globals);
29342948
#endif
2935-
#ifndef _WIN32
2949+
#if !defined(_WIN32) && HAVE_MMAP
29362950
# if defined(_SC_PAGESIZE)
29372951
REAL_PAGE_SIZE = sysconf(_SC_PAGESIZE);
29382952
# elif defined(_SC_PAGE_SIZE)

Zend/zend_fibers.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
# include <ucontext.h>
4040
#endif
4141

42-
#ifndef ZEND_WIN32
42+
#if !defined(ZEND_WIN32) && HAVE_MMAP
4343
# include <unistd.h>
4444
# include <sys/mman.h>
4545
# include <limits.h>
@@ -108,7 +108,9 @@ typedef struct _zend_fiber_vm_state {
108108
zend_execute_data *current_execute_data;
109109
int error_reporting;
110110
uint32_t jit_trace_num;
111+
#ifndef __wasi__
111112
JMP_BUF *bailout;
113+
#endif // __wasi__
112114
zend_fiber *active_fiber;
113115
#ifdef ZEND_CHECK_STACK_LIMIT
114116
void *stack_base;
@@ -125,7 +127,9 @@ static zend_always_inline void zend_fiber_capture_vm_state(zend_fiber_vm_state *
125127
state->current_execute_data = EG(current_execute_data);
126128
state->error_reporting = EG(error_reporting);
127129
state->jit_trace_num = EG(jit_trace_num);
130+
#ifndef __wasi__
128131
state->bailout = EG(bailout);
132+
#endif // __wasi__
129133
state->active_fiber = EG(active_fiber);
130134
#ifdef ZEND_CHECK_STACK_LIMIT
131135
state->stack_base = EG(stack_base);
@@ -142,7 +146,9 @@ static zend_always_inline void zend_fiber_restore_vm_state(zend_fiber_vm_state *
142146
EG(current_execute_data) = state->current_execute_data;
143147
EG(error_reporting) = state->error_reporting;
144148
EG(jit_trace_num) = state->jit_trace_num;
149+
#ifndef __wasi__
145150
EG(bailout) = state->bailout;
151+
#endif // __wasi__
146152
EG(active_fiber) = state->active_fiber;
147153
#ifdef ZEND_CHECK_STACK_LIMIT
148154
EG(stack_base) = state->stack_base;
@@ -236,6 +242,8 @@ static zend_fiber_stack *zend_fiber_stack_allocate(size_t size)
236242
return NULL;
237243
}
238244
# endif
245+
#elif defined __wasi__
246+
pointer = malloc(alloc_size);
239247
#else
240248
pointer = mmap(NULL, alloc_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
241249

@@ -302,6 +310,8 @@ static void zend_fiber_stack_free(zend_fiber_stack *stack)
302310

303311
#ifdef ZEND_WIN32
304312
VirtualFree(pointer, 0, MEM_RELEASE);
313+
#elif defined __wasi__
314+
free(pointer);
305315
#else
306316
munmap(pointer, stack->size + ZEND_FIBER_GUARD_PAGES * page_size);
307317
#endif
@@ -415,7 +425,7 @@ ZEND_API bool zend_fiber_init_context(zend_fiber_context *context, void *kind, z
415425
makecontext(handle, (void (*)(void)) zend_fiber_trampoline, 0);
416426

417427
context->handle = handle;
418-
#else
428+
#elif !defined(__wasi__)
419429
// Stack grows down, calculate the top of the stack. make_fcontext then shifts pointer to lower 16-byte boundary.
420430
void *stack = (void *) ((uintptr_t) context->stack->pointer + context->stack->size);
421431

@@ -428,6 +438,8 @@ ZEND_API bool zend_fiber_init_context(zend_fiber_context *context, void *kind, z
428438

429439
context->handle = make_fcontext(stack, context->stack->size, zend_fiber_trampoline);
430440
ZEND_ASSERT(context->handle != NULL && "make_fcontext() never returns NULL");
441+
#else
442+
return false;
431443
#endif
432444

433445
context->kind = kind;
@@ -502,16 +514,18 @@ ZEND_API void zend_fiber_switch_context(zend_fiber_transfer *transfer)
502514

503515
/* Copy transfer struct because it might live on the other fiber's stack that will eventually be destroyed. */
504516
*transfer = *transfer_data;
505-
#else
517+
#elif !defined(__wasi__)
506518
boost_context_data data = jump_fcontext(to->handle, transfer);
507519

508520
/* Copy transfer struct because it might live on the other fiber's stack that will eventually be destroyed. */
509521
*transfer = *data.transfer;
522+
#else
523+
return;
510524
#endif
511525

512526
to = transfer->context;
513527

514-
#ifndef ZEND_FIBER_UCONTEXT
528+
#if !defined(ZEND_FIBER_UCONTEXT) && !defined(__wasi__)
515529
/* Get the context that resumed us and update its handle to allow for symmetric coroutines. */
516530
to->handle = data.handle;
517531
#endif

Zend/zend_globals.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
#define ZEND_GLOBALS_H
2222

2323

24+
#ifndef __wasi__
2425
#include <setjmp.h>
26+
#endif
2527

2628
#include "zend_globals_macros.h"
2729

@@ -162,7 +164,9 @@ struct _zend_executor_globals {
162164

163165
HashTable included_files; /* files already included */
164166

167+
#ifndef __wasi__
165168
JMP_BUF *bailout;
169+
#endif
166170

167171
int error_reporting;
168172
int exit_status;

Zend/zend_types.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1453,5 +1453,15 @@ static zend_always_inline uint32_t zval_delref_p(zval* pz) {
14531453
#define ZVAL_COPY_OR_DUP_PROP(z, v) \
14541454
do { ZVAL_COPY_OR_DUP(z, v); Z_PROP_FLAG_P(z) = Z_PROP_FLAG_P(v); } while (0)
14551455

1456+
#ifdef __wasi__
1457+
#define LOG_EMERG 0 /* system is unusable */
1458+
#define LOG_ALERT 1 /* action must be taken immediately */
1459+
#define LOG_CRIT 2 /* critical conditions */
1460+
#define LOG_ERR 3 /* error conditions */
1461+
#define LOG_WARNING 4 /* warning conditions */
1462+
#define LOG_NOTICE 5 /* normal but significant condition */
1463+
#define LOG_INFO 6 /* informational */
1464+
#define LOG_DEBUG 7 /* debug-level messages */
1465+
#endif // __wasi__
14561466

14571467
#endif /* ZEND_TYPES_H */

Zend/zend_virtual_cwd.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1400,6 +1400,8 @@ CWD_API int virtual_chmod(const char *filename, mode_t mode) /* {{{ */
14001400
}
14011401
ret = php_win32_ioutil_chmod(new_state.cwd, mode);
14021402
}
1403+
#elif defined __wasi__
1404+
ret = 0;
14031405
#else
14041406
ret = chmod(new_state.cwd, mode);
14051407
#endif
@@ -1428,7 +1430,11 @@ CWD_API int virtual_chown(const char *filename, uid_t owner, gid_t group, int li
14281430
ret = -1;
14291431
#endif
14301432
} else {
1433+
#ifndef __wasi__
14311434
ret = chown(new_state.cwd, owner, group);
1435+
#else
1436+
ret = 0;
1437+
#endif // __wasi__
14321438
}
14331439

14341440
CWD_STATE_FREE_ERR(&new_state);
@@ -1706,8 +1712,11 @@ CWD_API FILE *virtual_popen(const char *command, const char *type) /* {{{ */
17061712
*ptr++ = ' ';
17071713

17081714
memcpy(ptr, command, command_length+1);
1715+
#ifndef __wasi__
17091716
retval = popen(command_line, type);
1710-
1717+
#else
1718+
retval = 0;
1719+
#endif // __wasi__
17111720
efree(command_line);
17121721
return retval;
17131722
}

configure.ac

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,9 @@ label2:
199199
fi
200200
PHP_SUBST(RE2C_FLAGS)
201201

202+
dnl Check if __wasi__ is defined by the compiler
203+
AC_CHECK_DECLS([__wasi__])
204+
202205
dnl Platform-specific compile settings.
203206
dnl ----------------------------------------------------------------------------
204207

@@ -1334,11 +1337,13 @@ else
13341337
if test "$fiber_os" = 'mac'; then
13351338
AC_DEFINE([_XOPEN_SOURCE], 1, [ ])
13361339
fi
1337-
AC_CHECK_HEADER(ucontext.h, [
1338-
AC_DEFINE([ZEND_FIBER_UCONTEXT], 1, [ ])
1339-
], [
1340-
AC_MSG_ERROR([fibers not available on this platform])
1341-
])
1340+
if test "$ac_cv_have_decl___wasi__" != "yes"; then
1341+
AC_CHECK_HEADER(ucontext.h, [
1342+
AC_DEFINE([ZEND_FIBER_UCONTEXT], 1, [ ])
1343+
], [
1344+
AC_MSG_ERROR([fibers not available on this platform])
1345+
])
1346+
fi
13421347
fi
13431348

13441349
LIBZEND_BASIC_CHECKS

ext/fileinfo/libmagic/fsmagic.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ file_fsmagic(struct magic_set *ms, const char *fn, zend_stat_t *sb)
167167
# endif
168168
#endif
169169

170+
#ifndef __wasi__
170171
#ifdef S_IFIFO
171172
case S_IFIFO:
172173
if((ms->flags & MAGIC_DEVICES) != 0)
@@ -179,6 +180,7 @@ file_fsmagic(struct magic_set *ms, const char *fn, zend_stat_t *sb)
179180
return -1;
180181
break;
181182
#endif
183+
#endif // __wasi__
182184
#ifdef S_IFDOOR
183185
case S_IFDOOR:
184186
if (mime) {

ext/pdo_sqlite/sqlite_statement.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ static int pdo_sqlite_stmt_dtor(pdo_stmt_t *stmt)
3232
pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data;
3333

3434
if (S->stmt) {
35+
#ifndef __wasi__
3536
sqlite3_finalize(S->stmt);
37+
#endif
3638
S->stmt = NULL;
3739
}
3840
efree(S);

0 commit comments

Comments
 (0)