1
0
mirror of https://github.com/janet-lang/janet synced 2025-06-26 15:12:49 +00:00

Do not explicitly free state machines, instead return a status.

This makes it harder to have some kind of use after free issue.
This commit is contained in:
Calvin Rose 2020-05-30 11:29:58 -05:00
parent 117ae196fd
commit a78af0a7fb
4 changed files with 37 additions and 23 deletions

View File

@ -136,7 +136,7 @@ BOOT_CFLAGS:=-DJANET_BOOTSTRAP -DJANET_BUILD=$(JANET_BUILD) $(CFLAGS)
$(JANET_BOOT_OBJECTS): $(JANET_BOOT_HEADERS) $(JANET_BOOT_OBJECTS): $(JANET_BOOT_HEADERS)
build/%.boot.o: src/%.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS) build/%.boot.o: src/%.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS) Makefile
$(CC) $(BOOT_CFLAGS) -o $@ -c $< $(CC) $(BOOT_CFLAGS) -o $@ -c $<
build/janet_boot: $(JANET_BOOT_OBJECTS) build/janet_boot: $(JANET_BOOT_OBJECTS)

View File

@ -343,7 +343,7 @@ JanetListenerState *janet_listen(JanetPollable *pollable, JanetListener behavior
} }
/* Tell system we are done listening for a certain event */ /* Tell system we are done listening for a certain event */
void janet_unlisten(JanetListenerState *state) { static void janet_unlisten(JanetListenerState *state) {
JanetPollable *pollable = state->pollable; JanetPollable *pollable = state->pollable;
int is_last = (state->_next == NULL && pollable->state == state); int is_last = (state->_next == NULL && pollable->state == state);
int op = is_last ? EPOLL_CTL_DEL : EPOLL_CTL_MOD; int op = is_last ? EPOLL_CTL_DEL : EPOLL_CTL_MOD;
@ -401,11 +401,15 @@ void janet_loop1_impl(void) {
int mask = events[i].events; int mask = events[i].events;
JanetListenerState *state = pollable->state; JanetListenerState *state = pollable->state;
while (NULL != state) { while (NULL != state) {
JanetListenerState *next_state = state->_next;
JanetAsyncStatus status = JANET_ASYNC_STATUS_NOT_DONE;
if (mask & EPOLLOUT) if (mask & EPOLLOUT)
state->machine(state, JANET_ASYNC_EVENT_WRITE); status = state->machine(state, JANET_ASYNC_EVENT_WRITE);
if (mask & EPOLLIN) if (status == JANET_ASYNC_STATUS_NOT_DONE && (mask & EPOLLIN))
state->machine(state, JANET_ASYNC_EVENT_READ); status = state->machine(state, JANET_ASYNC_EVENT_READ);
state = state->_next; if (status == JANET_ASYNC_STATUS_DONE)
janet_unlisten(state);
state = next_state;
} }
} }
} }

View File

@ -148,7 +148,7 @@ typedef struct {
int is_chunk; int is_chunk;
} NetStateRead; } NetStateRead;
void net_machine_read(JanetListenerState *s, int event) { JanetAsyncStatus net_machine_read(JanetListenerState *s, JanetAsyncEvent event) {
NetStateRead *state = (NetStateRead *) s; NetStateRead *state = (NetStateRead *) s;
switch (event) { switch (event) {
default: default:
@ -159,7 +159,7 @@ void net_machine_read(JanetListenerState *s, int event) {
case JANET_ASYNC_EVENT_CLOSE: case JANET_ASYNC_EVENT_CLOSE:
/* Read is finished, even if chunk is incomplete */ /* Read is finished, even if chunk is incomplete */
janet_schedule(s->fiber, janet_wrap_nil()); janet_schedule(s->fiber, janet_wrap_nil());
break; return JANET_ASYNC_STATUS_DONE;
case JANET_ASYNC_EVENT_READ: case JANET_ASYNC_EVENT_READ:
/* Read in bytes */ /* Read in bytes */
{ {
@ -187,11 +187,12 @@ void net_machine_read(JanetListenerState *s, int event) {
if (!state->is_chunk || bytes_left == 0) { if (!state->is_chunk || bytes_left == 0) {
Janet resume_val = nread > 0 ? janet_wrap_buffer(buffer) : janet_wrap_nil(); Janet resume_val = nread > 0 ? janet_wrap_buffer(buffer) : janet_wrap_nil();
janet_schedule(s->fiber, resume_val); janet_schedule(s->fiber, resume_val);
janet_unlisten(s); return JANET_ASYNC_STATUS_DONE;
} }
} }
break; break;
} }
return JANET_ASYNC_STATUS_NOT_DONE;
} }
JANET_NO_RETURN static void janet_sched_read(JanetStream *stream, JanetBuffer *buf, int32_t nbytes) { JANET_NO_RETURN static void janet_sched_read(JanetStream *stream, JanetBuffer *buf, int32_t nbytes) {
@ -226,7 +227,7 @@ typedef struct {
int is_buffer; int is_buffer;
} NetStateWrite; } NetStateWrite;
void net_machine_write(JanetListenerState *s, int event) { JanetAsyncStatus net_machine_write(JanetListenerState *s, JanetAsyncEvent event) {
NetStateWrite *state = (NetStateWrite *) s; NetStateWrite *state = (NetStateWrite *) s;
switch (event) { switch (event) {
default: default:
@ -238,7 +239,7 @@ void net_machine_write(JanetListenerState *s, int event) {
break; break;
case JANET_ASYNC_EVENT_CLOSE: case JANET_ASYNC_EVENT_CLOSE:
janet_schedule(s->fiber, janet_wrap_nil()); janet_schedule(s->fiber, janet_wrap_nil());
break; return JANET_ASYNC_STATUS_DONE;
case JANET_ASYNC_EVENT_WRITE: { case JANET_ASYNC_EVENT_WRITE: {
int32_t start, len; int32_t start, len;
const uint8_t *bytes; const uint8_t *bytes;
@ -266,12 +267,13 @@ void net_machine_write(JanetListenerState *s, int event) {
state->start = start; state->start = start;
if (start >= len) { if (start >= len) {
janet_schedule(s->fiber, janet_wrap_nil()); janet_schedule(s->fiber, janet_wrap_nil());
janet_unlisten(s); return JANET_ASYNC_STATUS_DONE;
} }
break; break;
} }
break; break;
} }
return JANET_ASYNC_STATUS_NOT_DONE;
} }
JANET_NO_RETURN static void janet_sched_write_buffer(JanetStream *stream, JanetBuffer *buf) { JANET_NO_RETURN static void janet_sched_write_buffer(JanetStream *stream, JanetBuffer *buf) {
@ -302,7 +304,7 @@ typedef struct {
JanetFunction *function; JanetFunction *function;
} NetStateSimpleServer; } NetStateSimpleServer;
void net_machine_simple_server(JanetListenerState *s, int event) { JanetAsyncStatus net_machine_simple_server(JanetListenerState *s, JanetAsyncEvent event) {
NetStateSimpleServer *state = (NetStateSimpleServer *) s; NetStateSimpleServer *state = (NetStateSimpleServer *) s;
switch (event) { switch (event) {
default: default:
@ -317,7 +319,7 @@ void net_machine_simple_server(JanetListenerState *s, int event) {
case JANET_ASYNC_EVENT_CLOSE: case JANET_ASYNC_EVENT_CLOSE:
janet_schedule(s->fiber, janet_wrap_nil()); janet_schedule(s->fiber, janet_wrap_nil());
janet_gcunroot(janet_wrap_abstract(s->pollable)); janet_gcunroot(janet_wrap_abstract(s->pollable));
break; return JANET_ASYNC_STATUS_DONE;
case JANET_ASYNC_EVENT_READ: { case JANET_ASYNC_EVENT_READ: {
JSock connfd = accept(s->pollable->handle, NULL, NULL); JSock connfd = accept(s->pollable->handle, NULL, NULL);
if (JSOCKVALID(connfd)) { if (JSOCKVALID(connfd)) {
@ -330,6 +332,7 @@ void net_machine_simple_server(JanetListenerState *s, int event) {
break; break;
} }
} }
return JANET_ASYNC_STATUS_NOT_DONE;
} }
/* Adress info */ /* Adress info */

View File

@ -1142,13 +1142,21 @@ extern enum JanetInstructionType janet_instructions[JOP_INSTRUCTION_COUNT];
#ifdef JANET_EV #ifdef JANET_EV
#define JANET_POLL_FLAG_CLOSED 0x1 #define JANET_POLL_FLAG_CLOSED 0x1
#define JANET_POLL_FLAG_SOCKET 0x2 #define JANET_POLL_FLAG_SOCKET 0x2
#define JANET_ASYNC_EVENT_INIT 0
#define JANET_ASYNC_EVENT_MARK 1 typedef enum {
#define JANET_ASYNC_EVENT_DEINIT 2 JANET_ASYNC_EVENT_INIT,
#define JANET_ASYNC_EVENT_CLOSE 3 JANET_ASYNC_EVENT_MARK,
#define JANET_ASYNC_EVENT_READ 4 JANET_ASYNC_EVENT_DEINIT,
#define JANET_ASYNC_EVENT_WRITE 5 JANET_ASYNC_EVENT_CLOSE,
#define JANET_ASYNC_EVENT_TIMEOUT 6 JANET_ASYNC_EVENT_READ,
JANET_ASYNC_EVENT_WRITE,
JANET_ASYNC_EVENT_TIMEOUT
} JanetAsyncEvent;
typedef enum {
JANET_ASYNC_STATUS_NOT_DONE,
JANET_ASYNC_STATUS_DONE
} JanetAsyncStatus;
/* Typedefs */ /* Typedefs */
#ifdef JANET_WINDOWS #ifdef JANET_WINDOWS
@ -1158,7 +1166,7 @@ typedef int JanetPollType;
#endif #endif
typedef struct JanetListenerState JanetListenerState; typedef struct JanetListenerState JanetListenerState;
typedef struct JanetPollable JanetPollable; typedef struct JanetPollable JanetPollable;
typedef void (*JanetListener)(JanetListenerState *state, int event); typedef JanetAsyncStatus(*JanetListener)(JanetListenerState *state, JanetAsyncEvent event);
/* Wrapper around file descriptors and HANDLEs that can be polled. */ /* Wrapper around file descriptors and HANDLEs that can be polled. */
struct JanetPollable { struct JanetPollable {
@ -1192,7 +1200,6 @@ JANET_API void janet_schedule(JanetFiber *fiber, Janet value);
/* Start a state machine listening for events from a pollable */ /* Start a state machine listening for events from a pollable */
JANET_API JanetListenerState *janet_listen(JanetPollable *pollable, JanetListener behavior, int mask, size_t size); JANET_API JanetListenerState *janet_listen(JanetPollable *pollable, JanetListener behavior, int mask, size_t size);
JANET_API void janet_unlisten(JanetListenerState *state);
/* Shorthand for yielding to event loop in C */ /* Shorthand for yielding to event loop in C */
JANET_NO_RETURN JANET_API void janet_await(void); JANET_NO_RETURN JANET_API void janet_await(void);