LCOV - code coverage report
Current view: top level - test - test_buffers.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 561 566 99.1 %
Date: 2021-11-24 03:28:48 Functions: 14 14 100.0 %

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

Generated by: LCOV version 1.14