kcar RubyGem user+dev discussion/patches/pulls/bugs/help
 help / color / mirror / code / Atom feed
* [PATCH] reduce parser size to 88 bytes on 64-bit
@ 2017-03-05  1:10 Eric Wong
  0 siblings, 0 replies; only message in thread
From: Eric Wong @ 2017-03-05  1:10 UTC (permalink / raw)
  To: kcar-public

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 <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
+#include <limits.h>
 #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


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2017-03-05  1:10 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-05  1:10 [PATCH] reduce parser size to 88 bytes on 64-bit Eric Wong

Code repositories for project(s) associated with this public inbox

	https://yhbt.net/kcar.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).