From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: X-Spam-Status: No, score=-4.0 required=3.0 tests=ALL_TRUSTED,BAYES_00 shortcircuit=no autolearn=ham autolearn_force=no version=3.4.0 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 4407B1FBEC for ; Sun, 5 Mar 2017 01:10:54 +0000 (UTC) From: Eric Wong To: kcar-public@bogomips.org Subject: [PATCH] reduce parser size to 88 bytes on 64-bit Date: Sun, 5 Mar 2017 01:10:54 +0000 Message-Id: <20170305011054.30573-1-e@80x24.org> List-Id: The actual struct we manage is 48 bytes, along with 40 bytes for object overhead. --- ext/kcar/kcar.rl | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/ext/kcar/kcar.rl b/ext/kcar/kcar.rl index 4c66fb5..e015bdb 100644 --- a/ext/kcar/kcar.rl +++ b/ext/kcar/kcar.rl @@ -10,6 +10,7 @@ #include #include #include +#include #include "c_util.h" static VALUE eParserError; @@ -47,15 +48,15 @@ DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32))); struct http_parser { int cs; /* Ragel internal state */ unsigned int flags; - size_t mark; - size_t offset; + unsigned int mark; + unsigned int offset; union { /* these 2 fields don't nest */ - size_t field; - size_t query; + unsigned int field; + unsigned int query; } start; union { - size_t field_len; /* only used during header processing */ - size_t dest_offset; /* only used during body processing */ + unsigned int field_len; /* only used during header processing */ + unsigned int dest_offset; /* only used during body processing */ } s; VALUE cont; /* Qfalse: unset, Qnil: ignored header, T_STRING: append */ VALUE status; /* String or Qnil */ @@ -65,9 +66,21 @@ struct http_parser { } len; }; +static unsigned int ulong2uint(unsigned long n) +{ + unsigned int i = (unsigned int)n; + + if (sizeof(unsigned int) != sizeof(unsigned long)) { + if ((unsigned long)i != n) { + rb_raise(rb_eRangeError, "too large to be 32-bit uint: %lu", n); + } + } + return i; +} + #define REMAINING (unsigned long)(pe - p) -#define LEN(AT, FPC) (FPC - buffer - hp->AT) -#define MARK(M,FPC) (hp->M = (FPC) - buffer) +#define LEN(AT, FPC) (ulong2uint(FPC - buffer) - hp->AT) +#define MARK(M,FPC) (hp->M = ulong2uint((FPC) - buffer)) #define PTR_TO(F) (buffer + hp->F) #define STR_NEW(M,FPC) rb_str_new(PTR_TO(M), LEN(M, FPC)) #define STRIPPED_STR_NEW(M,FPC) stripped_str_new(PTR_TO(M), LEN(M, FPC)) @@ -403,7 +416,7 @@ static void http_parser_execute(struct http_parser *hp, post_exec: /* "_out:" also goes here */ if (hp->cs != http_parser_error) hp->cs = cs; - hp->offset = p - buffer; + hp->offset = ulong2uint(p - buffer); assert(p <= pe && "buffer overflow after parsing execute"); assert(hp->offset <= len && "offset longer than length"); @@ -537,6 +550,12 @@ static VALUE chunked(VALUE self) return HP_FL_TEST(hp, CHUNKED) ? Qtrue : Qfalse; } +static void check_buffer_size(long dlen) +{ + if (dlen > UINT_MAX) + rb_raise(rb_eRangeError, "headers too large to process (%ld bytes)", dlen); +} + /** * Document-method: headers * call-seq: @@ -552,8 +571,10 @@ static VALUE chunked(VALUE self) static VALUE headers(VALUE self, VALUE hdr, VALUE data) { struct http_parser *hp = data_get(self); + long dlen = RSTRING_LEN(data); - http_parser_execute(hp, hdr, RSTRING_PTR(data), RSTRING_LEN(data)); + check_buffer_size(dlen); + http_parser_execute(hp, hdr, RSTRING_PTR(data), dlen); VALIDATE_MAX_LENGTH(hp->offset, HEADER); if (hp->cs == http_parser_first_final || @@ -653,6 +674,7 @@ static VALUE filter_body(VALUE self, VALUE buf, VALUE data) dptr = RSTRING_PTR(data); dlen = RSTRING_LEN(data); + check_buffer_size(dlen); StringValue(buf); rb_str_modify(buf); -- EW