LCOV - code coverage report
Current view: top level - fuzztest - random_data.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 101 101 100.0 %
Date: 2023-02-14 20:10:26 Functions: 11 11 100.0 %

          Line data    Source code
       1             : #include "random_data.h"
       2             : #include <string.h>
       3             : #include <malloc_wrappers.h>
       4             : #include <pb_encode.h>
       5             : 
       6             : #ifndef LLVMFUZZER
       7             : 
       8             : static uint32_t g_random_seed = 1234;
       9             : 
      10           2 : void random_set_seed(uint32_t seed)
      11             : {
      12           2 :     g_random_seed = seed;
      13           2 : }
      14             : 
      15        1000 : uint32_t random_get_seed()
      16             : {
      17        1000 :     return g_random_seed;
      18             : }
      19             : 
      20             : /* Uses xorshift64 here instead of rand() for both speed and
      21             :  * reproducibility across platforms. */
      22    17381470 : uint32_t rand_word()
      23             : {
      24    17381470 :     g_random_seed ^= g_random_seed << 13;
      25    17381470 :     g_random_seed ^= g_random_seed >> 17;
      26    17381470 :     g_random_seed ^= g_random_seed << 5;
      27    17381470 :     return g_random_seed;
      28             : }
      29             : 
      30             : /* Get a random integer in range, with approximately flat distribution. */
      31       64176 : int rand_int(int min, int max)
      32             : {
      33       64176 :     return rand_word() % (max + 1 - min) + min;
      34             : }
      35             : 
      36        1830 : bool rand_bool()
      37             : {
      38        1830 :     return rand_word() & 1;
      39             : }
      40             : 
      41             : /* Get a random byte, with skewed distribution.
      42             :  * Important corner cases like 0xFF, 0x00 and 0xFE occur more
      43             :  * often than other values. */
      44    17304875 : uint8_t rand_byte()
      45             : {
      46    17304875 :     uint32_t w = rand_word();
      47    17304875 :     uint8_t b = w & 0xFF;
      48    17304875 :     if (w & 0x100000)
      49     8652455 :         b >>= (w >> 8) & 7;
      50    17304875 :     if (w & 0x200000)
      51     8650588 :         b <<= (w >> 12) & 7;
      52    17304875 :     if (w & 0x400000)
      53     8654094 :         b ^= 0xFF;
      54    17304875 :     return b;
      55             : }
      56             : 
      57             : /* Get a random length, with skewed distribution.
      58             :  * Favors the shorter lengths, but always at least 1. */
      59       10514 : size_t rand_len(size_t max)
      60             : {
      61       10514 :     uint32_t w = rand_word();
      62             :     size_t s;
      63       10514 :     if (w & 0x800000)
      64        5175 :         w &= 3;
      65        5339 :     else if (w & 0x400000)
      66        2680 :         w &= 15;
      67        2659 :     else if (w & 0x200000)
      68        1349 :         w &= 255;
      69             : 
      70       10514 :     s = (w % max);
      71       10514 :     if (s == 0)
      72        1656 :         s = 1;
      73             : 
      74       10514 :     return s;
      75             : }
      76             : 
      77             : /* Fills a buffer with random data with skewed distribution. */
      78       22361 : void rand_fill(uint8_t *buf, size_t count)
      79             : {
      80    17327236 :     for (; count > 0; count--)
      81             :     {
      82    17304875 :         *buf++ = rand_byte();
      83             :     }
      84       22361 : }
      85             : 
      86             : /* Fill with random protobuf-like data */
      87        2238 : size_t rand_fill_protobuf(uint8_t *buf, size_t min_bytes, size_t max_bytes, int min_tag)
      88             : {
      89        2238 :     pb_ostream_t stream = pb_ostream_from_buffer(buf, max_bytes);
      90             : 
      91       21685 :     while(stream.bytes_written < min_bytes)
      92             :     {
      93       19448 :         pb_wire_type_t wt = rand_int(0, 3);
      94       19448 :         if (wt == 3) wt = 5; /* Gap in values */
      95             : 
      96       19448 :         if (!pb_encode_tag(&stream, wt, rand_int(min_tag, min_tag + 512)))
      97           1 :             break;
      98             : 
      99       19447 :         if (wt == PB_WT_VARINT)
     100             :         {
     101             :             uint64_t value;
     102        4844 :             rand_fill((uint8_t*)&value, sizeof(value));
     103        4844 :             pb_encode_varint(&stream, value);
     104             :         }
     105       14603 :         else if (wt == PB_WT_64BIT)
     106             :         {
     107             :             uint64_t value;
     108        4979 :             rand_fill((uint8_t*)&value, sizeof(value));
     109        4979 :             pb_encode_fixed64(&stream, &value);
     110             :         }
     111        9624 :         else if (wt == PB_WT_32BIT)
     112             :         {
     113             :             uint32_t value;
     114        4749 :             rand_fill((uint8_t*)&value, sizeof(value));
     115        4749 :             pb_encode_fixed32(&stream, &value);
     116             :         }
     117        4875 :         else if (wt == PB_WT_STRING)
     118             :         {
     119             :             size_t len;
     120             :             uint8_t *buf;
     121             : 
     122        4875 :             if (min_bytes > stream.bytes_written)
     123        4573 :                 len = rand_len(min_bytes - stream.bytes_written);
     124             :             else
     125         302 :                 len = 0;
     126             : 
     127        4875 :             buf = malloc(len);
     128        4875 :             pb_encode_varint(&stream, len);
     129        4875 :             rand_fill(buf, len);
     130        4875 :             pb_write(&stream, buf, len);
     131        4875 :             free(buf);
     132             :         }
     133             :     }
     134             : 
     135        2238 :     return stream.bytes_written;
     136             : }
     137             : 
     138             : /* Given a buffer of data, mess it up a bit */
     139        7404 : void rand_mess(uint8_t *buf, size_t count)
     140             : {
     141        7404 :     int m = rand_int(0, 3);
     142             : 
     143        7404 :     if (m == 0)
     144             :     {
     145             :         /* Replace random substring */
     146        1864 :         int s = rand_int(0, count - 1);
     147        1864 :         int l = rand_len(count - s);
     148        1864 :         rand_fill(buf + s, l);
     149             :     }
     150        5540 :     else if (m == 1)
     151             :     {
     152             :         /* Swap random bytes */
     153        1865 :         int a = rand_int(0, count - 1);
     154        1865 :         int b = rand_int(0, count - 1);
     155        1865 :         int x = buf[a];
     156        1865 :         buf[a] = buf[b];
     157        1865 :         buf[b] = x;
     158             :     }
     159        3675 :     else if (m == 2)
     160             :     {
     161             :         /* Duplicate substring */
     162        1839 :         int s = rand_int(0, count - 2);
     163        1839 :         int l = rand_len((count - s) / 2);
     164        1839 :         memcpy(buf + s + l, buf + s, l);
     165             :     }
     166        1836 :     else if (m == 3)
     167             :     {
     168             :         /* Add random protobuf noise */
     169        1836 :         int s = rand_int(0, count - 1);
     170        1836 :         int l = rand_len(count - s);
     171        1836 :         rand_fill_protobuf(buf + s, l, count - s, 1);
     172             :     }
     173        7404 : }
     174             : 
     175             : /* Append or prepend protobuf noise */
     176         584 : void rand_protobuf_noise(uint8_t *buffer, size_t bufsize, size_t *msglen)
     177             : {
     178         584 :     int m = rand_int(0, 2);
     179         584 :     size_t max_size = bufsize - 32 - *msglen;
     180         584 :     if (m == 1)
     181             :     {
     182             :         /* Prepend */
     183         207 :         uint8_t *tmp = malloc_with_check(bufsize);
     184         207 :         size_t s = rand_fill_protobuf(tmp, rand_len(max_size), bufsize - *msglen, 1000);
     185         207 :         memmove(buffer + s, buffer, *msglen);
     186         207 :         memcpy(buffer, tmp, s);
     187         207 :         free_with_check(tmp);
     188         207 :         *msglen += s;
     189             :     }
     190         377 :     else if (m == 2)
     191             :     {
     192             :         /* Append */
     193         195 :         size_t s = rand_fill_protobuf(buffer + *msglen, rand_len(max_size), bufsize - *msglen, 1000);
     194         195 :         *msglen += s;
     195             :     }
     196         584 : }
     197             : 
     198             : #endif

Generated by: LCOV version 1.14