tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

test_buffers.c (25512B)


      1 /* Copyright (c) 2001-2004, Roger Dingledine.
      2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
      3 * Copyright (c) 2007-2021, The Tor Project, Inc. */
      4 /* See LICENSE for licensing information */
      5 
      6 #define BUFFERS_PRIVATE
      7 #define PROTO_HTTP_PRIVATE
      8 #include "core/or/or.h"
      9 #include "lib/buf/buffers.h"
     10 #include "lib/tls/buffers_tls.h"
     11 #include "lib/tls/tortls.h"
     12 #include "lib/compress/compress.h"
     13 #include "lib/crypt_ops/crypto_rand.h"
     14 #include "core/proto/proto_http.h"
     15 #include "core/proto/proto_socks.h"
     16 #include "test/test.h"
     17 
     18 /** Run unit tests for buffers.c */
     19 static void
     20 test_buffers_basic(void *arg)
     21 {
     22  char str[256];
     23  char str2[256];
     24 
     25  buf_t *buf = NULL, *buf2 = NULL;
     26  const char *cp;
     27 
     28  int j;
     29  size_t r;
     30  (void) arg;
     31 
     32  /****
     33   * buf_new
     34   ****/
     35  if (!(buf = buf_new()))
     36    TT_DIE(("Assertion failed."));
     37 
     38  //test_eq(buf_capacity(buf), 4096);
     39  tt_int_op(buf_datalen(buf),OP_EQ, 0);
     40 
     41  /****
     42   * General pointer frobbing
     43   */
     44  for (j=0;j<256;++j) {
     45    str[j] = (char)j;
     46  }
     47  buf_add(buf, str, 256);
     48  buf_add(buf, str, 256);
     49  tt_int_op(buf_datalen(buf),OP_EQ, 512);
     50  buf_get_bytes(buf, str2, 200);
     51  tt_mem_op(str,OP_EQ, str2, 200);
     52  tt_int_op(buf_datalen(buf),OP_EQ, 312);
     53  memset(str2, 0, sizeof(str2));
     54 
     55  buf_get_bytes(buf, str2, 256);
     56  tt_mem_op(str+200,OP_EQ, str2, 56);
     57  tt_mem_op(str,OP_EQ, str2+56, 200);
     58  tt_int_op(buf_datalen(buf),OP_EQ, 56);
     59  memset(str2, 0, sizeof(str2));
     60  /* Okay, now we should be 512 bytes into the 4096-byte buffer.  If we add
     61   * another 3584 bytes, we hit the end. */
     62  for (j=0;j<15;++j) {
     63    buf_add(buf, str, 256);
     64  }
     65  buf_assert_ok(buf);
     66  tt_int_op(buf_datalen(buf),OP_EQ, 3896);
     67  buf_get_bytes(buf, str2, 56);
     68  tt_int_op(buf_datalen(buf),OP_EQ, 3840);
     69  tt_mem_op(str+200,OP_EQ, str2, 56);
     70  for (j=0;j<15;++j) {
     71    memset(str2, 0, sizeof(str2));
     72    buf_get_bytes(buf, str2, 256);
     73    tt_mem_op(str,OP_EQ, str2, 256);
     74  }
     75  tt_int_op(buf_datalen(buf),OP_EQ, 0);
     76  buf_free(buf);
     77  buf = NULL;
     78 
     79  /* Okay, now make sure growing can work. */
     80  buf = buf_new_with_capacity(16);
     81  //test_eq(buf_capacity(buf), 16);
     82  buf_add(buf, str+1, 255);
     83  //test_eq(buf_capacity(buf), 256);
     84  buf_get_bytes(buf, str2, 254);
     85  tt_mem_op(str+1,OP_EQ, str2, 254);
     86  //test_eq(buf_capacity(buf), 256);
     87  buf_assert_ok(buf);
     88  buf_add(buf, str, 32);
     89  //test_eq(buf_capacity(buf), 256);
     90  buf_assert_ok(buf);
     91  buf_add(buf, str, 256);
     92  buf_assert_ok(buf);
     93  //test_eq(buf_capacity(buf), 512);
     94  tt_int_op(buf_datalen(buf),OP_EQ, 33+256);
     95  buf_get_bytes(buf, str2, 33);
     96  tt_int_op(*str2,OP_EQ, str[255]);
     97 
     98  tt_mem_op(str2+1,OP_EQ, str, 32);
     99  //test_eq(buf_capacity(buf), 512);
    100  tt_int_op(buf_datalen(buf),OP_EQ, 256);
    101  buf_get_bytes(buf, str2, 256);
    102  tt_mem_op(str,OP_EQ, str2, 256);
    103 
    104  /* now try shrinking: case 1. */
    105  buf_free(buf);
    106  buf = buf_new_with_capacity(33668);
    107  for (j=0;j<67;++j) {
    108    buf_add(buf, str,255);
    109  }
    110  //test_eq(buf_capacity(buf), 33668);
    111  tt_int_op(buf_datalen(buf),OP_EQ, 17085);
    112  for (j=0; j < 40; ++j) {
    113    buf_get_bytes(buf, str2, 255);
    114    tt_mem_op(str2,OP_EQ, str, 255);
    115  }
    116 
    117  /* now try shrinking: case 2. */
    118  buf_free(buf);
    119  buf = buf_new_with_capacity(33668);
    120  for (j=0;j<67;++j) {
    121    buf_add(buf, str, 255);
    122  }
    123  for (j=0; j < 20; ++j) {
    124    buf_get_bytes(buf, str2, 255);
    125    tt_mem_op(str2,OP_EQ, str, 255);
    126  }
    127  for (j=0;j<80;++j) {
    128    buf_add(buf, str, 255);
    129  }
    130  //test_eq(buf_capacity(buf),33668);
    131  for (j=0; j < 120; ++j) {
    132    buf_get_bytes(buf, str2, 255);
    133    tt_mem_op(str2,OP_EQ, str, 255);
    134  }
    135 
    136  /* Move from buf to buf. */
    137  buf_free(buf);
    138  buf = buf_new_with_capacity(4096);
    139  buf2 = buf_new_with_capacity(4096);
    140  for (j=0;j<100;++j)
    141    buf_add(buf, str, 255);
    142  tt_int_op(buf_datalen(buf),OP_EQ, 25500);
    143  for (j=0;j<100;++j) {
    144    r = 10;
    145    buf_move_to_buf(buf2, buf, &r);
    146    tt_int_op(r,OP_EQ, 0);
    147  }
    148  tt_int_op(buf_datalen(buf),OP_EQ, 24500);
    149  tt_int_op(buf_datalen(buf2),OP_EQ, 1000);
    150  for (j=0;j<3;++j) {
    151    buf_get_bytes(buf2, str2, 255);
    152    tt_mem_op(str2,OP_EQ, str, 255);
    153  }
    154  r = 8192; /*big move*/
    155  buf_move_to_buf(buf2, buf, &r);
    156  tt_int_op(r,OP_EQ, 0);
    157  r = 30000; /* incomplete move */
    158  buf_move_to_buf(buf2, buf, &r);
    159  tt_int_op(r,OP_EQ, 13692);
    160  for (j=0;j<97;++j) {
    161    buf_get_bytes(buf2, str2, 255);
    162    tt_mem_op(str2,OP_EQ, str, 255);
    163  }
    164  buf_free(buf);
    165  buf_free(buf2);
    166  buf = buf2 = NULL;
    167 
    168  buf = buf_new_with_capacity(5);
    169  cp = "Testing. This is a moderately long Testing string.";
    170  for (j = 0; cp[j]; j++)
    171    buf_add(buf, cp+j, 1);
    172  tt_int_op(0,OP_EQ, buf_find_string_offset(buf, "Testing", 7));
    173  tt_int_op(1,OP_EQ, buf_find_string_offset(buf, "esting", 6));
    174  tt_int_op(1,OP_EQ, buf_find_string_offset(buf, "est", 3));
    175  tt_int_op(39,OP_EQ, buf_find_string_offset(buf, "ing str", 7));
    176  tt_int_op(35,OP_EQ, buf_find_string_offset(buf, "Testing str", 11));
    177  tt_int_op(32,OP_EQ, buf_find_string_offset(buf, "ng ", 3));
    178  tt_int_op(43,OP_EQ, buf_find_string_offset(buf, "string.", 7));
    179  tt_int_op(-1,OP_EQ, buf_find_string_offset(buf, "shrdlu", 6));
    180  tt_int_op(-1,OP_EQ, buf_find_string_offset(buf, "Testing thing", 13));
    181  tt_int_op(-1,OP_EQ, buf_find_string_offset(buf, "ngx", 3));
    182  buf_free(buf);
    183  buf = NULL;
    184 
    185  /* Try adding a string too long for any freelist. */
    186  {
    187    char *mem = tor_malloc_zero(65536);
    188    buf = buf_new();
    189    buf_add(buf, mem, 65536);
    190    tor_free(mem);
    191 
    192    tt_int_op(buf_datalen(buf), OP_EQ, 65536);
    193    buf_free(buf);
    194    buf = NULL;
    195  }
    196 
    197 done:
    198  if (buf)
    199    buf_free(buf);
    200  if (buf2)
    201    buf_free(buf2);
    202 }
    203 
    204 static void
    205 test_buffer_pullup(void *arg)
    206 {
    207  buf_t *buf;
    208  char *stuff, *tmp;
    209  const char *cp;
    210  size_t sz;
    211  (void)arg;
    212  stuff = tor_malloc(16384);
    213  tmp = tor_malloc(16384);
    214 
    215  buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */
    216 
    217  tt_assert(buf);
    218  tt_int_op(buf_get_default_chunk_size(buf), OP_EQ, 4096);
    219 
    220  tt_int_op(buf_get_total_allocation(), OP_EQ, 0);
    221 
    222  /* There are a bunch of cases for pullup.  One is the trivial case. Let's
    223     mess around with an empty buffer. */
    224  buf_pullup(buf, 16, &cp, &sz);
    225  tt_ptr_op(cp, OP_EQ, NULL);
    226  tt_uint_op(sz, OP_EQ, 0);
    227 
    228  /* Let's make sure nothing got allocated */
    229  tt_int_op(buf_get_total_allocation(), OP_EQ, 0);
    230 
    231  /* Case 1: everything puts into the first chunk with some moving. */
    232 
    233  /* Let's add some data. */
    234  crypto_rand(stuff, 16384);
    235  buf_add(buf, stuff, 3000);
    236  buf_add(buf, stuff+3000, 3000);
    237  buf_pullup(buf, 0, &cp, &sz);
    238  tt_ptr_op(cp, OP_NE, NULL);
    239  tt_int_op(sz, OP_LE, 4096);
    240 
    241  /* Make room for 3000 bytes in the first chunk, so that the pullup-move code
    242   * can get tested. */
    243  tt_int_op(buf_get_bytes(buf, tmp, 3000), OP_EQ, 3000);
    244  tt_mem_op(tmp,OP_EQ, stuff, 3000);
    245  buf_pullup(buf, 2048, &cp, &sz);
    246  buf_assert_ok(buf);
    247  tt_ptr_op(cp, OP_NE, NULL);
    248  tt_int_op(sz, OP_GE, 2048);
    249  tt_mem_op(cp,OP_EQ, stuff+3000, 2048);
    250  tt_int_op(3000, OP_EQ, buf_datalen(buf));
    251  tt_int_op(buf_get_bytes(buf, tmp, 3000), OP_EQ, 0);
    252  tt_mem_op(tmp,OP_EQ, stuff+3000, 2048);
    253 
    254  buf_free(buf);
    255 
    256  /* Now try the large-chunk case. */
    257  buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */
    258  buf_add(buf, stuff, 4000);
    259  buf_add(buf, stuff+4000, 4000);
    260  buf_add(buf, stuff+8000, 4000);
    261  buf_add(buf, stuff+12000, 4000);
    262  tt_int_op(buf_datalen(buf), OP_EQ, 16000);
    263  buf_pullup(buf, 0, &cp, &sz);
    264  tt_ptr_op(cp, OP_NE, NULL);
    265  tt_int_op(sz, OP_LE, 4096);
    266 
    267  buf_pullup(buf, 12500, &cp, &sz);
    268  buf_assert_ok(buf);
    269  tt_ptr_op(cp, OP_NE, NULL);
    270  tt_int_op(sz, OP_GE, 12500);
    271  tt_mem_op(cp,OP_EQ, stuff, 12500);
    272  tt_int_op(buf_datalen(buf), OP_EQ, 16000);
    273 
    274  buf_get_bytes(buf, tmp, 12400);
    275  tt_mem_op(tmp,OP_EQ, stuff, 12400);
    276  tt_int_op(buf_datalen(buf), OP_EQ, 3600);
    277  buf_get_bytes(buf, tmp, 3500);
    278  tt_mem_op(tmp,OP_EQ, stuff+12400, 3500);
    279  buf_get_bytes(buf, tmp, 100);
    280  tt_mem_op(tmp,OP_EQ, stuff+15900, 10);
    281 
    282  buf_free(buf);
    283 
    284  /* Make sure that the pull-up-whole-buffer case works */
    285  buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */
    286  buf_add(buf, stuff, 4000);
    287  buf_add(buf, stuff+4000, 4000);
    288  buf_get_bytes(buf, tmp, 100); /* dump 100 bytes from first chunk */
    289  buf_pullup(buf, 16000, &cp, &sz);
    290  buf_assert_ok(buf);
    291  tt_ptr_op(cp, OP_NE, NULL);
    292  tt_int_op(sz, OP_EQ, 7900);
    293  tt_mem_op(cp,OP_EQ, stuff+100, 7900);
    294 
    295  buf_free(buf);
    296  buf = NULL;
    297 
    298  tt_int_op(buf_get_total_allocation(), OP_EQ, 0);
    299 done:
    300  buf_free(buf);
    301  tor_free(stuff);
    302  tor_free(tmp);
    303 }
    304 
    305 static void
    306 test_buffers_move_all(void *arg)
    307 {
    308  (void)arg;
    309  buf_t *input = buf_new();
    310  buf_t *output = buf_new();
    311  char *s = NULL;
    312 
    313  /* Move from empty buffer to nonempty buffer. (This is a regression test for
    314   * #40076) */
    315  buf_add(output, "abc", 3);
    316  buf_assert_ok(input);
    317  buf_assert_ok(output);
    318  buf_move_all(output, input);
    319  buf_assert_ok(input);
    320  buf_assert_ok(output);
    321  tt_int_op(buf_datalen(output), OP_EQ, 3);
    322  s = buf_extract(output, NULL);
    323  tt_str_op(s, OP_EQ, "abc");
    324  buf_free(output);
    325  buf_free(input);
    326  tor_free(s);
    327 
    328  /* Move from empty to empty. */
    329  output = buf_new();
    330  input = buf_new();
    331  buf_move_all(output, input);
    332  buf_assert_ok(input);
    333  buf_assert_ok(output);
    334  tt_int_op(buf_datalen(output), OP_EQ, 0);
    335  buf_free(output);
    336  buf_free(input);
    337 
    338  /* Move from nonempty to empty. */
    339  output = buf_new();
    340  input = buf_new();
    341  buf_add(input, "longstanding bugs", 17);
    342  buf_move_all(output, input);
    343  buf_assert_ok(input);
    344  buf_assert_ok(output);
    345  s = buf_extract(output, NULL);
    346  tt_str_op(s, OP_EQ, "longstanding bugs");
    347  buf_free(output);
    348  buf_free(input);
    349  tor_free(s);
    350 
    351  /* Move from nonempty to nonempty. */
    352  output = buf_new();
    353  input = buf_new();
    354  buf_add(output, "the start of", 12);
    355  buf_add(input, " a string", 9);
    356  buf_move_all(output, input);
    357  buf_assert_ok(input);
    358  buf_assert_ok(output);
    359  s = buf_extract(output, NULL);
    360  tt_str_op(s, OP_EQ, "the start of a string");
    361 
    362 done:
    363  buf_free(output);
    364  buf_free(input);
    365  tor_free(s);
    366 }
    367 
    368 static void
    369 test_buffer_copy(void *arg)
    370 {
    371  buf_t *buf=NULL, *buf2=NULL;
    372  const char *s;
    373  size_t len;
    374  char b[256];
    375  int i;
    376  (void)arg;
    377 
    378  buf = buf_new();
    379  tt_assert(buf);
    380 
    381  /* Copy an empty buffer. */
    382  tt_int_op(0, OP_EQ, buf_set_to_copy(&buf2, buf));
    383  tt_assert(buf2);
    384  tt_int_op(0, OP_EQ, buf_datalen(buf2));
    385 
    386  /* Now try with a short buffer. */
    387  s = "And now comes an act of enormous enormance!";
    388  len = strlen(s);
    389  buf_add(buf, s, len);
    390  tt_int_op(len, OP_EQ, buf_datalen(buf));
    391  /* Add junk to buf2 so we can test replacing.*/
    392  buf_add(buf2, "BLARG", 5);
    393  tt_int_op(0, OP_EQ, buf_set_to_copy(&buf2, buf));
    394  tt_int_op(len, OP_EQ, buf_datalen(buf2));
    395  buf_get_bytes(buf2, b, len);
    396  tt_mem_op(b, OP_EQ, s, len);
    397  /* Now free buf2 and retry so we can test allocating */
    398  buf_free(buf2);
    399  buf2 = NULL;
    400  tt_int_op(0, OP_EQ, buf_set_to_copy(&buf2, buf));
    401  tt_int_op(len, OP_EQ, buf_datalen(buf2));
    402  buf_get_bytes(buf2, b, len);
    403  tt_mem_op(b, OP_EQ, s, len);
    404  /* Clear buf for next test */
    405  buf_get_bytes(buf, b, len);
    406  tt_int_op(buf_datalen(buf),OP_EQ,0);
    407 
    408  /* Okay, now let's try a bigger buffer. */
    409  s = "Quis autem vel eum iure reprehenderit qui in ea voluptate velit "
    410    "esse quam nihil molestiae consequatur, vel illum qui dolorem eum "
    411    "fugiat quo voluptas nulla pariatur?";
    412  len = strlen(s);
    413  for (i = 0; i < 256; ++i) {
    414    b[0]=i;
    415    buf_add(buf, b, 1);
    416    buf_add(buf, s, len);
    417  }
    418  tt_int_op(0, OP_EQ, buf_set_to_copy(&buf2, buf));
    419  tt_int_op(buf_datalen(buf2), OP_EQ, buf_datalen(buf));
    420  for (i = 0; i < 256; ++i) {
    421    buf_get_bytes(buf2, b, len+1);
    422    tt_int_op((unsigned char)b[0],OP_EQ,i);
    423    tt_mem_op(b+1, OP_EQ, s, len);
    424  }
    425 
    426 done:
    427  if (buf)
    428    buf_free(buf);
    429  if (buf2)
    430    buf_free(buf2);
    431 }
    432 
    433 static void
    434 test_buffer_allocation_tracking(void *arg)
    435 {
    436  char *junk = tor_malloc(16384);
    437  buf_t *buf1 = NULL, *buf2 = NULL;
    438  int i;
    439 
    440  (void)arg;
    441 
    442  crypto_rand(junk, 16384);
    443  tt_int_op(buf_get_total_allocation(), OP_EQ, 0);
    444 
    445  buf1 = buf_new();
    446  tt_assert(buf1);
    447  buf2 = buf_new();
    448  tt_assert(buf2);
    449 
    450  tt_int_op(buf_allocation(buf1), OP_EQ, 0);
    451  tt_int_op(buf_get_total_allocation(), OP_EQ, 0);
    452 
    453  buf_add(buf1, junk, 4000);
    454  buf_add(buf1, junk, 4000);
    455  buf_add(buf1, junk, 4000);
    456  buf_add(buf1, junk, 4000);
    457  tt_int_op(buf_allocation(buf1), OP_EQ, 16384);
    458  buf_get_bytes(buf1, junk, 100);
    459  tt_int_op(buf_allocation(buf1), OP_EQ, 16384); /* still 4 4k chunks */
    460 
    461  tt_int_op(buf_get_total_allocation(), OP_EQ, 16384);
    462 
    463  buf_get_bytes(buf1, junk, 4096); /* drop a 1k chunk... */
    464  tt_int_op(buf_allocation(buf1), OP_EQ, 3*4096); /* now 3 4k chunks */
    465 
    466  tt_int_op(buf_get_total_allocation(), OP_EQ, 12288); /* that chunk was really
    467                                                       freed. */
    468 
    469  buf_add(buf2, junk, 4000);
    470  tt_int_op(buf_allocation(buf2), OP_EQ, 4096); /* another 4k chunk. */
    471  /*
    472   * We bounce back up to 16384 by allocating a new chunk.
    473   */
    474  tt_int_op(buf_get_total_allocation(), OP_EQ, 16384);
    475  buf_add(buf2, junk, 4000);
    476  tt_int_op(buf_allocation(buf2), OP_EQ, 8192); /* another 4k chunk. */
    477  tt_int_op(buf_get_total_allocation(),
    478            OP_EQ, 5*4096); /* that chunk was new. */
    479 
    480  /* Make a really huge buffer */
    481  for (i = 0; i < 1000; ++i) {
    482    buf_add(buf2, junk, 4000);
    483  }
    484  tt_int_op(buf_allocation(buf2), OP_GE, 4008000);
    485  tt_int_op(buf_get_total_allocation(), OP_GE, 4008000);
    486  buf_free(buf2);
    487  buf2 = NULL;
    488 
    489  tt_int_op(buf_get_total_allocation(), OP_LT, 4008000);
    490  tt_int_op(buf_get_total_allocation(), OP_EQ, buf_allocation(buf1));
    491  buf_free(buf1);
    492  buf1 = NULL;
    493  tt_int_op(buf_get_total_allocation(), OP_EQ, 0);
    494 
    495 done:
    496  buf_free(buf1);
    497  buf_free(buf2);
    498  tor_free(junk);
    499 }
    500 
    501 static void
    502 test_buffer_time_tracking(void *arg)
    503 {
    504  buf_t *buf=NULL, *buf2=NULL;
    505  const time_t START = 1389288246;
    506  const uint64_t START_NSEC = ((uint64_t)START) * 1000000000;
    507  int i;
    508  char tmp[4096];
    509  (void)arg;
    510 
    511  crypto_rand(tmp, sizeof(tmp));
    512 
    513  monotime_enable_test_mocking();
    514 
    515  buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */
    516  tt_assert(buf);
    517 
    518  monotime_coarse_set_mock_time_nsec(START_NSEC);
    519  const uint32_t START_TS = monotime_coarse_get_stamp();
    520 
    521  /* Empty buffer means the timestamp is 0. */
    522  tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_TS));
    523  tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_TS+1000));
    524 
    525  buf_add(buf, "ABCDEFG", 7);
    526  tt_int_op(1000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_TS+1000));
    527 
    528  buf2 = buf_copy(buf);
    529  tt_assert(buf2);
    530  tt_int_op(1234, OP_EQ,
    531            buf_get_oldest_chunk_timestamp(buf2, START_TS+1234));
    532 
    533  /* Now add more bytes; enough to overflow the first chunk. */
    534  monotime_coarse_set_mock_time_nsec(START_NSEC + 123 * (uint64_t)1000000);
    535  const uint32_t TS2 = monotime_coarse_get_stamp();
    536  for (i = 0; i < 600; ++i)
    537    buf_add(buf, "ABCDEFG", 7);
    538  tt_int_op(4207, OP_EQ, buf_datalen(buf));
    539 
    540  /* The oldest bytes are still in the front. */
    541  tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_TS+2000));
    542 
    543  /* Once those bytes are dropped, the chunk is still on the first
    544   * timestamp. */
    545  buf_get_bytes(buf, tmp, 100);
    546  tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_TS+2000));
    547 
    548  /* But once we discard the whole first chunk, we get the data in the second
    549   * chunk. */
    550  buf_get_bytes(buf, tmp, 4000);
    551  tt_int_op(107, OP_EQ, buf_datalen(buf));
    552  tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, TS2+2000));
    553 
    554  /* This time we'll be grabbing a chunk from the freelist, and making sure
    555     its time gets updated */
    556  monotime_coarse_set_mock_time_nsec(START_NSEC + 5617 * (uint64_t)1000000);
    557  const uint32_t TS3 = monotime_coarse_get_stamp();
    558  for (i = 0; i < 600; ++i)
    559    buf_add(buf, "ABCDEFG", 7);
    560  tt_int_op(4307, OP_EQ, buf_datalen(buf));
    561 
    562  tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, TS2+2000));
    563  buf_get_bytes(buf, tmp, 4000);
    564  buf_get_bytes(buf, tmp, 306);
    565  tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, TS3));
    566  tt_int_op(383, OP_EQ, buf_get_oldest_chunk_timestamp(buf, TS3+383));
    567 
    568 done:
    569  buf_free(buf);
    570  buf_free(buf2);
    571  monotime_disable_test_mocking();
    572 }
    573 
    574 static void
    575 test_buffers_compress_fin_at_chunk_end_impl(compress_method_t method,
    576                                            compression_level_t level)
    577 {
    578  char *msg = NULL;
    579  char *contents = NULL;
    580  char *expanded = NULL;
    581  buf_t *buf = NULL;
    582  tor_compress_state_t *compress_state = NULL;
    583  size_t out_len, in_len;
    584  size_t sz, headerjunk;
    585 
    586  buf = buf_new_with_capacity(128); /* will round up */
    587  sz = buf_get_default_chunk_size(buf);
    588  msg = tor_malloc_zero(sz);
    589 
    590  buf_add(buf, msg, 1);
    591  tt_assert(buf->head);
    592 
    593  /* Fill up the chunk so the compression stuff won't fit in one chunk. */
    594  tt_uint_op(buf->head->memlen, OP_LT, sz);
    595  headerjunk = buf->head->memlen - 7;
    596  buf_add(buf, msg, headerjunk-1);
    597  tt_uint_op(buf->head->datalen, OP_EQ, headerjunk);
    598  tt_uint_op(buf_datalen(buf), OP_EQ, headerjunk);
    599  /* Write an empty string, with finalization on. */
    600  compress_state = tor_compress_new(1, method, level);
    601  tt_int_op(buf_add_compress(buf, compress_state, "", 0, 1), OP_EQ, 0);
    602 
    603  in_len = buf_datalen(buf);
    604  contents = tor_malloc(in_len);
    605 
    606  tt_int_op(buf_get_bytes(buf, contents, in_len), OP_EQ, 0);
    607 
    608  if (method == NO_METHOD) {
    609    tt_uint_op(in_len, OP_EQ, headerjunk);
    610  } else {
    611    tt_uint_op(in_len, OP_GT, headerjunk);
    612  }
    613 
    614  tt_int_op(0, OP_EQ, tor_uncompress(&expanded, &out_len,
    615                                     contents + headerjunk,
    616                                     in_len - headerjunk,
    617                                     method, 1,
    618                                     LOG_WARN));
    619 
    620  tt_int_op(out_len, OP_EQ, 0);
    621  tt_assert(expanded);
    622 
    623 done:
    624  buf_free(buf);
    625  tor_compress_free(compress_state);
    626  tor_free(contents);
    627  tor_free(expanded);
    628  tor_free(msg);
    629 }
    630 
    631 static void
    632 test_buffers_compress_impl(compress_method_t method,
    633                           compression_level_t level,
    634                           int finalize_with_nil)
    635 {
    636  char *msg = NULL;
    637  char *contents = NULL;
    638  char *expanded = NULL;
    639  buf_t *buf = NULL;
    640  tor_compress_state_t *compress_state = NULL;
    641  size_t out_len, in_len;
    642  int done;
    643 
    644  buf = buf_new_with_capacity(128); /* will round up */
    645  compress_state = tor_compress_new(1, method, level);
    646 
    647  msg = tor_malloc(512);
    648  crypto_rand(msg, 512);
    649  tt_int_op(buf_add_compress(buf, compress_state,
    650                                  msg, 128, 0), OP_EQ, 0);
    651  tt_int_op(buf_add_compress(buf, compress_state,
    652                                  msg+128, 128, 0), OP_EQ, 0);
    653  tt_int_op(buf_add_compress(buf, compress_state,
    654                                  msg+256, 256, 0), OP_EQ, 0);
    655  done = !finalize_with_nil;
    656  tt_int_op(buf_add_compress(buf, compress_state,
    657                                  "all done", 9, done), OP_EQ, 0);
    658  if (finalize_with_nil) {
    659    tt_int_op(buf_add_compress(buf, compress_state, "", 0, 1), OP_EQ, 0);
    660  }
    661 
    662  in_len = buf_datalen(buf);
    663  contents = tor_malloc(in_len);
    664 
    665  tt_int_op(buf_get_bytes(buf, contents, in_len), OP_EQ, 0);
    666 
    667  tt_int_op(0, OP_EQ, tor_uncompress(&expanded, &out_len,
    668                                     contents, in_len,
    669                                     method, 1,
    670                                     LOG_WARN));
    671 
    672  tt_int_op(out_len, OP_GE, 128);
    673  tt_mem_op(msg, OP_EQ, expanded, 128);
    674  tt_int_op(out_len, OP_GE, 512);
    675  tt_mem_op(msg, OP_EQ, expanded, 512);
    676  tt_int_op(out_len, OP_EQ, 512+9);
    677  tt_mem_op("all done", OP_EQ, expanded+512, 9);
    678 
    679 done:
    680  buf_free(buf);
    681  tor_compress_free(compress_state);
    682  tor_free(contents);
    683  tor_free(expanded);
    684  tor_free(msg);
    685 }
    686 
    687 static void
    688 test_buffers_compress(void *arg)
    689 {
    690  const char *methodname = arg;
    691  tt_assert(methodname);
    692 
    693  compress_method_t method = compression_method_get_by_name(methodname);
    694  tt_int_op(method, OP_NE, UNKNOWN_METHOD);
    695 
    696  if (! tor_compress_supports_method(method)) {
    697    tt_skip();
    698  }
    699 
    700  compression_level_t levels[] = {
    701    BEST_COMPRESSION,
    702    HIGH_COMPRESSION,
    703    MEDIUM_COMPRESSION,
    704    LOW_COMPRESSION
    705  };
    706 
    707  for (unsigned l = 0; l < ARRAY_LENGTH(levels); ++l) {
    708    compression_level_t level = levels[l];
    709 
    710    test_buffers_compress_impl(method, level, 0);
    711    test_buffers_compress_impl(method, level, 1);
    712    test_buffers_compress_fin_at_chunk_end_impl(method, level);
    713  }
    714 
    715 done:
    716  ;
    717 }
    718 
    719 static const uint8_t *tls_read_ptr;
    720 static int n_remaining;
    721 static int next_reply_val[16];
    722 
    723 static int
    724 mock_tls_read(tor_tls_t *tls, char *cp, size_t len)
    725 {
    726  (void)tls;
    727  int rv = next_reply_val[0];
    728  if (rv > 0) {
    729    int max = rv > (int)len ? (int)len : rv;
    730    if (max > n_remaining)
    731      max = n_remaining;
    732    memcpy(cp, tls_read_ptr, max);
    733    rv = max;
    734    n_remaining -= max;
    735    tls_read_ptr += max;
    736  }
    737 
    738  memmove(next_reply_val, next_reply_val + 1, 15*sizeof(int));
    739  return rv;
    740 }
    741 
    742 static void
    743 test_buffers_tls_read_mocked(void *arg)
    744 {
    745  uint8_t *mem;
    746  buf_t *buf;
    747  (void)arg;
    748 
    749  mem = tor_malloc(64*1024);
    750  crypto_rand((char*)mem, 64*1024);
    751  tls_read_ptr = mem;
    752  n_remaining = 64*1024;
    753 
    754  MOCK(tor_tls_read, mock_tls_read);
    755 
    756  buf = buf_new();
    757 
    758  next_reply_val[0] = 1024;
    759  tt_int_op(128, OP_EQ, buf_read_from_tls(buf, NULL, 128));
    760 
    761  next_reply_val[0] = 5000;
    762  next_reply_val[1] = 5000;
    763  tt_int_op(6000, OP_EQ, buf_read_from_tls(buf, NULL, 6000));
    764 
    765 done:
    766  UNMOCK(tor_tls_read);
    767  tor_free(mem);
    768  buf_free(buf);
    769 }
    770 
    771 static void
    772 test_buffers_chunk_size(void *arg)
    773 {
    774  (void)arg;
    775  const int min = 256;
    776  const int max = 65536;
    777  tt_uint_op(buf_preferred_chunk_size(3), OP_EQ, min);
    778  tt_uint_op(buf_preferred_chunk_size(25), OP_EQ, min);
    779  tt_uint_op(buf_preferred_chunk_size(0), OP_EQ, min);
    780  tt_uint_op(buf_preferred_chunk_size(256), OP_EQ, 512);
    781  tt_uint_op(buf_preferred_chunk_size(65400), OP_EQ, max);
    782  /* Here, we're implicitly saying that the chunk header overhead is
    783   * between 1 and 100 bytes. 24..48 would probably be more accurate. */
    784  tt_uint_op(buf_preferred_chunk_size(65536), OP_GT, 65536);
    785  tt_uint_op(buf_preferred_chunk_size(65536), OP_LT, 65536+100);
    786  tt_uint_op(buf_preferred_chunk_size(165536), OP_GT, 165536);
    787  tt_uint_op(buf_preferred_chunk_size(165536), OP_LT, 165536+100);
    788 done:
    789  ;
    790 }
    791 
    792 static void
    793 test_buffers_find_contentlen(void *arg)
    794 {
    795  static const struct {
    796    const char *headers;
    797    int r;
    798    int contentlen;
    799  } results[] = {
    800    { "Blah blah\r\nContent-Length: 1\r\n\r\n", 1, 1 },
    801    { "Blah blah\r\n\r\n", 0, 0 }, /* no content-len */
    802    { "Blah blah Content-Length: 1\r\n", 0, 0 }, /* no content-len. */
    803    { "Blah blah\r\nContent-Length: 100000\r\n", 1, 100000},
    804    { "Blah blah\r\nContent-Length: 1000000000000000000000000\r\n", -1, 0},
    805    { "Blah blah\r\nContent-Length: 0\r\n", 1, 0},
    806    { "Blah blah\r\nContent-Length: -1\r\n", -1, 0},
    807    { "Blah blah\r\nContent-Length: 1x\r\n", -1, 0},
    808    { "Blah blah\r\nContent-Length: 1 x\r\n", -1, 0},
    809    { "Blah blah\r\nContent-Length: 1 \r\n", 1, 1},
    810    { "Blah blah\r\nContent-Length:  \r\n", -1, 0},
    811    { "Blah blah\r\nContent-Length: ", -1, 0},
    812    { "Blah blah\r\nContent-Length: 5050", -1, 0},
    813    { NULL, 0, 0 }
    814  };
    815  int i;
    816 
    817  (void)arg;
    818 
    819  for (i = 0; results[i].headers; ++i) {
    820    int r;
    821    size_t sz;
    822    size_t headerlen = strlen(results[i].headers);
    823    char * tmp = tor_memdup(results[i].headers, headerlen);/* ensure no eos */
    824    sz = 999; /* to ensure it gets set */
    825    r = buf_http_find_content_length(tmp, headerlen, &sz);
    826    tor_free(tmp);
    827    log_debug(LD_DIR, "%d: %s", i, escaped(results[i].headers));
    828    tt_int_op(r, OP_EQ, results[i].r);
    829    tt_int_op(sz, OP_EQ, results[i].contentlen);
    830  }
    831 done:
    832  ;
    833 }
    834 
    835 static void
    836 test_buffer_peek_startswith(void *arg)
    837 {
    838  (void)arg;
    839  buf_t *buf;
    840  buf = buf_new();
    841  tt_ptr_op(buf, OP_NE, NULL);
    842 
    843  tt_assert(buf_peek_startswith(buf, ""));
    844  tt_assert(! buf_peek_startswith(buf, "X"));
    845 
    846  buf_add(buf, "Tor", 3);
    847 
    848  tt_assert(buf_peek_startswith(buf, ""));
    849  tt_assert(buf_peek_startswith(buf, "T"));
    850  tt_assert(buf_peek_startswith(buf, "To"));
    851  tt_assert(buf_peek_startswith(buf, "Tor"));
    852  tt_assert(! buf_peek_startswith(buf, "Top"));
    853  tt_assert(! buf_peek_startswith(buf, "For"));
    854  tt_assert(! buf_peek_startswith(buf, "Tork"));
    855  tt_assert(! buf_peek_startswith(buf, "Torpor"));
    856 
    857 done:
    858  buf_free(buf);
    859 }
    860 
    861 struct testcase_t buffer_tests[] = {
    862  { "basic", test_buffers_basic, TT_FORK, NULL, NULL },
    863  { "copy", test_buffer_copy, TT_FORK, NULL, NULL },
    864  { "pullup", test_buffer_pullup, TT_FORK, NULL, NULL },
    865  { "move_all", test_buffers_move_all, 0, NULL, NULL },
    866  { "startswith", test_buffer_peek_startswith, 0, NULL, NULL },
    867  { "allocation_tracking", test_buffer_allocation_tracking, TT_FORK,
    868    NULL, NULL },
    869  { "time_tracking", test_buffer_time_tracking, TT_FORK, NULL, NULL },
    870  { "tls_read_mocked", test_buffers_tls_read_mocked, 0,
    871    NULL, NULL },
    872  { "chunk_size", test_buffers_chunk_size, 0, NULL, NULL },
    873  { "find_contentlen", test_buffers_find_contentlen, 0, NULL, NULL },
    874 
    875  { "compress/zlib", test_buffers_compress, TT_FORK,
    876    &passthrough_setup, (char*)"deflate" },
    877  { "compress/gzip", test_buffers_compress, TT_FORK,
    878    &passthrough_setup, (char*)"gzip" },
    879  { "compress/zstd", test_buffers_compress, TT_FORK,
    880    &passthrough_setup, (char*)"x-zstd" },
    881  { "compress/lzma", test_buffers_compress, TT_FORK,
    882    &passthrough_setup, (char*)"x-tor-lzma" },
    883  { "compress/none", test_buffers_compress, TT_FORK,
    884    &passthrough_setup, (char*)"identity" },
    885 
    886  END_OF_TESTCASES
    887 };