From f0cebdcab0c4407c0a32a7cee10f4af1ad7cf8eb Mon Sep 17 00:00:00 2001 From: Peter McEvoy Date: Wed, 6 Jul 2022 11:27:13 -0700 Subject: [PATCH 01/21] u3: place guard page between heap and stack --- pkg/urbit/include/c/defs.h | 10 ++++ pkg/urbit/noun/events.c | 115 ++++++++++++++++++++++++++----------- 2 files changed, 93 insertions(+), 32 deletions(-) diff --git a/pkg/urbit/include/c/defs.h b/pkg/urbit/include/c/defs.h index 29198bc009..b649a8866d 100644 --- a/pkg/urbit/include/c/defs.h +++ b/pkg/urbit/include/c/defs.h @@ -56,6 +56,16 @@ # define c3_max(x, y) ( ((x) > (y)) ? (x) : (y) ) # define c3_min(x, y) ( ((x) < (y)) ? (x) : (y) ) + +//! Round up/down (respectively). +//! +//! @param[in] x Integer to round. +//! @param[in] n Multiple to round to. Must be power of 2. +//! +//! @return `x` rounded to the nearest multiple of `n`. +# define c3_rop(x, n) (((x) + ((n) - 1)) & (~((n) - 1))) +# define c3_rod(x, n) ((x) & ~((n) - 1)) + /* Rotate. */ # define c3_rotw(r, x) ( ((x) << (r)) | ((x) >> (32 - (r))) ) diff --git a/pkg/urbit/noun/events.c b/pkg/urbit/noun/events.c index e37fdf0ee2..bb0981a263 100644 --- a/pkg/urbit/noun/events.c +++ b/pkg/urbit/noun/events.c @@ -29,6 +29,11 @@ //! handled outside this module). //! - faults are handled by dirtying the page and switching protections to //! read/write. +//! - a guard page is initially placed in the approximate middle of the free +//! space between the heap and stack at the time of the first page fault. +//! when a fault is detected in the guard page, the guard page is recentered +//! in the free space of the current road. if the guard page cannot be +//! recentered, then memory exhaustion has occurred. //! //! ### updates (u3e_save()) //! @@ -71,6 +76,12 @@ #include #include +//! Urbit page size in 4-byte words. +static const size_t pag_wiz_i = 1 << u3a_page; + +//! Urbit page size in bytes. +static const size_t pag_siz_i = sizeof(c3_w) * pag_wiz_i; + #ifdef U3_SNAPSHOT_VALIDATION /* Image check. */ @@ -177,6 +188,52 @@ _ce_mapfree(void* map_v) c3_i u3e_fault(void* adr_v, c3_i ser_i) { + //! Place a guard page at the (approximate) middle of the free space between + //! the heap and stack of the current road. + //! + //! @param[in] failure_action Action to perform on failure. +#define center_guard_page(failure_action) \ + do { \ + u3p(c3_w) bottom_page, top_page; \ + if ( c3y == u3a_is_north(u3R) ) { \ + top_page = c3_rod(u3R->cap_p, pag_wiz_i); \ + bottom_page = c3_rop(u3R->hat_p, pag_wiz_i); \ + } \ + else { \ + top_page = c3_rod(u3R->hat_p, pag_wiz_i); \ + bottom_page = c3_rop(u3R->cap_p, pag_wiz_i); \ + } \ + if ( top_page < bottom_page + pag_wiz_i ) { \ + fprintf(stderr, \ + "loom: not enough memory to recenter the guard page\r\n"); \ + failure_action; \ + } else { \ + const u3p(c3_w) previous_guard_page = gar_pag_p; \ + const c3_w midpoint = (top_page - bottom_page) / 2; \ + gar_pag_p = bottom_page + c3_rod(midpoint, pag_wiz_i); \ + if ( previous_guard_page == gar_pag_p ) { \ + fprintf(stderr, \ + "loom: can't move the guard page to the same location" \ + " (base address %p)\r\n", \ + u3a_into(gar_pag_p)); \ + failure_action; \ + } \ + else if ( -1 == mprotect(u3a_into(gar_pag_p), pag_siz_i, PROT_NONE) ) { \ + fprintf(stderr, \ + "loom: failed to protect the guard page " \ + "(base address %p)\r\n", \ + u3a_into(gar_pag_p)); \ + failure_action; \ + } \ + } \ + } while ( 0 ) + + // Base loom offset of the guard page. + static u3p(c3_w) gar_pag_p; + if ( 0 == gar_pag_p ) { + center_guard_page(goto fail); + } + // Let the stack overflow handler run. if ( 0 == ser_i ) { return 0; @@ -191,43 +248,37 @@ u3e_fault(void* adr_v, c3_i ser_i) fprintf(stderr, "address %p out of loom!\r\n", adr_w); fprintf(stderr, "loom: [%p : %p)\r\n", u3_Loom, u3_Loom + u3a_words); c3_assert(0); - return 0; } - else { - c3_w off_w = u3a_outa(adr_w); - c3_w pag_w = off_w >> u3a_page; - c3_w blk_w = (pag_w >> 5); - c3_w bit_w = (pag_w & 31); -#if 0 - if ( pag_w == 131041 ) { - u3l_log("dirty page %d (at %p); unprotecting %p to %p\r\n", - pag_w, - adr_v, - (u3_Loom + (pag_w << u3a_page)), - (u3_Loom + (pag_w << u3a_page) + (1 << u3a_page))); - } -#endif + u3p(c3_w) adr_p = u3a_outa(adr_w); + c3_w pag_w = adr_p >> u3a_page; + c3_w blk_w = (pag_w >> 5); + c3_w bit_w = (pag_w & 31); - if ( 0 != (u3P.dit_w[blk_w] & (1 << bit_w)) ) { - fprintf(stderr, "strange page: %d, at %p, off %x\r\n", - pag_w, adr_w, off_w); - c3_assert(0); - return 0; - } - - u3P.dit_w[blk_w] |= (1 << bit_w); - - if ( -1 == mprotect((void *)(u3_Loom + (pag_w << u3a_page)), - (1 << (u3a_page + 2)), - (PROT_READ | PROT_WRITE)) ) - { - fprintf(stderr, "loom: fault mprotect: %s\r\n", strerror(errno)); - c3_assert(0); - return 0; - } + // The fault happened in the guard page. + if ( gar_pag_p <= adr_p && adr_p < gar_pag_p + pag_wiz_i ) { + center_guard_page(goto fail); } + else if ( 0 != (u3P.dit_w[blk_w] & (1 << bit_w)) ) { + fprintf(stderr, "strange page: %d, at %p, off %x\r\n", pag_w, adr_w, adr_p); + c3_assert(0); + } + + u3P.dit_w[blk_w] |= (1 << bit_w); + + if ( -1 == mprotect((void *)(u3_Loom + (pag_w << u3a_page)), + (1 << (u3a_page + 2)), + (PROT_READ | PROT_WRITE)) ) + { + fprintf(stderr, "loom: fault mprotect: %s\r\n", strerror(errno)); + c3_assert(0); + } + return 1; + +fail: + u3m_bail(c3__meme); +#undef center_guard_page } /* _ce_image_open(): open or create image. From 78cb3967364ff1fa08f48d57684bcb9219504b2b Mon Sep 17 00:00:00 2001 From: Peter McEvoy Date: Wed, 6 Jul 2022 11:30:32 -0700 Subject: [PATCH 02/21] u3: use pag_siz_i and pag_wiz_i where appropriate --- pkg/urbit/noun/events.c | 63 ++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/pkg/urbit/noun/events.c b/pkg/urbit/noun/events.c index bb0981a263..34dcb34cfc 100644 --- a/pkg/urbit/noun/events.c +++ b/pkg/urbit/noun/events.c @@ -267,7 +267,7 @@ u3e_fault(void* adr_v, c3_i ser_i) u3P.dit_w[blk_w] |= (1 << bit_w); if ( -1 == mprotect((void *)(u3_Loom + (pag_w << u3a_page)), - (1 << (u3a_page + 2)), + pag_siz_i, (PROT_READ | PROT_WRITE)) ) { fprintf(stderr, "loom: fault mprotect: %s\r\n", strerror(errno)); @@ -313,7 +313,7 @@ _ce_image_open(u3e_image* img_u) } else { c3_d siz_d = buf_u.st_size; - c3_d pgs_d = (siz_d + (c3_d)((1 << (u3a_page + 2)) - 1)) >> + c3_d pgs_d = (siz_d + (c3_d)(pag_siz_i - 1)) >> (c3_d)(u3a_page + 2); if ( !siz_d ) { @@ -439,12 +439,12 @@ _ce_patch_verify(u3_ce_patch* pat_u) fprintf(stderr, "loom: patch seek: %s\r\n", strerror(errno)); return c3n; } - if ( -1 == read(pat_u->mem_i, mem_w, (1 << (u3a_page + 2))) ) { + if ( -1 == read(pat_u->mem_i, mem_w, pag_siz_i) ) { fprintf(stderr, "loom: patch read: %s\r\n", strerror(errno)); return c3n; } { - c3_w nug_w = u3r_mug_words(mem_w, (1 << u3a_page)); + c3_w nug_w = u3r_mug_words(mem_w, pag_wiz_i); if ( mug_w != nug_w ) { fprintf(stderr, "loom: patch mug mismatch %d/%d; (%x, %x)\r\n", @@ -527,14 +527,8 @@ _ce_patch_write_page(u3_ce_patch* pat_u, c3_w pgc_w, c3_w* mem_w) { - if ( -1 == lseek(pat_u->mem_i, (pgc_w << (u3a_page + 2)), SEEK_SET) ) { - c3_assert(0); - } - if ( (1 << (u3a_page + 2)) != - write(pat_u->mem_i, mem_w, (1 << (u3a_page + 2))) ) - { - c3_assert(0); - } + c3_assert(-1 != lseek(pat_u->mem_i, pgc_w * pag_siz_i, SEEK_SET)); + c3_assert(pag_siz_i == write(pat_u->mem_i, mem_w, pag_siz_i)); } /* _ce_patch_count_page(): count a page, producing new counter. @@ -566,8 +560,7 @@ _ce_patch_save_page(u3_ce_patch* pat_u, c3_w* mem_w = u3_Loom + (pag_w << u3a_page); pat_u->con_u->mem_u[pgc_w].pag_w = pag_w; - pat_u->con_u->mem_u[pgc_w].mug_w = u3r_mug_words(mem_w, - (1 << u3a_page)); + pat_u->con_u->mem_u[pgc_w].mug_w = u3r_mug_words(mem_w, pag_wiz_i); #if 0 u3l_log("protect a: page %d\r\n", pag_w); @@ -575,7 +568,7 @@ _ce_patch_save_page(u3_ce_patch* pat_u, _ce_patch_write_page(pat_u, pgc_w, mem_w); if ( -1 == mprotect(u3_Loom + (pag_w << u3a_page), - (1 << (u3a_page + 2)), + pag_siz_i, PROT_READ) ) { c3_assert(0); @@ -603,8 +596,8 @@ _ce_patch_compose(void) u3m_water(&nwr_w, &swu_w); - nor_w = (nwr_w + ((1 << u3a_page) - 1)) >> u3a_page; - sou_w = (swu_w + ((1 << u3a_page) - 1)) >> u3a_page; + nor_w = (nwr_w + (pag_wiz_i - 1)) >> u3a_page; + sou_w = (swu_w + (pag_wiz_i - 1)) >> u3a_page; } #ifdef U3_SNAPSHOT_VALIDATION @@ -727,7 +720,7 @@ _ce_patch_apply(u3_ce_patch* pat_u) // for ( i_w = 0; i_w < pat_u->con_u->pgs_w; i_w++ ) { c3_w pag_w = pat_u->con_u->mem_u[i_w].pag_w; - c3_w mem_w[1 << u3a_page]; + c3_w mem_w[pag_wiz_i]; c3_i fid_i; c3_w off_w; @@ -740,7 +733,7 @@ _ce_patch_apply(u3_ce_patch* pat_u) off_w = (u3a_pages - (pag_w + 1)); } - if ( -1 == read(pat_u->mem_i, mem_w, (1 << (u3a_page + 2))) ) { + if ( -1 == read(pat_u->mem_i, mem_w, pag_siz_i) ) { fprintf(stderr, "loom: patch apply read: %s\r\n", strerror(errno)); c3_assert(0); } @@ -749,13 +742,13 @@ _ce_patch_apply(u3_ce_patch* pat_u) fprintf(stderr, "loom: patch apply seek: %s\r\n", strerror(errno)); c3_assert(0); } - if ( -1 == write(fid_i, mem_w, (1 << (u3a_page + 2))) ) { + if ( -1 == write(fid_i, mem_w, pag_siz_i) ) { fprintf(stderr, "loom: patch apply write: %s\r\n", strerror(errno)); c3_assert(0); } } #if 0 - u3l_log("apply: %d, %x\n", pag_w, u3r_mug_words(mem_w, (1 << u3a_page))); + u3l_log("apply: %d, %x\n", pag_w, u3r_mug_words(mem_w, pag_wiz_i)); #endif } } @@ -772,7 +765,7 @@ _ce_image_blit(u3e_image* img_u, } c3_w i_w; - c3_w siz_w = 1 << (u3a_page + 2); + c3_w siz_w = pag_siz_i; lseek(img_u->fid_i, 0, SEEK_SET); for ( i_w = 0; i_w < img_u->pgs_w; i_w++ ) { @@ -804,18 +797,18 @@ _ce_image_fine(u3e_image* img_u, c3_ws stp_ws) { c3_w i_w; - c3_w buf_w[1 << u3a_page]; + c3_w buf_w[pag_wiz_i]; lseek(img_u->fid_i, 0, SEEK_SET); for ( i_w=0; i_w < img_u->pgs_w; i_w++ ) { c3_w mem_w, fil_w; - if ( -1 == read(img_u->fid_i, buf_w, (1 << (u3a_page + 2))) ) { + if ( -1 == read(img_u->fid_i, buf_w, pag_siz_i) ) { fprintf(stderr, "loom: image fine read: %s\r\n", strerror(errno)); c3_assert(0); } - mem_w = u3r_mug_words(ptr_w, (1 << u3a_page)); - fil_w = u3r_mug_words(buf_w, (1 << u3a_page)); + mem_w = u3r_mug_words(ptr_w, pag_wiz_i); + fil_w = u3r_mug_words(buf_w, pag_wiz_i); if ( mem_w != fil_w ) { c3_w pag_w = (ptr_w - u3_Loom) >> u3a_page; @@ -855,10 +848,10 @@ _ce_image_copy(u3e_image* fom_u, u3e_image* tou_u) // copy pages into destination image // for ( i_w = 0; i_w < fom_u->pgs_w; i_w++ ) { - c3_w mem_w[1 << u3a_page]; + c3_w mem_w[pag_wiz_i]; c3_w off_w = i_w; - if ( -1 == read(fom_u->fid_i, mem_w, (1 << (u3a_page + 2))) ) { + if ( -1 == read(fom_u->fid_i, mem_w, pag_siz_i) ) { fprintf(stderr, "loom: image copy read: %s\r\n", strerror(errno)); return c3n; } @@ -867,7 +860,7 @@ _ce_image_copy(u3e_image* fom_u, u3e_image* tou_u) fprintf(stderr, "loom: image copy seek: %s\r\n", strerror(errno)); return c3n; } - if ( -1 == write(tou_u->fid_i, mem_w, (1 << (u3a_page + 2))) ) { + if ( -1 == write(tou_u->fid_i, mem_w, pag_siz_i) ) { fprintf(stderr, "loom: image copy write: %s\r\n", strerror(errno)); return c3n; } @@ -972,11 +965,11 @@ u3e_save(void) { _ce_image_fine(&u3P.nor_u, u3_Loom, - (1 << u3a_page)); + pag_wiz_i); _ce_image_fine(&u3P.sou_u, - (u3_Loom + (1 << u3a_bits) - (1 << u3a_page)), - -(1 << u3a_page)); + (u3_Loom + (1 << u3a_bits) - pag_wiz_i), + -(ssize_t)pag_wiz_i); c3_assert(u3P.nor_u.pgs_w == u3K.nor_w); c3_assert(u3P.sou_u.pgs_w == u3K.sou_w); @@ -1042,11 +1035,11 @@ u3e_live(c3_o nuu_o, c3_c* dir_c) { _ce_image_blit(&u3P.nor_u, u3_Loom, - (1 << u3a_page)); + pag_wiz_i); _ce_image_blit(&u3P.sou_u, - (u3_Loom + (1 << u3a_bits) - (1 << u3a_page)), - -(1 << u3a_page)); + (u3_Loom + (1 << u3a_bits) - pag_wiz_i), + -(ssize_t)pag_wiz_i); u3l_log("boot: protected loom\r\n"); } From bcdafbe2063104905a7a466bb6ae87d7399c125b Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Wed, 29 Jun 2022 23:28:37 -0400 Subject: [PATCH 03/21] u3: make output pointer optional in u3r_p() (cherry picked from commit 2a0b92b4474947fcbb519d4158eae9cb3b5d6287) --- pkg/urbit/noun/retrieve.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/urbit/noun/retrieve.c b/pkg/urbit/noun/retrieve.c index 2a09ccd0e8..a6e873c42b 100644 --- a/pkg/urbit/noun/retrieve.c +++ b/pkg/urbit/noun/retrieve.c @@ -864,7 +864,7 @@ u3r_p(u3_noun a, if ( (c3y == u3r_cell(a, &feg, &nux)) && (c3y == u3r_sing(feg, b)) ) { - *c = nux; + if ( c ) *c = nux; return c3y; } else return c3n; From eaf47ce0cf902104bf535e03cf499943b8b007e4 Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Wed, 29 Jun 2022 23:29:24 -0400 Subject: [PATCH 04/21] u3: correct u3m_soft() error result where +mook is unavailable (cherry picked from commit bbc54b7a890845e4281d3a250fefedefb464bc8d) --- pkg/urbit/noun/manage.c | 55 +++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/pkg/urbit/noun/manage.c b/pkg/urbit/noun/manage.c index 5ac5568239..6f051bbbc5 100644 --- a/pkg/urbit/noun/manage.c +++ b/pkg/urbit/noun/manage.c @@ -1290,20 +1290,32 @@ u3m_soft(c3_w mil_w, return why; } else { - // don't use .^ at the top level! - // - c3_assert(1 != u3h(why)); + u3_noun tax, cod, pro; + + switch ( u3h(why) ) { + case 2: { + cod = c3__exit; + tax = u3t(why); + } break; + + case 3: { + cod = u3h(u3t(why)); + tax = u3t(u3t(why)); + } break; + + // don't use .^ at the top level! + // + default: { + u3m_p("invalid mot", u3h(why)); + c3_assert(0); + } + } // don't call +mook if we have no kernel // // This is required to soft the boot sequence. - // XX produce specific error motes instead of %2? // if ( 0 == u3A->roc ) { - u3_noun tax = u3t(why); - - u3m_p("tone", u3h(why)); - while ( u3_nul != tax ) { u3_noun dat, mot, val; u3x_cell(tax, &dat, &tax); @@ -1323,31 +1335,16 @@ u3m_soft(c3_w mil_w, } } - u3z(why); - return u3nc(c3__fail, u3_nul); + pro = u3nc(u3k(cod), u3_nul); } else { - u3_noun tax, cod, pro, mok; - - if ( 2 == u3h(why) ) { - cod = c3__exit; - tax = u3k(u3t(why)); - } - else { - c3_assert(3 == u3h(why)); - - cod = u3k(u3h(u3t(why))); - tax = u3k(u3t(u3t(why))); - } - - mok = u3dc("mook", 2, tax); - pro = u3nc(cod, u3k(u3t(mok))); - + u3_noun mok = u3dc("mook", 2, u3k(tax)); + pro = u3nc(u3k(cod), u3k(u3t(mok))); u3z(mok); - u3z(why); - - return pro; } + + u3z(why); + return pro; } } From 146db7b832c4848a5120e54f902f7344a1d0fd6a Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Wed, 29 Jun 2022 23:30:26 -0400 Subject: [PATCH 05/21] u3: allocate emergency buffer on every road, free on bail for trace cells (cherry picked from commit 3a11a08b712b52805f97ceb06da8417a8b7cbde4) --- pkg/urbit/noun/manage.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pkg/urbit/noun/manage.c b/pkg/urbit/noun/manage.c index 6f051bbbc5..3dd97d5001 100644 --- a/pkg/urbit/noun/manage.c +++ b/pkg/urbit/noun/manage.c @@ -361,7 +361,9 @@ _cm_signal_deep(c3_w mil_w) // go utterly haywire. // if ( 0 == u3H->rod_u.bug.mer ) { - u3H->rod_u.bug.mer = u3i_string("emergency buffer"); + u3H->rod_u.bug.mer = u3i_string( + "emergency buffer with sufficient space to cons the trace and bail" + ); } if ( mil_w ) { @@ -731,6 +733,11 @@ u3m_bail(u3_noun how) u3m_signal(how); } + // release the emergency buffer, ensuring space for cells + // + u3z(u3R->bug.mer); + u3R->bug.mer = 0; + /* Reconstruct a correct error ball. */ if ( _(u3ud(how)) ) { @@ -900,6 +907,10 @@ u3m_hate(c3_w pad_w) u3R->ear_p = u3R->cap_p; u3m_leap(pad_w); + + u3R->bug.mer = u3i_string( + "emergency buffer with sufficient space to cons the trace and bail" + ); } /* u3m_love(): return product from leap. From e045bfd593c0e611a55dbd99fda1c5acf2d34179 Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Wed, 29 Jun 2022 23:12:45 -0400 Subject: [PATCH 06/21] u3: adds (failing) test for bail:meme (cherry picked from commit 3a03b1de5d57201c153229db69051235a50907c0) --- pkg/urbit/tests/nock_tests.c | 82 ++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 pkg/urbit/tests/nock_tests.c diff --git a/pkg/urbit/tests/nock_tests.c b/pkg/urbit/tests/nock_tests.c new file mode 100644 index 0000000000..cb8e13e3f2 --- /dev/null +++ b/pkg/urbit/tests/nock_tests.c @@ -0,0 +1,82 @@ +#include "all.h" + +/* _setup(): prepare for tests. +*/ +static void +_setup(void) +{ + u3m_init(); + u3m_pave(c3y); +} + +static u3_noun +_nock_fol(u3_noun fol) +{ + return u3n_nock_on(u3_nul, fol); +} + +static c3_i +_test_nock_meme(void) +{ + // (jam !=(=(~ =|(i=@ |-(?:(=(i ^~((bex 32))) ~ [i $(i +(i))])))))) + // + const c3_y buf_y[] = { + 0xe1, 0x16, 0x1b, 0x4, 0x1b, 0xe1, 0x20, 0x58, 0x1c, 0x76, 0x4d, 0x96, 0xd8, + 0x31, 0x60, 0x0, 0x0, 0x0, 0x0, 0xd8, 0x8, 0x37, 0xce, 0xd, 0x92, 0x21, + 0x83, 0x68, 0x61, 0x87, 0x39, 0xce, 0x4d, 0xe, 0x92, 0x21, 0x87, 0x19, 0x8 + }; + u3_noun fol = u3s_cue_bytes(sizeof(buf_y), buf_y); + u3_noun gon; + c3_w i_w; + c3_i ret_i = 1; + + for ( i_w = 0; i_w < 3; i_w++ ) { + gon = u3m_soft(0, _nock_fol, u3k(fol)); + + if ( c3n == u3r_p(gon, c3__meme, 0) ) { + u3m_p("nock meme unexpected mote", u3h(gon)); + ret_i = 0; + u3z(gon); + break; + } + + u3z(gon); + } + + u3z(fol); + + return ret_i; +} + +static c3_i +_test_nock(void) +{ + c3_i ret_i = 1; + + if ( !_test_nock_meme() ) { + fprintf(stderr, "test nock meme: failed\r\n"); + ret_i = 0; + } + + return ret_i; +} + +/* main(): run all test cases. +*/ +int +main(int argc, char* argv[]) +{ + _setup(); + + if ( !_test_nock() ) { + fprintf(stderr, "test nock: failed\r\n"); + exit(1); + } + + // GC + // + u3m_grab(u3_none); + + fprintf(stderr, "test nock: ok\r\n"); + return 0; +} From 4bd4e8a4a9104a967262536d6d9f07e68bdd79e8 Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Wed, 29 Jun 2022 23:32:57 -0400 Subject: [PATCH 07/21] u3: check for road stack overflow on every nock %2 and %9 (cherry picked from commit 9db1411bd8e8c0b8e9bf38aadb869c5fd678023b) --- pkg/urbit/noun/nock.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pkg/urbit/noun/nock.c b/pkg/urbit/noun/nock.c index 6aef6e065e..6065a6c960 100644 --- a/pkg/urbit/noun/nock.c +++ b/pkg/urbit/noun/nock.c @@ -1838,6 +1838,23 @@ _n_kale(u3_noun a) return a; } +/* _n_sane(): check for stack overflow +*/ +static inline void +_n_sane(c3_ys off_ys) +{ + if ( !off_ys ) { + if( !(u3R->cap_p > u3R->hat_p) ) { + u3m_bail(c3__meme); + } + } + else { + if( !(u3R->cap_p < u3R->hat_p) ) { + u3m_bail(c3__meme); + } + } +} + typedef struct { u3n_prog* pog_u; c3_w ip_w; @@ -2078,6 +2095,7 @@ _n_burn(u3n_prog* pog_u, u3_noun bus, c3_ys mov, c3_ys off) x = _n_pep(mov, off); fam = u3to(burnframe, u3R->cap_p) + off + mov; u3R->cap_p = u3of(burnframe, fam - off); + _n_sane(off); fam->ip_w = ip_w; fam->pog_u = pog_u; _n_push(mov, off, x); @@ -2240,6 +2258,7 @@ _n_burn(u3n_prog* pog_u, u3_noun bus, c3_ys mov, c3_ys off) fam = u3to(burnframe, u3R->cap_p) + off + mov; u3R->cap_p = u3of(burnframe, fam - off); + _n_sane(off); fam->ip_w = ip_w; fam->pog_u = pog_u; From f2d24201a5dbc6a951e3088546cc23028625db50 Mon Sep 17 00:00:00 2001 From: Peter McEvoy Date: Wed, 6 Jul 2022 15:33:16 -0700 Subject: [PATCH 08/21] u3: replace u3m_bail() with u3m_signal() in u3e_fault() --- pkg/urbit/include/noun/manage.h | 5 +++++ pkg/urbit/noun/events.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/pkg/urbit/include/noun/manage.h b/pkg/urbit/include/noun/manage.h index 5c522bcd17..89f50d6037 100644 --- a/pkg/urbit/include/noun/manage.h +++ b/pkg/urbit/include/noun/manage.h @@ -44,6 +44,11 @@ void u3m_pave(c3_o nuu_o); + /* u3m_signal(): treat a nock-level exception as a signal interrupt. + */ + void + u3m_signal(u3_noun sig_l); + /* u3m_file(): load file, as atom, or bail. */ u3_noun diff --git a/pkg/urbit/noun/events.c b/pkg/urbit/noun/events.c index 34dcb34cfc..a8795b3c0b 100644 --- a/pkg/urbit/noun/events.c +++ b/pkg/urbit/noun/events.c @@ -277,7 +277,7 @@ u3e_fault(void* adr_v, c3_i ser_i) return 1; fail: - u3m_bail(c3__meme); + u3m_signal(c3__meme); #undef center_guard_page } From 1ea6e10a3600b5aa0d95496d2604f0947ac56f2e Mon Sep 17 00:00:00 2001 From: Peter McEvoy Date: Wed, 6 Jul 2022 16:09:34 -0700 Subject: [PATCH 09/21] u3: initialize guard page in u3e_live() --- pkg/urbit/include/noun/allocate.h | 2 +- pkg/urbit/noun/events.c | 110 ++++++++++++++++-------------- 2 files changed, 60 insertions(+), 52 deletions(-) diff --git a/pkg/urbit/include/noun/allocate.h b/pkg/urbit/include/noun/allocate.h index cc30b18fae..98d153d493 100644 --- a/pkg/urbit/include/noun/allocate.h +++ b/pkg/urbit/include/noun/allocate.h @@ -25,7 +25,7 @@ /* u3a_bytes: number of bytes in memory. */ -# define u3a_bytes (c3_w)((1 << (2 + u3a_bits))) +# define u3a_bytes (sizeof(c3_w) * u3a_words) /* u3a_cells: number of representable cells. */ diff --git a/pkg/urbit/noun/events.c b/pkg/urbit/noun/events.c index a8795b3c0b..9af3a4e111 100644 --- a/pkg/urbit/noun/events.c +++ b/pkg/urbit/noun/events.c @@ -76,6 +76,9 @@ #include #include +// Base loom offset of the guard page. +static u3p(c3_w) gar_pag_p; + //! Urbit page size in 4-byte words. static const size_t pag_wiz_i = 1 << u3a_page; @@ -183,57 +186,61 @@ _ce_mapfree(void* map_v) } #endif +//! Place a guard page at the (approximate) middle of the free space between +//! the heap and stack of the current road, bailing if memory has been +//! exhausted. +static void +_ce_center_guard_page(void) +{ + u3p(c3_w) bot_p, top_p; + if ( !u3R ) { + top_p = u3a_outa(u3_Loom + u3a_words); + bot_p = u3a_outa(u3_Loom); + } + else if ( c3y == u3a_is_north(u3R) ) { + top_p = c3_rod(u3R->cap_p, pag_wiz_i); + bot_p = c3_rop(u3R->hat_p, pag_wiz_i); + } + else { + top_p = c3_rod(u3R->hat_p, pag_wiz_i); + bot_p = c3_rop(u3R->cap_p, pag_wiz_i); + } + + if ( top_p < bot_p + pag_wiz_i ) { + fprintf(stderr, + "loom: not enough memory to recenter the guard page\r\n"); + goto fail; + } + const u3p(c3_w) old_gar_p = gar_pag_p; + const c3_w mid_p = (top_p - bot_p) / 2; + gar_pag_p = bot_p + c3_rod(mid_p, pag_wiz_i); + if ( old_gar_p == gar_pag_p ) { + fprintf(stderr, + "loom: can't move the guard page to the same location" + " (base address %p)\r\n", + u3a_into(gar_pag_p)); + goto fail; + } + + if ( -1 == mprotect(u3a_into(gar_pag_p), pag_siz_i, PROT_NONE) ) { + fprintf(stderr, + "loom: failed to protect the guard page " + "(base address %p)\r\n", + u3a_into(gar_pag_p)); + goto fail; + } + + return; + +fail: + u3m_signal(c3__meme); +} + /* u3e_fault(): handle a memory event with libsigsegv protocol. */ c3_i u3e_fault(void* adr_v, c3_i ser_i) { - //! Place a guard page at the (approximate) middle of the free space between - //! the heap and stack of the current road. - //! - //! @param[in] failure_action Action to perform on failure. -#define center_guard_page(failure_action) \ - do { \ - u3p(c3_w) bottom_page, top_page; \ - if ( c3y == u3a_is_north(u3R) ) { \ - top_page = c3_rod(u3R->cap_p, pag_wiz_i); \ - bottom_page = c3_rop(u3R->hat_p, pag_wiz_i); \ - } \ - else { \ - top_page = c3_rod(u3R->hat_p, pag_wiz_i); \ - bottom_page = c3_rop(u3R->cap_p, pag_wiz_i); \ - } \ - if ( top_page < bottom_page + pag_wiz_i ) { \ - fprintf(stderr, \ - "loom: not enough memory to recenter the guard page\r\n"); \ - failure_action; \ - } else { \ - const u3p(c3_w) previous_guard_page = gar_pag_p; \ - const c3_w midpoint = (top_page - bottom_page) / 2; \ - gar_pag_p = bottom_page + c3_rod(midpoint, pag_wiz_i); \ - if ( previous_guard_page == gar_pag_p ) { \ - fprintf(stderr, \ - "loom: can't move the guard page to the same location" \ - " (base address %p)\r\n", \ - u3a_into(gar_pag_p)); \ - failure_action; \ - } \ - else if ( -1 == mprotect(u3a_into(gar_pag_p), pag_siz_i, PROT_NONE) ) { \ - fprintf(stderr, \ - "loom: failed to protect the guard page " \ - "(base address %p)\r\n", \ - u3a_into(gar_pag_p)); \ - failure_action; \ - } \ - } \ - } while ( 0 ) - - // Base loom offset of the guard page. - static u3p(c3_w) gar_pag_p; - if ( 0 == gar_pag_p ) { - center_guard_page(goto fail); - } - // Let the stack overflow handler run. if ( 0 == ser_i ) { return 0; @@ -248,6 +255,7 @@ u3e_fault(void* adr_v, c3_i ser_i) fprintf(stderr, "address %p out of loom!\r\n", adr_w); fprintf(stderr, "loom: [%p : %p)\r\n", u3_Loom, u3_Loom + u3a_words); c3_assert(0); + return 0; } u3p(c3_w) adr_p = u3a_outa(adr_w); @@ -257,11 +265,12 @@ u3e_fault(void* adr_v, c3_i ser_i) // The fault happened in the guard page. if ( gar_pag_p <= adr_p && adr_p < gar_pag_p + pag_wiz_i ) { - center_guard_page(goto fail); + _ce_center_guard_page(); } else if ( 0 != (u3P.dit_w[blk_w] & (1 << bit_w)) ) { fprintf(stderr, "strange page: %d, at %p, off %x\r\n", pag_w, adr_w, adr_p); c3_assert(0); + return 0; } u3P.dit_w[blk_w] |= (1 << bit_w); @@ -275,10 +284,6 @@ u3e_fault(void* adr_v, c3_i ser_i) } return 1; - -fail: - u3m_signal(c3__meme); -#undef center_guard_page } /* _ce_image_open(): open or create image. @@ -1056,6 +1061,9 @@ u3e_live(c3_o nuu_o, c3_c* dir_c) } } } + + _ce_center_guard_page(); + return nuu_o; } From a830db5f683446999ca0dbf0bc8ad8a3976a2c7e Mon Sep 17 00:00:00 2001 From: Peter McEvoy Date: Wed, 6 Jul 2022 18:29:16 -0700 Subject: [PATCH 10/21] u3: initialize guard page in u3e_init() --- pkg/urbit/include/noun/events.h | 5 +++++ pkg/urbit/noun/events.c | 8 ++++++-- pkg/urbit/noun/manage.c | 4 ++++ pkg/urbit/tests/nock_tests.c | 1 + 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/pkg/urbit/include/noun/events.h b/pkg/urbit/include/noun/events.h index f44a94e571..92d5c2a75e 100644 --- a/pkg/urbit/include/noun/events.h +++ b/pkg/urbit/include/noun/events.h @@ -84,4 +84,9 @@ void u3e_foul(void); + /* u3e_init(): initialize page tracking. + */ + void + u3e_init(void); + #endif /* ifndef U3_EVENTS_H */ diff --git a/pkg/urbit/noun/events.c b/pkg/urbit/noun/events.c index 9af3a4e111..541068e231 100644 --- a/pkg/urbit/noun/events.c +++ b/pkg/urbit/noun/events.c @@ -1062,8 +1062,6 @@ u3e_live(c3_o nuu_o, c3_c* dir_c) } } - _ce_center_guard_page(); - return nuu_o; } @@ -1088,3 +1086,9 @@ u3e_foul(void) { memset((void*)u3P.dit_w, 0xff, sizeof(u3P.dit_w)); } + +void +u3e_init(void) +{ + _ce_center_guard_page(); +} diff --git a/pkg/urbit/noun/manage.c b/pkg/urbit/noun/manage.c index 3dd97d5001..2fc24a23ae 100644 --- a/pkg/urbit/noun/manage.c +++ b/pkg/urbit/noun/manage.c @@ -1804,6 +1804,10 @@ u3m_boot(c3_c* dir_c) */ u3m_pave(nuu_o); + /* Place the guard page. + */ + u3e_init(); + /* Initialize the jet system. */ { diff --git a/pkg/urbit/tests/nock_tests.c b/pkg/urbit/tests/nock_tests.c index cb8e13e3f2..19c7ef200d 100644 --- a/pkg/urbit/tests/nock_tests.c +++ b/pkg/urbit/tests/nock_tests.c @@ -7,6 +7,7 @@ _setup(void) { u3m_init(); u3m_pave(c3y); + u3e_init(); } static u3_noun From a2a6250d7743e2ef582c343f6e7bcbb9c79505c7 Mon Sep 17 00:00:00 2001 From: Peter McEvoy Date: Wed, 6 Jul 2022 18:42:50 -0700 Subject: [PATCH 11/21] u3: restore missing `return 0` to u3e_fault() --- pkg/urbit/noun/events.c | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/urbit/noun/events.c b/pkg/urbit/noun/events.c index 541068e231..914de93878 100644 --- a/pkg/urbit/noun/events.c +++ b/pkg/urbit/noun/events.c @@ -281,6 +281,7 @@ u3e_fault(void* adr_v, c3_i ser_i) { fprintf(stderr, "loom: fault mprotect: %s\r\n", strerror(errno)); c3_assert(0); + return 0; } return 1; From b63049057352983bec09ba72a1850cd4e9a15da8 Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Thu, 7 Jul 2022 00:48:19 -0400 Subject: [PATCH 12/21] u3: bump road heap offset before allocating cellblock --- pkg/urbit/noun/allocate.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pkg/urbit/noun/allocate.c b/pkg/urbit/noun/allocate.c index ddee5451bd..5a32249fcf 100644 --- a/pkg/urbit/noun/allocate.c +++ b/pkg/urbit/noun/allocate.c @@ -719,8 +719,9 @@ u3a_cellblock(c3_w num_w) return c3n; } else { - u3_post hat_p = u3R->hat_p; u3_post cel_p = u3R->all.cel_p; + u3_post hat_p = u3R->hat_p; + u3R->hat_p += (num_w * u3a_minimum); for ( i_w = 0; i_w < num_w; i_w++) { u3_post all_p = hat_p; @@ -744,7 +745,7 @@ u3a_cellblock(c3_w num_w) u3to(u3a_fbox, fre_p)->nex_p = cel_p; cel_p = fre_p; } - u3R->hat_p = hat_p; + u3R->all.cel_p = cel_p; } } @@ -753,8 +754,9 @@ u3a_cellblock(c3_w num_w) return c3n; } else { - u3_post hat_p = u3R->hat_p; u3_post cel_p = u3R->all.cel_p; + u3_post hat_p = u3R->hat_p; + u3R->hat_p -= (num_w * u3a_minimum); for ( i_w = 0; i_w < num_w; i_w++ ) { u3_post all_p = (hat_p -= u3a_minimum); @@ -776,7 +778,7 @@ u3a_cellblock(c3_w num_w) u3to(u3a_fbox, fre_p)->nex_p = cel_p; cel_p = fre_p; } - u3R->hat_p = hat_p; + u3R->all.cel_p = cel_p; } } From 350406c9e16770791a84e26974f272c75762bc6e Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Thu, 7 Jul 2022 00:48:50 -0400 Subject: [PATCH 13/21] u3: account for guard page in cellblock allocation conditional --- pkg/urbit/noun/allocate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/urbit/noun/allocate.c b/pkg/urbit/noun/allocate.c index 5a32249fcf..3bbbe0eb23 100644 --- a/pkg/urbit/noun/allocate.c +++ b/pkg/urbit/noun/allocate.c @@ -715,7 +715,7 @@ u3a_cellblock(c3_w num_w) c3_w i_w; if ( c3y == u3a_is_north(u3R) ) { - if ( u3R->cap_p <= (u3R->hat_p + (num_w * u3a_minimum)) ) { + if ( u3R->cap_p <= (u3R->hat_p + (num_w * u3a_minimum) + (1 << u3a_page)) ) { return c3n; } else { @@ -750,7 +750,7 @@ u3a_cellblock(c3_w num_w) } } else { - if ( (u3R->cap_p + (num_w * u3a_minimum)) >= u3R->hat_p ) { + if ( (u3R->cap_p + (num_w * u3a_minimum) + (1 << u3a_page)) >= u3R->hat_p ) { return c3n; } else { From f0fa528f3b5d28125644e49fbd43d96d39c758d0 Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Thu, 7 Jul 2022 01:15:01 -0400 Subject: [PATCH 14/21] u3: removes/disables obsolete road stack overflow checks --- pkg/urbit/include/noun/allocate.h | 29 +++++++------------ pkg/urbit/jets/b/reel.c | 1 - pkg/urbit/jets/e/parse.c | 4 --- pkg/urbit/noun/allocate.c | 48 ------------------------------- pkg/urbit/noun/nock.c | 3 +- pkg/urbit/noun/retrieve.c | 4 --- pkg/urbit/noun/serial.c | 20 ++----------- 7 files changed, 14 insertions(+), 95 deletions(-) diff --git a/pkg/urbit/include/noun/allocate.h b/pkg/urbit/include/noun/allocate.h index 98d153d493..13f4a545fb 100644 --- a/pkg/urbit/include/noun/allocate.h +++ b/pkg/urbit/include/noun/allocate.h @@ -397,36 +397,35 @@ u3a_push(const u3a_pile* pil_u) { u3R->cap_p += pil_u->mov_ws; - return u3a_peek(pil_u); - } - /* u3a_pile_sane(): bail on invalid road stack state. - */ - inline void - u3a_pile_sane(const u3a_pile* pil_u) - { + // XX define symbol to control guard page + // +#if 0 // !off means we're on a north road // if ( !pil_u->off_ws ) { if( !(u3R->cap_p > u3R->hat_p) ) { u3m_bail(c3__meme); } -#ifdef U3_MEMORY_DEBUG + #ifdef U3_MEMORY_DEBUG c3_assert( pil_u->top_p >= u3R->cap_p ); -#endif + #endif } else { if( !(u3R->cap_p < u3R->hat_p) ) { u3m_bail(c3__meme); } -#ifdef U3_MEMORY_DEBUG + #ifdef U3_MEMORY_DEBUG c3_assert( pil_u->top_p <= u3R->cap_p ); -#endif + #endif } +#endif #ifdef U3_MEMORY_DEBUG c3_assert( pil_u->rod_u == u3R ); #endif + + return u3a_peek(pil_u); } /* u3a_pile_done(): assert valid upon completion. @@ -708,14 +707,6 @@ void (*pat_f)(u3_atom, void*), c3_o (*cel_f)(u3_noun, void*)); - /* u3a_walk_fore_unsafe(): u3a_walk_fore(), without overflow checks - */ - void - u3a_walk_fore_unsafe(u3_noun a, - void* ptr_v, - void (*pat_f)(u3_atom, void*), - c3_o (*cel_f)(u3_noun, void*)); - /* u3a_string(): `a` as an on-loom c-string. */ c3_c* diff --git a/pkg/urbit/jets/b/reel.c b/pkg/urbit/jets/b/reel.c index 2292db1a98..13c47f3d12 100644 --- a/pkg/urbit/jets/b/reel.c +++ b/pkg/urbit/jets/b/reel.c @@ -27,7 +27,6 @@ *top = i; } while ( u3_nul != t ); - u3a_pile_sane(&pil_u); u3j_gate_prep(&sit_u, u3k(b)); while ( c3n == u3a_pile_done(&pil_u) ) { diff --git a/pkg/urbit/jets/e/parse.c b/pkg/urbit/jets/e/parse.c index 8befe6a804..4d50439e25 100644 --- a/pkg/urbit/jets/e/parse.c +++ b/pkg/urbit/jets/e/parse.c @@ -984,10 +984,6 @@ u3j_site raq_u; u3j_gate_prep(&raq_u, u3k(raq)); - // check for stack overflow - // - u3a_pile_sane(&pil_u); - while ( c3n == u3a_pile_done(&pil_u) ) { p_wag = _last_k(par_u->har, p_wag); puq_wag = u3j_gate_slam(&raq_u, u3nc(par_u->res, puq_wag)); diff --git a/pkg/urbit/noun/allocate.c b/pkg/urbit/noun/allocate.c index 3bbbe0eb23..2a92e64903 100644 --- a/pkg/urbit/noun/allocate.c +++ b/pkg/urbit/noun/allocate.c @@ -13,8 +13,6 @@ void* u3a_pop(const u3a_pile* pil_u); void* u3a_push(const u3a_pile* pil_u); -void -u3a_pile_sane(const u3a_pile* pil_u); c3_o u3a_pile_done(const u3a_pile* pil_u); @@ -1176,7 +1174,6 @@ _ca_take_next_north(u3a_pile* pil_u, u3_noun veb) else { u3a_cell* old_u = (u3a_cell*)veb_u; _ca_take* fam_u = u3a_push(pil_u); - u3a_pile_sane(pil_u); fam_u->hed = u3_none; fam_u->old = veb; @@ -1232,7 +1229,6 @@ _ca_take_next_south(u3a_pile* pil_u, u3_noun veb) else { u3a_cell* old_u = (u3a_cell*)veb_u; _ca_take* fam_u = u3a_push(pil_u); - u3a_pile_sane(pil_u); fam_u->hed = u3_none; fam_u->old = veb; @@ -2656,50 +2652,6 @@ u3a_walk_fore(u3_noun a, else { *top = u3t(a); top = u3a_push(&pil_u); - u3a_pile_sane(&pil_u); - *top = u3h(a); - } - - a = *top; - } -} - -/* u3a_walk_fore_unsafe(): u3a_walk_fore(), without overflow checks -*/ -void -u3a_walk_fore_unsafe(u3_noun a, - void* ptr_v, - void (*pat_f)(u3_atom, void*), - c3_o (*cel_f)(u3_noun, void*)) -{ - u3_noun* top; - u3a_pile pil_u; - - // initialize stack control; push argument - // - u3a_pile_prep(&pil_u, sizeof(u3_noun)); - top = u3a_push(&pil_u); - *top = a; - - while ( c3n == u3a_pile_done(&pil_u) ) { - // visit an atom, then pop the stack - // - if ( c3y == u3a_is_atom(a) ) { - pat_f(a, ptr_v); - top = u3a_pop(&pil_u); - } - // vist a cell, if c3n, pop the stack - // - else if ( c3n == cel_f(a, ptr_v) ) { - top = u3a_pop(&pil_u); - } - // otherwise, push the tail and continue into the head - // - else { - *top = u3t(a); - // NB: overflow check elided here - // - top = u3a_push(&pil_u); *top = u3h(a); } diff --git a/pkg/urbit/noun/nock.c b/pkg/urbit/noun/nock.c index 6065a6c960..6bfe4f3caf 100644 --- a/pkg/urbit/noun/nock.c +++ b/pkg/urbit/noun/nock.c @@ -1444,7 +1444,8 @@ _n_push(c3_ys mov, c3_ys off, u3_noun a) { u3R->cap_p += mov; - // XX stack sanity-check disabled for performance + // XX define symbol to control guard page + // or switch to u3a_push() // #if 0 if ( 0 == off ) { diff --git a/pkg/urbit/noun/retrieve.c b/pkg/urbit/noun/retrieve.c index a6e873c42b..c207c7f47f 100644 --- a/pkg/urbit/noun/retrieve.c +++ b/pkg/urbit/noun/retrieve.c @@ -1732,10 +1732,6 @@ _cr_mug_next(u3a_pile* pil_u, u3_noun veb) u3a_cell* cel_u = (u3a_cell*)veb_u; _cr_mugf* fam_u = u3a_push(pil_u); - // check for overflow - // - u3a_pile_sane(pil_u); - fam_u->mug_l = 0; fam_u->cel = veb; diff --git a/pkg/urbit/noun/serial.c b/pkg/urbit/noun/serial.c index ae0a78310c..26cc05f24a 100644 --- a/pkg/urbit/noun/serial.c +++ b/pkg/urbit/noun/serial.c @@ -158,15 +158,9 @@ u3s_jam_fib(u3i_slab* sab_u, u3_noun a) fib_u.bit_w = 0; u3i_slab_init(sab_u, 0, fib_u.a_w); - // as this is a hot path, we unsafely elide overflow checks - // - // a page-fault overflow detection system is urgently needed ... - // - u3a_walk_fore_unsafe(a, &fib_u, _cs_jam_fib_atom_cb, - _cs_jam_fib_cell_cb); + u3a_walk_fore(a, &fib_u, _cs_jam_fib_atom_cb, _cs_jam_fib_cell_cb); u3h_free(fib_u.har_p); - return fib_u.bit_w; } @@ -270,18 +264,11 @@ u3s_jam_xeno(u3_noun a, c3_d* len_d, c3_y** byt_y) { _jam_xeno_t jam_u = {0}; ur_bsw_init(&jam_u.rit_u, ur_fib11, ur_fib12); - jam_u.har_p = u3h_new(); - // as this is a hot path, we unsafely elide overflow checks - // - // a page-fault overflow detection system is urgently needed ... - // - u3a_walk_fore_unsafe(a, &jam_u, _cs_jam_xeno_atom, - _cs_jam_xeno_cell); + u3a_walk_fore(a, &jam_u, _cs_jam_xeno_atom, _cs_jam_xeno_cell); u3h_free(jam_u.har_p); - return ur_bsw_done(&jam_u.rit_u, len_d, byt_y); } @@ -360,7 +347,6 @@ _cs_cue_next(u3a_pile* pil_u, // else { _cs_cue* fam_u = u3a_push(pil_u); - u3a_pile_sane(pil_u); // NB: fam_u->wid unused in head-frame // @@ -472,7 +458,6 @@ _cs_cue_xeno_next(u3a_pile* pil_u, case ur_jam_cell: { _cue_frame_t* fam_u = u3a_push(pil_u); - u3a_pile_sane(pil_u); fam_u->ref = u3_none; fam_u->bit_d = bit_d; @@ -731,7 +716,6 @@ _cs_cue_bytes_next(u3a_pile* pil_u, case ur_jam_cell: { _cue_frame_t* fam_u = u3a_push(pil_u); - u3a_pile_sane(pil_u); fam_u->ref = u3_none; fam_u->bit_d = bit_d; From 9d5b24362e1faafe552b68302cd9838a25c68792 Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Thu, 7 Jul 2022 01:33:23 -0400 Subject: [PATCH 15/21] u3: failure to mprotect() the new guard page is fatal --- pkg/urbit/noun/events.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/urbit/noun/events.c b/pkg/urbit/noun/events.c index 914de93878..455137efce 100644 --- a/pkg/urbit/noun/events.c +++ b/pkg/urbit/noun/events.c @@ -227,7 +227,9 @@ _ce_center_guard_page(void) "loom: failed to protect the guard page " "(base address %p)\r\n", u3a_into(gar_pag_p)); - goto fail; + // XX this should probably return 0 through the libsigsegv protocol + // -- we couldn't handle the fault + c3_assert(0); } return; From 8fb3b1502b87e694c206a7c7ed83bb4a881afd86 Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Thu, 7 Jul 2022 01:33:44 -0400 Subject: [PATCH 16/21] build: make bench is phony --- pkg/urbit/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/urbit/Makefile b/pkg/urbit/Makefile index e6c4fe5bc6..6b934bc790 100644 --- a/pkg/urbit/Makefile +++ b/pkg/urbit/Makefile @@ -33,7 +33,7 @@ CFLAGS := $(CFLAGS) ################################################################################ -.PHONY: all test clean mrproper +.PHONY: all bench test clean mrproper ################################################################################ From 53af044d18a27dcff7dfa1a570828c177c960957 Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Thu, 7 Jul 2022 01:17:25 -0400 Subject: [PATCH 17/21] Revert "u3: check for road stack overflow on every nock %2 and %9" This reverts commit 4bd4e8a4a9104a967262536d6d9f07e68bdd79e8. --- pkg/urbit/noun/nock.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/pkg/urbit/noun/nock.c b/pkg/urbit/noun/nock.c index 6bfe4f3caf..dd885a8d8c 100644 --- a/pkg/urbit/noun/nock.c +++ b/pkg/urbit/noun/nock.c @@ -1839,23 +1839,6 @@ _n_kale(u3_noun a) return a; } -/* _n_sane(): check for stack overflow -*/ -static inline void -_n_sane(c3_ys off_ys) -{ - if ( !off_ys ) { - if( !(u3R->cap_p > u3R->hat_p) ) { - u3m_bail(c3__meme); - } - } - else { - if( !(u3R->cap_p < u3R->hat_p) ) { - u3m_bail(c3__meme); - } - } -} - typedef struct { u3n_prog* pog_u; c3_w ip_w; @@ -2096,7 +2079,6 @@ _n_burn(u3n_prog* pog_u, u3_noun bus, c3_ys mov, c3_ys off) x = _n_pep(mov, off); fam = u3to(burnframe, u3R->cap_p) + off + mov; u3R->cap_p = u3of(burnframe, fam - off); - _n_sane(off); fam->ip_w = ip_w; fam->pog_u = pog_u; _n_push(mov, off, x); @@ -2259,7 +2241,6 @@ _n_burn(u3n_prog* pog_u, u3_noun bus, c3_ys mov, c3_ys off) fam = u3to(burnframe, u3R->cap_p) + off + mov; u3R->cap_p = u3of(burnframe, fam - off); - _n_sane(off); fam->ip_w = ip_w; fam->pog_u = pog_u; From b7cd97664dc00a961d0e96c7dc9d168636fda04f Mon Sep 17 00:00:00 2001 From: Peter McEvoy Date: Thu, 7 Jul 2022 09:33:41 -0700 Subject: [PATCH 18/21] u3: control presence of guard page using macro --- nix/pkgs/urbit/default.nix | 1 + pkg/urbit/configure | 1 + pkg/urbit/include/noun/allocate.h | 14 ++++++-------- pkg/urbit/noun/events.c | 9 ++++++++- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/nix/pkgs/urbit/default.nix b/nix/pkgs/urbit/default.nix index e9da7b305b..c9023c077d 100644 --- a/nix/pkgs/urbit/default.nix +++ b/nix/pkgs/urbit/default.nix @@ -68,6 +68,7 @@ in stdenv.mkDerivation { CFLAGS = oFlags ++ lib.optionals (!enableDebug) [ "-Werror" ]; + GUARD_PAGE = true; MEMORY_DEBUG = enableDebug; CPU_DEBUG = enableDebug; EVENT_TIME_DEBUG = false; diff --git a/pkg/urbit/configure b/pkg/urbit/configure index 22958e3ed6..54be912e57 100755 --- a/pkg/urbit/configure +++ b/pkg/urbit/configure @@ -64,6 +64,7 @@ do shift done +[ -n "${GUARD_PAGE-}" ] && defmacro U3_GUARD_PAGE 1 [ -n "${MEMORY_DEBUG-}" ] && defmacro U3_MEMORY_DEBUG 1 [ -n "${MEMORY_LOG-}" ] && defmacro U3_MEMORY_LOG 1 [ -n "${CPU_DEBUG-}" ] && defmacro U3_CPU_DEBUG 1 diff --git a/pkg/urbit/include/noun/allocate.h b/pkg/urbit/include/noun/allocate.h index 13f4a545fb..529ad6fb60 100644 --- a/pkg/urbit/include/noun/allocate.h +++ b/pkg/urbit/include/noun/allocate.h @@ -398,28 +398,26 @@ { u3R->cap_p += pil_u->mov_ws; - // XX define symbol to control guard page - // -#if 0 +#ifndef U3_GUARD_PAGE // !off means we're on a north road // if ( !pil_u->off_ws ) { if( !(u3R->cap_p > u3R->hat_p) ) { u3m_bail(c3__meme); } - #ifdef U3_MEMORY_DEBUG +# ifdef U3_MEMORY_DEBUG c3_assert( pil_u->top_p >= u3R->cap_p ); - #endif +# endif } else { if( !(u3R->cap_p < u3R->hat_p) ) { u3m_bail(c3__meme); } - #ifdef U3_MEMORY_DEBUG +# ifdef U3_MEMORY_DEBUG c3_assert( pil_u->top_p <= u3R->cap_p ); - #endif +# endif } -#endif +#endif /* ifndef U3_GUARD_PAGE */ #ifdef U3_MEMORY_DEBUG c3_assert( pil_u->rod_u == u3R ); diff --git a/pkg/urbit/noun/events.c b/pkg/urbit/noun/events.c index 455137efce..3d4d47e104 100644 --- a/pkg/urbit/noun/events.c +++ b/pkg/urbit/noun/events.c @@ -186,6 +186,7 @@ _ce_mapfree(void* map_v) } #endif +#ifdef U3_GUARD_PAGE //! Place a guard page at the (approximate) middle of the free space between //! the heap and stack of the current road, bailing if memory has been //! exhausted. @@ -237,6 +238,7 @@ _ce_center_guard_page(void) fail: u3m_signal(c3__meme); } +#endif /* ifdef U3_GUARD_PAGE */ /* u3e_fault(): handle a memory event with libsigsegv protocol. */ @@ -265,11 +267,14 @@ u3e_fault(void* adr_v, c3_i ser_i) c3_w blk_w = (pag_w >> 5); c3_w bit_w = (pag_w & 31); +#ifdef U3_GUARD_PAGE // The fault happened in the guard page. if ( gar_pag_p <= adr_p && adr_p < gar_pag_p + pag_wiz_i ) { _ce_center_guard_page(); } - else if ( 0 != (u3P.dit_w[blk_w] & (1 << bit_w)) ) { + else +#endif /* ifdef U3_GUARD_PAGE */ + if ( 0 != (u3P.dit_w[blk_w] & (1 << bit_w)) ) { fprintf(stderr, "strange page: %d, at %p, off %x\r\n", pag_w, adr_w, adr_p); c3_assert(0); return 0; @@ -1093,5 +1098,7 @@ u3e_foul(void) void u3e_init(void) { +#ifdef U3_GUARD_PAGE _ce_center_guard_page(); +#endif } From abe5788daf75fa95070aa75d7254f27a0bbf48dc Mon Sep 17 00:00:00 2001 From: Peter McEvoy Date: Thu, 7 Jul 2022 09:39:35 -0700 Subject: [PATCH 19/21] u3: return 0 from u3e_fault() if guard page cannot be protected --- pkg/urbit/noun/events.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/pkg/urbit/noun/events.c b/pkg/urbit/noun/events.c index 3d4d47e104..6986e91a22 100644 --- a/pkg/urbit/noun/events.c +++ b/pkg/urbit/noun/events.c @@ -190,7 +190,7 @@ _ce_mapfree(void* map_v) //! Place a guard page at the (approximate) middle of the free space between //! the heap and stack of the current road, bailing if memory has been //! exhausted. -static void +static c3_i _ce_center_guard_page(void) { u3p(c3_w) bot_p, top_p; @@ -210,7 +210,7 @@ _ce_center_guard_page(void) if ( top_p < bot_p + pag_wiz_i ) { fprintf(stderr, "loom: not enough memory to recenter the guard page\r\n"); - goto fail; + goto bail; } const u3p(c3_w) old_gar_p = gar_pag_p; const c3_w mid_p = (top_p - bot_p) / 2; @@ -220,7 +220,7 @@ _ce_center_guard_page(void) "loom: can't move the guard page to the same location" " (base address %p)\r\n", u3a_into(gar_pag_p)); - goto fail; + goto bail; } if ( -1 == mprotect(u3a_into(gar_pag_p), pag_siz_i, PROT_NONE) ) { @@ -228,15 +228,15 @@ _ce_center_guard_page(void) "loom: failed to protect the guard page " "(base address %p)\r\n", u3a_into(gar_pag_p)); - // XX this should probably return 0 through the libsigsegv protocol - // -- we couldn't handle the fault - c3_assert(0); + goto fail; } - return; + return 1; -fail: +bail: u3m_signal(c3__meme); +fail: + return 0; } #endif /* ifdef U3_GUARD_PAGE */ @@ -270,7 +270,9 @@ u3e_fault(void* adr_v, c3_i ser_i) #ifdef U3_GUARD_PAGE // The fault happened in the guard page. if ( gar_pag_p <= adr_p && adr_p < gar_pag_p + pag_wiz_i ) { - _ce_center_guard_page(); + if ( 0 == _ce_center_guard_page() ) { + return 0; + } } else #endif /* ifdef U3_GUARD_PAGE */ From 517ca69823716e226a6edf7336b84ccb442931cd Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Fri, 8 Jul 2022 14:37:39 -0400 Subject: [PATCH 20/21] build: default to using guard page --- nix/pkgs/urbit/default.nix | 1 - pkg/urbit/configure | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/nix/pkgs/urbit/default.nix b/nix/pkgs/urbit/default.nix index c9023c077d..e9da7b305b 100644 --- a/nix/pkgs/urbit/default.nix +++ b/nix/pkgs/urbit/default.nix @@ -68,7 +68,6 @@ in stdenv.mkDerivation { CFLAGS = oFlags ++ lib.optionals (!enableDebug) [ "-Werror" ]; - GUARD_PAGE = true; MEMORY_DEBUG = enableDebug; CPU_DEBUG = enableDebug; EVENT_TIME_DEBUG = false; diff --git a/pkg/urbit/configure b/pkg/urbit/configure index 54be912e57..a01d032c4f 100755 --- a/pkg/urbit/configure +++ b/pkg/urbit/configure @@ -64,7 +64,7 @@ do shift done -[ -n "${GUARD_PAGE-}" ] && defmacro U3_GUARD_PAGE 1 +[ -z "${NO_GUARD_PAGE-}" ] && defmacro U3_GUARD_PAGE 1 [ -n "${MEMORY_DEBUG-}" ] && defmacro U3_MEMORY_DEBUG 1 [ -n "${MEMORY_LOG-}" ] && defmacro U3_MEMORY_LOG 1 [ -n "${CPU_DEBUG-}" ] && defmacro U3_CPU_DEBUG 1 From ae370dd7e03614ff16cb7be57590ded50277502d Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Fri, 8 Jul 2022 14:38:32 -0400 Subject: [PATCH 21/21] u3: check for overflow in interpreter if guard page not present --- pkg/urbit/noun/nock.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pkg/urbit/noun/nock.c b/pkg/urbit/noun/nock.c index dd885a8d8c..3722f1d619 100644 --- a/pkg/urbit/noun/nock.c +++ b/pkg/urbit/noun/nock.c @@ -1444,10 +1444,9 @@ _n_push(c3_ys mov, c3_ys off, u3_noun a) { u3R->cap_p += mov; - // XX define symbol to control guard page - // or switch to u3a_push() + // XX switch to u3a_push() // -#if 0 +#ifndef U3_GUARD_PAGE if ( 0 == off ) { if( !(u3R->cap_p > u3R->hat_p) ) { u3m_bail(c3__meme);