Skip to content

Commit 3a730be

Browse files
white-axekateinoigakukun
authored andcommitted
Fix jump buffer leak in setjmp handler in WASI builds
1 parent 72fc9c7 commit 3a730be

File tree

3 files changed

+55
-27
lines changed

3 files changed

+55
-27
lines changed

cont.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1369,6 +1369,7 @@ cont_init(rb_context_t *cont, rb_thread_t *th)
13691369
/* save thread context */
13701370
cont_save_thread(cont, th);
13711371
cont->saved_ec.thread_ptr = th;
1372+
cont->saved_ec.tag = NULL;
13721373
cont->saved_ec.local_storage = NULL;
13731374
cont->saved_ec.local_storage_recursive_hash = Qnil;
13741375
cont->saved_ec.local_storage_recursive_hash_for_trace = Qnil;

eval_intern.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,11 @@ extern int select_large_fdset(int, fd_set *, fd_set *, fd_set *, struct timeval
102102
_tag.tag = Qundef; \
103103
_tag.prev = _ec->tag; \
104104
_tag.lock_rec = rb_ec_vm_lock_rec(_ec); \
105-
rb_vm_tag_jmpbuf_init(&_tag.buf); \
105+
rb_vm_tag_jmpbuf_init(&_tag);
106106

107107
#define EC_POP_TAG() \
108108
_ec->tag = _tag.prev; \
109-
rb_vm_tag_jmpbuf_deinit(&_tag.buf); \
109+
rb_vm_tag_jmpbuf_deinit(&_tag); \
110110
} while (0)
111111

112112
#define EC_TMPPOP_TAG() \

vm_core.h

Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -946,52 +946,79 @@ typedef void *rb_jmpbuf_t[5];
946946
Therefore, we allocates the buffer on the heap on such
947947
environments.
948948
*/
949-
typedef rb_jmpbuf_t *rb_vm_tag_jmpbuf_t;
949+
typedef struct _rb_vm_tag_jmpbuf {
950+
struct _rb_vm_tag_jmpbuf *next;
951+
rb_jmpbuf_t buf;
952+
} *rb_vm_tag_jmpbuf_t;
950953

951-
#define RB_VM_TAG_JMPBUF_GET(buf) (*buf)
954+
#define RB_VM_TAG_JMPBUF_GET(jmpbuf) ((jmpbuf)->buf)
955+
#else
956+
typedef rb_jmpbuf_t rb_vm_tag_jmpbuf_t;
957+
958+
#define RB_VM_TAG_JMPBUF_GET(jmpbuf) (jmpbuf)
959+
#endif
960+
961+
/*
962+
the members which are written in EC_PUSH_TAG() should be placed at
963+
the beginning and the end, so that entire region is accessible.
964+
*/
965+
struct rb_vm_tag {
966+
VALUE tag;
967+
VALUE retval;
968+
rb_vm_tag_jmpbuf_t buf;
969+
struct rb_vm_tag *prev;
970+
enum ruby_tag_type state;
971+
unsigned int lock_rec;
972+
};
973+
974+
#if defined(__wasm__) && !defined(__EMSCRIPTEN__)
975+
static inline void
976+
_rb_vm_tag_jmpbuf_deinit_internal(rb_vm_tag_jmpbuf_t jmpbuf)
977+
{
978+
rb_vm_tag_jmpbuf_t buf = jmpbuf;
979+
while (buf != NULL) {
980+
rb_vm_tag_jmpbuf_t next = buf->next;
981+
ruby_xfree(buf);
982+
buf = next;
983+
}
984+
}
952985

953986
static inline void
954-
rb_vm_tag_jmpbuf_init(rb_vm_tag_jmpbuf_t *jmpbuf)
987+
rb_vm_tag_jmpbuf_init(struct rb_vm_tag *tag)
955988
{
956-
*jmpbuf = ruby_xmalloc(sizeof(rb_jmpbuf_t));
989+
if (tag->prev != NULL && tag->prev->buf->next != NULL) {
990+
_rb_vm_tag_jmpbuf_deinit_internal(tag->prev->buf->next);
991+
tag->prev->buf->next = NULL;
992+
}
993+
tag->buf = ruby_xmalloc(sizeof *tag->buf);
994+
tag->buf->next = NULL;
995+
if (tag->prev != NULL) {
996+
tag->prev->buf->next = tag->buf;
997+
}
957998
}
958999

9591000
static inline void
960-
rb_vm_tag_jmpbuf_deinit(const rb_vm_tag_jmpbuf_t *jmpbuf)
1001+
rb_vm_tag_jmpbuf_deinit(struct rb_vm_tag *tag)
9611002
{
962-
ruby_xfree(*jmpbuf);
1003+
if (tag->prev != NULL) {
1004+
tag->prev->buf->next = NULL;
1005+
}
1006+
_rb_vm_tag_jmpbuf_deinit_internal(tag->buf);
9631007
}
9641008
#else
965-
typedef rb_jmpbuf_t rb_vm_tag_jmpbuf_t;
966-
967-
#define RB_VM_TAG_JMPBUF_GET(buf) (buf)
968-
9691009
static inline void
970-
rb_vm_tag_jmpbuf_init(rb_vm_tag_jmpbuf_t *jmpbuf)
1010+
rb_vm_tag_jmpbuf_init(struct rb_vm_tag *tag)
9711011
{
9721012
// no-op
9731013
}
9741014

9751015
static inline void
976-
rb_vm_tag_jmpbuf_deinit(const rb_vm_tag_jmpbuf_t *jmpbuf)
1016+
rb_vm_tag_jmpbuf_deinit(struct rb_vm_tag *tag)
9771017
{
9781018
// no-op
9791019
}
9801020
#endif
9811021

982-
/*
983-
the members which are written in EC_PUSH_TAG() should be placed at
984-
the beginning and the end, so that entire region is accessible.
985-
*/
986-
struct rb_vm_tag {
987-
VALUE tag;
988-
VALUE retval;
989-
rb_vm_tag_jmpbuf_t buf;
990-
struct rb_vm_tag *prev;
991-
enum ruby_tag_type state;
992-
unsigned int lock_rec;
993-
};
994-
9951022
STATIC_ASSERT(rb_vm_tag_buf_offset, offsetof(struct rb_vm_tag, buf) > 0);
9961023
STATIC_ASSERT(rb_vm_tag_buf_end,
9971024
offsetof(struct rb_vm_tag, buf) + sizeof(rb_vm_tag_jmpbuf_t) <

0 commit comments

Comments
 (0)