1
0
mirror of https://github.com/janet-lang/janet synced 2024-12-28 17:30:31 +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)
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 $<
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 */
void janet_unlisten(JanetListenerState *state) {
static void janet_unlisten(JanetListenerState *state) {
JanetPollable *pollable = state->pollable;
int is_last = (state->_next == NULL && pollable->state == state);
int op = is_last ? EPOLL_CTL_DEL : EPOLL_CTL_MOD;
@ -401,11 +401,15 @@ void janet_loop1_impl(void) {
int mask = events[i].events;
JanetListenerState *state = pollable->state;
while (NULL != state) {
JanetListenerState *next_state = state->_next;
JanetAsyncStatus status = JANET_ASYNC_STATUS_NOT_DONE;
if (mask & EPOLLOUT)
state->machine(state, JANET_ASYNC_EVENT_WRITE);
if (mask & EPOLLIN)
state->machine(state, JANET_ASYNC_EVENT_READ);
state = state->_next;
status = state->machine(state, JANET_ASYNC_EVENT_WRITE);
if (status == JANET_ASYNC_STATUS_NOT_DONE && (mask & EPOLLIN))
status = state->machine(state, JANET_ASYNC_EVENT_READ);
if (status == JANET_ASYNC_STATUS_DONE)
janet_unlisten(state);
state = next_state;
}
}
}

View File

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

View File

@ -1142,13 +1142,21 @@ extern enum JanetInstructionType janet_instructions[JOP_INSTRUCTION_COUNT];
#ifdef JANET_EV
#define JANET_POLL_FLAG_CLOSED 0x1
#define JANET_POLL_FLAG_SOCKET 0x2
#define JANET_ASYNC_EVENT_INIT 0
#define JANET_ASYNC_EVENT_MARK 1
#define JANET_ASYNC_EVENT_DEINIT 2
#define JANET_ASYNC_EVENT_CLOSE 3
#define JANET_ASYNC_EVENT_READ 4
#define JANET_ASYNC_EVENT_WRITE 5
#define JANET_ASYNC_EVENT_TIMEOUT 6
typedef enum {
JANET_ASYNC_EVENT_INIT,
JANET_ASYNC_EVENT_MARK,
JANET_ASYNC_EVENT_DEINIT,
JANET_ASYNC_EVENT_CLOSE,
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 */
#ifdef JANET_WINDOWS
@ -1158,7 +1166,7 @@ typedef int JanetPollType;
#endif
typedef struct JanetListenerState JanetListenerState;
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. */
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 */
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 */
JANET_NO_RETURN JANET_API void janet_await(void);