From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: X-Spam-Status: No, score=-3.6 required=3.0 tests=ALL_TRUSTED,AWL,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,NORMAL_HTTP_TO_IP, NUMERIC_HTTP_ADDR shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id D42391F61A for ; Fri, 16 Dec 2022 14:39:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=80x24.org; s=selector1; t=1671201573; bh=fLWMXdNlPoplykZXG2rmVILZH40msZdCIQ6Wyg5dxMg=; h=From:To:Subject:Date:In-Reply-To:References:From; b=V2VFi9/+BJ99qqJY+ghlTwpTlAV6N6pa3iog2gES5DKm3b/paKQvhGCzHSeI7CAm1 DwTdXi1OYTszyKG/2FLME+4onWMX8n9cYJrGij1XgJA0vy/CBqK3TVm7xeZ4JPA6gy IhmqDgM7tCXmJs2tv9Xc1uYR5Ih3xk0HTGuKt7jo= From: Eric Wong To: mwrap-perl@80x24.org Subject: [PATCH 1/3] support changing bt_req_depth dynamically Date: Fri, 16 Dec 2022 14:39:31 +0000 Message-Id: <20221216143933.22430-2-e@80x24.org> In-Reply-To: <20221216143933.22430-1-e@80x24.org> References: <20221216143933.22430-1-e@80x24.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: This is a valuable tuning knob and allows users to forgo restarting an app to change backtrace depth. A /reset is recommended. --- Mwrap.xs | 16 ++++++++++++ httpd.h | 70 +++++++++++++++++++++++++++++++++++++++++++++------- mwrap_core.h | 11 +++++---- t/httpd.t | 4 +++ t/mwrap.t | 8 ++++++ 5 files changed, 95 insertions(+), 14 deletions(-) diff --git a/Mwrap.xs b/Mwrap.xs index 568ec2b..846d89d 100644 --- a/Mwrap.xs +++ b/Mwrap.xs @@ -132,6 +132,22 @@ mwrap_reset() CODE: mwrap_reset(); +unsigned +mwrap_bt_depth(arg = &PL_sv_undef) + SV *arg; +CODE: + if (SvOK(arg)) { + UV n = SvUVx(arg); + if (n > MWRAP_BT_MAX) + n = MWRAP_BT_MAX; + CMM_STORE_SHARED(bt_req_depth, (uint32_t)n); + RETVAL = n; + } else { + RETVAL = CMM_LOAD_SHARED(bt_req_depth); + } +OUTPUT: + RETVAL + Devel::Mwrap::SrcLoc mwrap_get(loc) SV *loc; diff --git a/httpd.h b/httpd.h index 9b4ebe7..fc7b873 100644 --- a/httpd.h +++ b/httpd.h @@ -41,6 +41,7 @@ #define URL "https://80x24.org/mwrap-perl.git/about" #define TYPE_HTML "text/html; charset=UTF-8" #define TYPE_CSV "text/csv" +#define TYPE_PLAIN "text/plain" enum mw_qev { MW_QEV_IGNORE = 0, @@ -341,6 +342,15 @@ static enum mw_qev h1_do_trim(struct mw_h1 *h1) return h1_res_oneshot(h1, r200, sizeof(r200) - 1); } +static enum mw_qev h1_do_ctl_finish(struct mw_h1 *h1) +{ + struct mw_fbuf plain; + FILE *fp = wbuf_init(&plain); + if (!fp) return h1_close(h1); + fprintf(fp, "MWRAP=bt:%u\n", (unsigned)CMM_LOAD_SHARED(bt_req_depth)); + return h1_200(h1, &plain, TYPE_PLAIN); +} + #define PATH_SKIP(h1r, pfx) path_skip(h1r, pfx, sizeof(pfx) - 1) static const char *path_skip(struct mw_h1req *h1r, const char *pfx, size_t len) { @@ -570,7 +580,7 @@ static enum mw_qev each_at(struct mw_h1 *h1, struct mw_h1req *h1r) FPUTS("", fp); write_html(fp, lb.ptr, lb.len); FPUTS("

live allocations at:", fp); - if (bt_req_depth) FPUTS("
", fp); + if (l->bt_len > 1 || (l->bt_len == 1 && l->f)) FPUTS("
", fp); else fputc(' ', fp); write_html(fp, lb.ptr, lb.len); @@ -627,13 +637,14 @@ static enum mw_qev each_gt(struct mw_h1 *h1, struct mw_h1req *h1r, if (!fp) return h1_close(h1); if (!csv) { + unsigned depth = (unsigned)CMM_LOAD_SHARED(bt_req_depth); fprintf(fp, "mwrap each >%lu" "

mwrap each >%lu " "(change `%lu' in URL to adjust filtering) - " - "MWRAP=bt:%u", min, min, min, (unsigned)bt_req_depth); + "MWRAP=bt:%u", min, min, min, depth); show_stats(fp); /* need borders to distinguish multi-level traces */ - if (bt_req_depth) + if (depth) FPUTS("", fp); else /* save screen space if only tracing one line */ FPUTS("", fp); @@ -757,6 +768,8 @@ static enum mw_qev h1_dispatch(struct mw_h1 *h1, struct mw_h1req *h1r) return h1_do_reset(h1); if (h1r->path_len == 5 && !memcmp(h1r->path, "/trim", 5)) return h1_do_trim(h1); + if (h1r->path_len == 4 && !memcmp(h1r->path, "/ctl", 4)) + return h1_do_ctl_finish(h1); } return h1_404(h1); } @@ -816,12 +829,31 @@ static enum mw_qev h1_drain_input(struct mw_h1 *h1, struct mw_h1req *h1r) return h1_dispatch(h1, h1r); } +static bool valid_end(const char *end) +{ + switch (*end) { + case '\r': case ' ': case '\t': case '\n': return true; + default: return false; + } +} + +/* no error reporting, too much code */ +static void ctl_set(struct mw_h1 *h1, long n) +{ + if (n >= 0) { + if (n > MWRAP_BT_MAX) + n = MWRAP_BT_MAX; + CMM_STORE_SHARED(bt_req_depth, (uint32_t)n); + } +} + static enum mw_qev h1_parse_harder(struct mw_h1 *h1, struct mw_h1req *h1r) { enum { HDR_IGN, HDR_CONN, HDR_XENC, HDR_CLEN } cur = HDR_IGN; bool conn_set = false; char *end; struct phr_header *hdr = h1r->hdr; + long depth = -1; h1->prev_len = 0; h1->has_input = 0; @@ -837,8 +869,21 @@ static enum mw_qev h1_parse_harder(struct mw_h1 *h1, struct mw_h1req *h1r) cur = HDR_CONN; else if (NAME_EQ(hdr, "Trailer")) return h1_400(h1); - else if (hdr->name) + else if (hdr->name) { cur = HDR_IGN; + /* + * don't want to increase code to deal with POST + * request bodies, so let pico handle parameters in + * HTTP request headers, instead. + */ + if (NAME_EQ(hdr, "X-Mwrap-BT-Depth")) { + errno = 0; + depth = strtol(hdr->value, &end, 10); + if (errno || !valid_end(end)) + depth = -1; + } + } + /* else: continuation line */ if (!hdr->value_len) continue; @@ -860,12 +905,8 @@ static enum mw_qev h1_parse_harder(struct mw_h1 *h1, struct mw_h1req *h1r) h1->has_input = 1; errno = 0; h1->in_len = strtoul(hdr->value, &end, 10); - if (errno) + if (errno || !valid_end(end)) return h1_400(h1); - switch (*end) { - case '\r': case ' ': case '\t': case '\n': break; - default: return h1_400(h1); - } break; case HDR_IGN: break; @@ -883,6 +924,17 @@ static enum mw_qev h1_parse_harder(struct mw_h1 *h1, struct mw_h1req *h1r) } else { return h1_404(h1); } + + /* + * special case for /ctl, since I don't feel like parsing queries + * in the request body (ensure no query string, too) + */ + if (h1r->method_len == 4 && !memcmp(h1r->method, "POST", 4)) { + if (h1r->path_len == 4 && !memcmp(h1r->path, "/ctl", 4)) + ctl_set(h1, depth); + } + + /* break off QUERY_STRING */ h1r->qstr = memchr(h1r->path, '?', h1r->path_len); if (h1r->qstr) { ++h1r->qstr; /* ignore '?' */ diff --git a/mwrap_core.h b/mwrap_core.h index 3fd67f1..9e4f065 100644 --- a/mwrap_core.h +++ b/mwrap_core.h @@ -13,6 +13,7 @@ typedef void COP; #endif +/* set a sensible max to avoid stack overflows */ #ifndef MWRAP_BT_MAX # define MWRAP_BT_MAX 32 #endif @@ -136,14 +137,14 @@ static void *my_mempcpy(void *dest, const void *src, size_t n) #define SRC_LOC_BT(bt) union stk_bt bt; do { \ - uint32_t depth = locating ? 1 : bt_req_depth; \ + uint32_t depth = locating ? 1 : CMM_LOAD_SHARED(bt_req_depth); \ switch (depth) { \ case 0: \ case 1: bt.sl.bt_len = 1; bt.sl.bt[0] = RETURN_ADDRESS(0); break; \ default: /* skip 1st level of BT since thats our function */ \ - mwrap_assert(bt_req_depth <= MWRAP_BT_MAX); \ + mwrap_assert(depth <= MWRAP_BT_MAX); \ ++locating; \ - long n = (long)backtrace(bt_dst(&bt), bt_req_depth); \ + long n = (long)backtrace(bt_dst(&bt), depth); \ --locating; \ bt.sl.bt_len = n <= 1 ? 0 : (uint32_t)n - 1; \ if (n > 1) mwrap_assert(bt.sl.bt[0] == RETURN_ADDRESS(0)); \ @@ -1026,9 +1027,9 @@ __attribute__((constructor)) static void mwrap_ctor(void) char *end; unsigned long n = strtoul(bt, &end, 10); if (n && !errno && (*end == ',' || *end == 0)) { - if (n >= MWRAP_BT_MAX) + if (n > MWRAP_BT_MAX) n = MWRAP_BT_MAX; - bt_req_depth = (uint32_t)n; + CMM_STORE_SHARED(bt_req_depth, (uint32_t)n); } } } diff --git a/t/httpd.t b/t/httpd.t index 176c6ed..3fe9c1f 100644 --- a/t/httpd.t +++ b/t/httpd.t @@ -157,6 +157,10 @@ SKIP: { $rc = system(qw(curl -vsSf --unix-socket), $sock, '-o', $cout, '-d', 'x=y', "http://0/$pid/reset"); is($rc, 0, 'curl /reset'); + $rc = system(qw(curl -vsSf --unix-socket), $sock, '-o', $cout, + '-HX-Mwrap-BT-Depth:10', '-XPOST', "http://0/$pid/ctl"); + is($rc, 0, 'curl /ctl (X-Mwrap-BT-Depth)'); + like(slurp($cout), qr/\bMWRAP=bt:10\b/, 'changed bt depth'); }; diff --git a/t/mwrap.t b/t/mwrap.t index bf6ae6e..76a2366 100644 --- a/t/mwrap.t +++ b/t/mwrap.t @@ -166,4 +166,12 @@ EOM 'aligned_alloc + cfree function ran w/o crashing'); }; +is(Devel::Mwrap::bt_depth(), 0, 'default bt depth is zero'); +is(Devel::Mwrap::bt_depth(5), 5, 'set depth to reasonable level'); +is(Devel::Mwrap::bt_depth(), 5, 'depth stays at 5'); +is(Devel::Mwrap::bt_depth(500), 32, 'depth clamped to 32 when 500 attempted'); +is(Devel::Mwrap::bt_depth(), 32, 'depth stayed clamped at 32'); +is(Devel::Mwrap::bt_depth(undef), 32, 'depth stayed clamped at 32'); +is(Devel::Mwrap::bt_depth(-1), 32, 'depth stayed clamped at 32'); + done_testing;