From 13395d8a54245380f13a1c588166d3d4c5a04e2c Mon Sep 17 00:00:00 2001
From: "Meredith L. Patterson" <clonearmy@gmail.com>
Date: Thu, 24 May 2012 13:22:43 +0200
Subject: [PATCH] counted_array now holds parsed_token_t's. TQ will fix the
 problem with accumulate_size. Compile-time bounds checks added to int_range.

---
 examples/dns.c | 35 +++++++++++++++++++++++-----------
 src/hammer.c   | 51 ++++++++++++++++++++++++++++----------------------
 src/hammer.h   |  4 +++-
 3 files changed, 56 insertions(+), 34 deletions(-)

diff --git a/examples/dns.c b/examples/dns.c
index 26f48549..c2fc59d3 100644
--- a/examples/dns.c
+++ b/examples/dns.c
@@ -5,7 +5,7 @@
 
 bool is_zero(parse_result_t *p) {
   if (TT_UINT != p->ast->token_type)
-    return 0;
+    return false;
   return (0 == p->ast->uint);
 }
 
@@ -14,7 +14,7 @@ bool is_zero(parse_result_t *p) {
  */
 bool validate_label(parse_result_t *p) {
   if (TT_SEQUENCE != p->ast->token_type)
-    return 0;
+    return false;
   return (64 > p->ast->seq->used);
 }
 
@@ -25,19 +25,20 @@ bool validate_label(parse_result_t *p) {
  */
 bool validate_dns(parse_result_t *p) {
   if (TT_SEQUENCE != p->ast->token_type)
-    return 0;
+    return false;
   // The header holds the counts as its last 4 elements.
   parsed_token_t *header = p->ast->seq->elements[0];
-  size_t qd = ((parsed_token_t*)header->seq->elements[8])->uint;
-  size_t an = ((parsed_token_t*)header->seq->elements[9])->uint;
-  size_t ns = ((parsed_token_t*)header->seq->elements[10])->uint;
-  size_t ar = ((parsed_token_t*)header->seq->elements[11])->uint;
+  size_t qd = header->seq->elements[8]->uint;
+  size_t an = header->seq->elements[9]->uint;
+  size_t ns = header->seq->elements[10]->uint;
+  size_t ar = header->seq->elements[11]->uint;
   parsed_token_t *questions = p->ast->seq->elements[1];
   if (questions->seq->used != qd)
-    return 0;
+    return false;
   parsed_token_t *rrs = p->ast->seq->elements[2];
   if (an+ns+ar != rrs->seq->used)
-    return 0;
+    return false;
+  return true;
 }
 
 parser_t* init_parser() {
@@ -60,9 +61,21 @@ parser_t* init_parser() {
 				       uint16(), // ARCOUNT
 				       NULL);
 
+  const parser_t *type = int_range(uint16(), 1, 16);
+
+  const parser_t *qtype = choice(type, 
+				 int_range(uint16(), 252, 255),
+				 NULL);
+
+  const parser_t *class = int_range(uint16(), 1, 4);
+  
+  const parser_t *qclass = choice(class,
+				  int_range(uint16(), 255, 255),
+				  NULL);
+
   const parser_t *dns_question = sequence(length_value(uint8(), uint8()), // QNAME
-					  uint16(),                       // QTYPE
-					  uint16(),                       // QCLASS
+					  qtype,                          // QTYPE
+					  qclass,                         // QCLASS
 					  NULL);
 
   const parser_t *letter = choice(ch_range('a', 'z'),
diff --git a/src/hammer.c b/src/hammer.c
index cad143ab..bb033114 100644
--- a/src/hammer.c
+++ b/src/hammer.c
@@ -19,10 +19,11 @@
 #include "internal.h"
 #include "allocator.h"
 #include <assert.h>
-#include <string.h>
-#include <stdarg.h>
 #include <ctype.h>
 #include <error.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <string.h>
 
 #define a_new_(arena, typ, count) ((typ*)arena_malloc((arena), sizeof(typ)*(count)))
 #define a_new(typ, count) a_new_(state->arena, typ, count)
@@ -407,10 +408,34 @@ static parse_result_t* parse_int_range(void *env, parse_state_t *state) {
 
 const parser_t* int_range(const parser_t *p, const int64_t lower, const int64_t upper) {
   struct bits_env *b_env = p->env;
-  // p must be an integer parser, which means it's using parse_bits;
-  // if it's a uint parser, it can't be uint64
+  // p must be an integer parser, which means it's using parse_bits
   assert_message(p->fn == parse_bits, "int_range requires an integer parser"); 
+  // if it's a uint parser, it can't be uint64
   assert_message(!(b_env->signedp) ? (b_env->length < 64) : true, "int_range can't use a uint64 parser");
+  // and regardless, the bounds need to fit in the parser in question
+  switch(b_env->length) {
+  case 32:
+    if (b_env->signedp)
+      assert_message(lower >= INT_MIN && upper <= INT_MAX, "bounds for 32-bit signed integer exceeded");
+    else
+      assert_message(lower >= 0 && upper <= UINT_MAX, "bounds for 32-bit unsigned integer exceeded");
+    break;
+  case 16:
+    if (b_env->signedp)
+      assert_message(lower >= SHRT_MIN && upper <= SHRT_MAX, "bounds for 16-bit signed integer exceeded");
+    else
+      assert_message(lower >= 0 && upper <= USHRT_MAX, "bounds for 16-bit unsigned integer exceeded");
+    break;
+  case 8:
+    if (b_env->signedp)
+      assert_message(lower >= SCHAR_MIN && upper <= SCHAR_MAX, "bounds for 8-bit signed integer exceeded");
+    else
+      assert_message(lower >= 0 && upper <= UCHAR_MAX, "bounds for 8-bit unsigned integer exceeded");
+    break;
+  default:
+    // how'd that happen? if we got here, this parser is broken.
+    return NULL;
+  }
 
   range_t *r_env = g_new(range_t, 1);
   r_env->p = p;
@@ -557,24 +582,6 @@ typedef struct {
 } two_parsers_t;
 
 size_t accumulate_size(parse_result_t *pr) {
-  if (NULL != ((parse_result_t*)pr)->ast) {
-    switch (pr->ast->token_type) {
-    case TT_BYTES:
-      return pr->ast->bytes.len;
-    case TT_SINT:
-    case TT_UINT:
-      return sizeof(pr->ast->uint);
-    case TT_SEQUENCE: {
-      counted_array_t *arr = pr->ast->seq;
-      size_t ret = 0;
-      for (size_t i = 0; i < arr->used; i++)
-	ret += accumulate_size(arr->elements[i]);
-      return ret;
-    }
-    default:
-      return 0;
-    }
-  } // no else, if the AST is null then acc doesn't change
   return 0;
 }
 
diff --git a/src/hammer.h b/src/hammer.h
index c59cdbc6..ae6346c4 100644
--- a/src/hammer.h
+++ b/src/hammer.h
@@ -41,11 +41,13 @@ typedef enum token_type {
   TT_MAX
 } token_type_t;
 
+typedef struct parsed_token parsed_token_t;
+
 typedef struct counted_array {
   size_t capacity;
   size_t used;
   arena_t arena;
-  void **elements;
+  parsed_token_t **elements;
 } counted_array_t;
 
 typedef struct parsed_token {
-- 
GitLab