stream_decompress.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. /*
  2. * Copyright (c) Facebook, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under both the BSD-style license (found in the
  6. * LICENSE file in the root directory of this source tree) and the GPLv2 (found
  7. * in the COPYING file in the root directory of this source tree).
  8. * You may select, at your option, one of the above-listed licenses.
  9. */
  10. /**
  11. * This fuzz target attempts to decompress the fuzzed data with the simple
  12. * decompression function to ensure the decompressor never crashes.
  13. */
  14. #define ZSTD_STATIC_LINKING_ONLY
  15. #include <stddef.h>
  16. #include <stdlib.h>
  17. #include <stdio.h>
  18. #include "fuzz_helpers.h"
  19. #include "zstd.h"
  20. #include "fuzz_data_producer.h"
  21. static ZSTD_DStream *dstream = NULL;
  22. uint32_t seed;
  23. static ZSTD_outBuffer makeOutBuffer(FUZZ_dataProducer_t *producer, void* buf, size_t bufSize)
  24. {
  25. ZSTD_outBuffer buffer = { buf, 0, 0 };
  26. if (FUZZ_dataProducer_empty(producer)) {
  27. buffer.size = bufSize;
  28. } else {
  29. buffer.size = (FUZZ_dataProducer_uint32Range(producer, 0, bufSize));
  30. }
  31. FUZZ_ASSERT(buffer.size <= bufSize);
  32. if (buffer.size == 0) {
  33. buffer.dst = NULL;
  34. }
  35. return buffer;
  36. }
  37. static ZSTD_inBuffer makeInBuffer(const uint8_t **src, size_t *size,
  38. FUZZ_dataProducer_t *producer)
  39. {
  40. ZSTD_inBuffer buffer = { *src, 0, 0 };
  41. FUZZ_ASSERT(*size > 0);
  42. if (FUZZ_dataProducer_empty(producer)) {
  43. buffer.size = *size;
  44. } else {
  45. buffer.size = (FUZZ_dataProducer_uint32Range(producer, 0, *size));
  46. }
  47. FUZZ_ASSERT(buffer.size <= *size);
  48. *src += buffer.size;
  49. *size -= buffer.size;
  50. if (buffer.size == 0) {
  51. buffer.src = NULL;
  52. }
  53. return buffer;
  54. }
  55. int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
  56. {
  57. /* Give a random portion of src data to the producer, to use for
  58. parameter generation. The rest will be used for (de)compression */
  59. FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
  60. int stableOutBuffer;
  61. ZSTD_outBuffer out;
  62. void* buf;
  63. size_t bufSize;
  64. size = FUZZ_dataProducer_reserveDataPrefix(producer);
  65. bufSize = MAX(10 * size, ZSTD_BLOCKSIZE_MAX);
  66. /* Allocate all buffers and contexts if not already allocated */
  67. buf = FUZZ_malloc(bufSize);
  68. if (!dstream) {
  69. dstream = ZSTD_createDStream();
  70. FUZZ_ASSERT(dstream);
  71. } else {
  72. FUZZ_ZASSERT(ZSTD_DCtx_reset(dstream, ZSTD_reset_session_only));
  73. }
  74. stableOutBuffer = FUZZ_dataProducer_uint32Range(producer, 0, 10) == 5;
  75. if (stableOutBuffer) {
  76. FUZZ_ZASSERT(ZSTD_DCtx_setParameter(dstream, ZSTD_d_stableOutBuffer, 1));
  77. out.dst = buf;
  78. out.size = bufSize;
  79. out.pos = 0;
  80. } else {
  81. out = makeOutBuffer(producer, buf, bufSize);
  82. }
  83. while (size > 0) {
  84. ZSTD_inBuffer in = makeInBuffer(&src, &size, producer);
  85. while (in.pos != in.size) {
  86. if (out.pos == out.size) {
  87. if (stableOutBuffer) goto error;
  88. out = makeOutBuffer(producer, buf, bufSize);
  89. }
  90. size_t const rc = ZSTD_decompressStream(dstream, &out, &in);
  91. if (ZSTD_isError(rc)) goto error;
  92. }
  93. }
  94. error:
  95. #ifndef STATEFUL_FUZZING
  96. ZSTD_freeDStream(dstream); dstream = NULL;
  97. #endif
  98. FUZZ_dataProducer_free(producer);
  99. free(buf);
  100. return 0;
  101. }