(root)/
gcc-13.2.0/
libbacktrace/
xztest.c
       1  /* xztest.c -- Test for libbacktrace LZMA decoder.
       2     Copyright (C) 2020-2023 Free Software Foundation, Inc.
       3     Written by Ian Lance Taylor, Google.
       4  
       5  Redistribution and use in source and binary forms, with or without
       6  modification, are permitted provided that the following conditions are
       7  met:
       8  
       9      (1) Redistributions of source code must retain the above copyright
      10      notice, this list of conditions and the following disclaimer.
      11  
      12      (2) Redistributions in binary form must reproduce the above copyright
      13      notice, this list of conditions and the following disclaimer in
      14      the documentation and/or other materials provided with the
      15      distribution.
      16  
      17      (3) The name of the author may not be used to
      18      endorse or promote products derived from this software without
      19      specific prior written permission.
      20  
      21  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
      22  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
      23  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
      24  DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
      25  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
      26  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      27  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      28  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
      29  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
      30  IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      31  POSSIBILITY OF SUCH DAMAGE.  */
      32  
      33  #include "config.h"
      34  
      35  #include <errno.h>
      36  #include <limits.h>
      37  #include <stdio.h>
      38  #include <stdlib.h>
      39  #include <string.h>
      40  #include <time.h>
      41  #include <sys/types.h>
      42  #include <sys/stat.h>
      43  
      44  #ifdef HAVE_LIBLZMA
      45  #include <lzma.h>
      46  #endif
      47  
      48  #include "backtrace.h"
      49  #include "backtrace-supported.h"
      50  
      51  #include "internal.h"
      52  #include "testlib.h"
      53  
      54  #ifndef HAVE_CLOCK_GETTIME
      55  
      56  typedef int xclockid_t;
      57  
      58  static int
      59  xclock_gettime (xclockid_t id ATTRIBUTE_UNUSED,
      60  		struct timespec *ts ATTRIBUTE_UNUSED)
      61  {
      62    errno = EINVAL;
      63    return -1;
      64  }
      65  
      66  #define clockid_t xclockid_t
      67  #define clock_gettime xclock_gettime
      68  #undef CLOCK_REALTIME
      69  #define CLOCK_REALTIME 0
      70  
      71  #endif /* !defined(HAVE_CLOCK_GETTIME) */
      72  
      73  #ifdef CLOCK_PROCESS_CPUTIME_ID
      74  #define LIBLZMA_CLOCK_GETTIME_ARG CLOCK_PROCESS_CPUTIME_ID
      75  #else
      76  #define LIBLZMA_CLOCK_GETTIME_ARG CLOCK_REALTIME
      77  #endif
      78  
      79  /* Some tests for the local lzma inflation code.  */
      80  
      81  struct lzma_test
      82  {
      83    const char *name;
      84    const char *uncompressed;
      85    size_t uncompressed_len;
      86    const char *compressed;
      87    size_t compressed_len;
      88  };
      89  
      90  /* Error callback.  */
      91  
      92  static void
      93  error_callback_compress (void *vdata ATTRIBUTE_UNUSED, const char *msg,
      94  			 int errnum)
      95  {
      96    fprintf (stderr, "%s", msg);
      97    if (errnum > 0)
      98      fprintf (stderr, ": %s", strerror (errnum));
      99    fprintf (stderr, "\n");
     100    exit (EXIT_FAILURE);
     101  }
     102  
     103  static const struct lzma_test tests[] =
     104  {
     105    {
     106      "empty",
     107      "",
     108      0,
     109      ("\xfd\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x00\x00\x00\x00"
     110       "\x1c\xdf\x44\x21\x1f\xb6\xf3\x7d\x01\x00\x00\x00\x00\x04\x59\x5a"),
     111      32,
     112    },
     113    {
     114      "hello",
     115      "hello, world\n",
     116      0,
     117      ("\xfd\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x02\x00\x21\x01"
     118       "\x16\x00\x00\x00\x74\x2f\xe5\xa3\x01\x00\x0c\x68\x65\x6c\x6c\x6f"
     119       "\x2c\x20\x77\x6f\x72\x6c\x64\x0a\x00\x00\x00\x00\x7b\x46\x5a\x81"
     120       "\xc9\x12\xb8\xea\x00\x01\x25\x0d\x71\x19\xc4\xb6\x1f\xb6\xf3\x7d"
     121       "\x01\x00\x00\x00\x00\x04\x59\x5a"),
     122      72,
     123    },
     124    {
     125      "goodbye",
     126      "goodbye, world",
     127      0,
     128      ("\xfd\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x02\x00\x21\x01"
     129       "\x16\x00\x00\x00\x74\x2f\xe5\xa3\x01\x00\x0d\x67\x6f\x6f\x64\x62"
     130       "\x79\x65\x2c\x20\x77\x6f\x72\x6c\x64\x00\x00\x00\xf6\xf8\xa3\x33"
     131       "\x8c\x4e\xc9\x68\x00\x01\x26\x0e\x08\x1b\xe0\x04\x1f\xb6\xf3\x7d"
     132       "\x01\x00\x00\x00\x00\x04\x59\x5a"),
     133      72,
     134    },
     135  };
     136  
     137  /* Test the hand coded samples.  */
     138  
     139  static void
     140  test_samples (struct backtrace_state *state)
     141  {
     142    size_t i;
     143  
     144    for (i = 0; i < sizeof tests / sizeof tests[0]; ++i)
     145      {
     146        unsigned char *uncompressed;
     147        size_t uncompressed_len;
     148  
     149        uncompressed = NULL;
     150        uncompressed_len = 0;
     151        if (!backtrace_uncompress_lzma (state,
     152  				      ((const unsigned char *)
     153  				       tests[i].compressed),
     154  				      tests[i].compressed_len,
     155  				      error_callback_compress, NULL,
     156  				      &uncompressed, &uncompressed_len))
     157  	{
     158  	  fprintf (stderr, "test %s: uncompress failed\n", tests[i].name);
     159  	  ++failures;
     160  	}
     161        else
     162  	{
     163  	  size_t v;
     164  
     165  	  v = tests[i].uncompressed_len;
     166  	  if (v == 0)
     167  	    v = strlen (tests[i].uncompressed);
     168  	  if (uncompressed_len != v)
     169  	    {
     170  	      fprintf (stderr,
     171  		       "test %s: got uncompressed length %zu, want %zu\n",
     172  		       tests[i].name, uncompressed_len, v);
     173  	      ++failures;
     174  	    }
     175  	  else if (v > 0 && memcmp (tests[i].uncompressed, uncompressed, v) != 0)
     176  	    {
     177  	      size_t j;
     178  
     179  	      fprintf (stderr, "test %s: uncompressed data mismatch\n",
     180  		       tests[i].name);
     181  	      for (j = 0; j < v; ++j)
     182  		if (tests[i].uncompressed[j] != uncompressed[j])
     183  		  fprintf (stderr, "  %zu: got %#x want %#x\n", j,
     184  			   uncompressed[j], tests[i].uncompressed[j]);
     185  	      ++failures;
     186  	    }
     187  	  else
     188  	    printf ("PASS: lzma %s\n", tests[i].name);
     189  
     190  	  backtrace_free (state, uncompressed, uncompressed_len,
     191  			  error_callback_compress, NULL);
     192  	}
     193      }
     194  }
     195  
     196  #if HAVE_LIBLZMA
     197  
     198  /* Given a set of TRIALS timings, discard the lowest and highest
     199     values and return the mean average of the rest.  */
     200  
     201  static size_t
     202  average_time (const size_t *times, size_t trials)
     203  {
     204    size_t imax;
     205    size_t max;
     206    size_t imin;
     207    size_t min;
     208    size_t i;
     209    size_t sum;
     210  
     211    imin = 0;
     212    imax = 0;
     213    min = times[0];
     214    max = times[0];
     215    for (i = 1; i < trials; ++i)
     216      {
     217        if (times[i] < min)
     218  	{
     219  	  imin = i;
     220  	  min = times[i];
     221  	}
     222        if (times[i] > max)
     223  	{
     224  	  imax = i;
     225  	  max = times[i];
     226  	}
     227      }
     228  
     229    sum = 0;
     230    for (i = 0; i < trials; ++i)
     231      {
     232        if (i != imax && i != imin)
     233  	sum += times[i];
     234      }
     235    return sum / (trials - 2);
     236  }
     237  
     238  #endif
     239  
     240  /* Test a larger text, if available.  */
     241  
     242  static void
     243  test_large (struct backtrace_state *state ATTRIBUTE_UNUSED)
     244  {
     245  #if HAVE_LIBLZMA
     246    unsigned char *orig_buf;
     247    size_t orig_bufsize;
     248    size_t i;
     249    lzma_stream initial_stream = LZMA_STREAM_INIT;
     250    lzma_stream stream;
     251    unsigned char *compressed_buf;
     252    size_t compressed_bufsize;
     253    unsigned char *uncompressed_buf;
     254    size_t uncompressed_bufsize;
     255    unsigned char *spare_buf;
     256    int r;
     257    clockid_t cid;
     258    struct timespec ts1;
     259    struct timespec ts2;
     260    size_t ctime;
     261    size_t ztime;
     262    const size_t trials = 16;
     263    size_t ctimes[16];
     264    size_t ztimes[16];
     265    static const char * const names[] = {
     266      "Isaac.Newton-Opticks.txt",
     267      "../libgo/go/testdata/Isaac.Newton-Opticks.txt",
     268    };
     269  
     270    orig_buf = NULL;
     271    orig_bufsize = 0;
     272    uncompressed_buf = NULL;
     273    compressed_buf = NULL;
     274  
     275    for (i = 0; i < sizeof names / sizeof names[0]; ++i)
     276      {
     277        size_t len;
     278        char *namebuf;
     279        FILE *e;
     280        struct stat st;
     281        char *rbuf;
     282        size_t got;
     283  
     284        len = strlen (SRCDIR) + strlen (names[i]) + 2;
     285        namebuf = malloc (len);
     286        if (namebuf == NULL)
     287  	{
     288  	  perror ("malloc");
     289  	  goto fail;
     290  	}
     291        snprintf (namebuf, len, "%s/%s", SRCDIR, names[i]);
     292        e = fopen (namebuf, "r");
     293        free (namebuf);
     294        if (e == NULL)
     295  	continue;
     296        if (fstat (fileno (e), &st) < 0)
     297  	{
     298  	  perror ("fstat");
     299  	  fclose (e);
     300  	  continue;
     301  	}
     302        rbuf = malloc (st.st_size);
     303        if (rbuf == NULL)
     304  	{
     305  	  perror ("malloc");
     306  	  goto fail;
     307  	}
     308        got = fread (rbuf, 1, st.st_size, e);
     309        fclose (e);
     310        if (got > 0)
     311  	{
     312  	  orig_buf = (unsigned char *) rbuf;
     313  	  orig_bufsize = got;
     314  	  break;
     315  	}
     316        free (rbuf);
     317      }
     318  
     319    if (orig_buf == NULL)
     320      {
     321        /* We couldn't find an input file.  */
     322        printf ("UNSUPPORTED: lzma large\n");
     323        return;
     324      }
     325  
     326    stream = initial_stream;
     327    r =  lzma_easy_encoder (&stream, 6, LZMA_CHECK_CRC32);
     328    if (r != LZMA_OK)
     329      {
     330        fprintf (stderr, "lzma_easy_encoder failed: %d\n", r);
     331        goto fail;
     332      }
     333  
     334    compressed_bufsize = orig_bufsize + 100;
     335    compressed_buf = malloc (compressed_bufsize);
     336    if (compressed_buf == NULL)
     337      {
     338        perror ("malloc");
     339        goto fail;
     340      }
     341  
     342    stream.next_in = orig_buf;
     343    stream.avail_in = orig_bufsize;
     344    stream.next_out = compressed_buf;
     345    stream.avail_out = compressed_bufsize;
     346  
     347    do
     348      {
     349        r = lzma_code (&stream, LZMA_FINISH);
     350        if (r != LZMA_OK && r != LZMA_STREAM_END)
     351  	{
     352  	  fprintf (stderr, "lzma_code failed: %d\n", r);
     353  	  goto fail;
     354  	}
     355      }
     356    while (r != LZMA_STREAM_END);
     357  
     358    compressed_bufsize = stream.total_out;
     359  
     360    if (!backtrace_uncompress_lzma (state, (unsigned char *) compressed_buf,
     361  				  compressed_bufsize,
     362  				  error_callback_compress, NULL,
     363  				  &uncompressed_buf, &uncompressed_bufsize))
     364      {
     365        fprintf (stderr, "lzma large: backtrace_uncompress_lzma failed\n");
     366        goto fail;
     367      }
     368  
     369    if (uncompressed_bufsize != orig_bufsize)
     370      {
     371        fprintf (stderr,
     372  	       "lzma large: got uncompressed length %zu, want %zu\n",
     373  	       uncompressed_bufsize, orig_bufsize);
     374        goto fail;
     375      }
     376  
     377    if (memcmp (uncompressed_buf, orig_buf, uncompressed_bufsize) != 0)
     378      {
     379        fprintf (stderr, "lzma large: uncompressed data mismatch\n");
     380        goto fail;
     381      }
     382  
     383    printf ("PASS: lzma large\n");
     384  
     385    spare_buf = malloc (orig_bufsize);
     386    if (spare_buf == NULL)
     387      {
     388        perror ("malloc");
     389        goto fail;
     390      }
     391  
     392    for (i = 0; i < trials; ++i)
     393      {
     394        cid = LIBLZMA_CLOCK_GETTIME_ARG;
     395        if (clock_gettime (cid, &ts1) < 0)
     396  	{
     397  	  if (errno == EINVAL)
     398  	    return;
     399  	  perror ("clock_gettime");
     400  	  return;
     401  	}
     402  
     403        if (!backtrace_uncompress_lzma (state,
     404  				      (unsigned char *) compressed_buf,
     405  				      compressed_bufsize,
     406  				      error_callback_compress, NULL,
     407  				      &uncompressed_buf,
     408  				      &uncompressed_bufsize))
     409  	{
     410  	  fprintf (stderr,
     411  		   ("lzma large: "
     412  		    "benchmark backtrace_uncompress_lzma failed\n"));
     413  	  return;
     414  	}
     415  
     416        if (clock_gettime (cid, &ts2) < 0)
     417  	{
     418  	  perror ("clock_gettime");
     419  	  return;
     420  	}
     421  
     422        ctime = (ts2.tv_sec - ts1.tv_sec) * 1000000000;
     423        ctime += ts2.tv_nsec - ts1.tv_nsec;
     424        ctimes[i] = ctime;
     425  
     426        stream = initial_stream;
     427  
     428        r = lzma_auto_decoder (&stream, UINT64_MAX, 0);
     429        if (r != LZMA_OK)
     430  	{
     431  	  fprintf (stderr, "lzma_stream_decoder failed: %d\n", r);
     432  	  goto fail;
     433  	}
     434  
     435        stream.next_in = compressed_buf;
     436        stream.avail_in = compressed_bufsize;
     437        stream.next_out = spare_buf;
     438        stream.avail_out = orig_bufsize;
     439  
     440        if (clock_gettime (cid, &ts1) < 0)
     441  	{
     442  	  perror("clock_gettime");
     443  	  return;
     444  	}
     445  
     446        do
     447  	{
     448  	  r = lzma_code (&stream, LZMA_FINISH);
     449  	  if (r != LZMA_OK && r != LZMA_STREAM_END)
     450  	    {
     451  	      fprintf (stderr, "lzma_code failed: %d\n", r);
     452  	      goto fail;
     453  	    }
     454  	}
     455        while (r != LZMA_STREAM_END);
     456  
     457        if (clock_gettime (cid, &ts2) < 0)
     458  	{
     459  	  perror ("clock_gettime");
     460  	  return;
     461  	}
     462  
     463        ztime = (ts2.tv_sec - ts1.tv_sec) * 1000000000;
     464        ztime += ts2.tv_nsec - ts1.tv_nsec;
     465        ztimes[i] = ztime;
     466      }
     467  
     468    /* Toss the highest and lowest times and average the rest.  */
     469    ctime = average_time (ctimes, trials);
     470    ztime = average_time (ztimes, trials);
     471  
     472    printf ("backtrace: %zu ns\n", ctime);
     473    printf ("liblzma  : %zu ns\n", ztime);
     474    printf ("ratio    : %g\n", (double) ztime / (double) ctime);
     475  
     476    return;
     477  
     478   fail:
     479    printf ("FAIL: lzma large\n");
     480    ++failures;
     481  
     482    if (orig_buf != NULL)
     483      free (orig_buf);
     484    if (compressed_buf != NULL)
     485      free (compressed_buf);
     486    if (uncompressed_buf != NULL)
     487      free (uncompressed_buf);
     488  
     489  #else /* !HAVE_LIBLZMA */
     490  
     491   printf ("UNSUPPORTED: lzma large\n");
     492  
     493  #endif /* !HAVE_LIBLZMA */
     494  }
     495  
     496  int
     497  main (int argc ATTRIBUTE_UNUSED, char **argv)
     498  {
     499    struct backtrace_state *state;
     500  
     501    state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
     502  				  error_callback_create, NULL);
     503  
     504    test_samples (state);
     505    test_large (state);
     506  
     507    exit (failures != 0 ? EXIT_FAILURE : EXIT_SUCCESS);
     508  }