| 1 | /* |
| 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. |
| 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 | |
| 12 | #include <stdio.h> |
| 13 | #include <stddef.h> |
| 14 | #include <stdlib.h> |
| 15 | #include <stdint.h> |
| 16 | #include "mem.h" |
| 17 | #define ZSTD_STATIC_LINKING_ONLY |
| 18 | #include "zstd.h" |
| 19 | |
| 20 | static int |
| 21 | compress(ZSTD_CStream *ctx, ZSTD_outBuffer out, const void *data, size_t size) |
| 22 | { |
| 23 | ZSTD_inBuffer in = { data, size, 0 }; |
| 24 | while (in.pos < in.size) { |
| 25 | ZSTD_outBuffer tmp = out; |
| 26 | const size_t rc = ZSTD_compressStream(ctx, &tmp, &in); |
| 27 | if (ZSTD_isError(rc)) return 1; |
| 28 | } |
| 29 | { ZSTD_outBuffer tmp = out; |
| 30 | const size_t rc = ZSTD_flushStream(ctx, &tmp); |
| 31 | if (rc != 0) { return 1; } |
| 32 | } |
| 33 | return 0; |
| 34 | } |
| 35 | |
| 36 | int main(int argc, const char** argv) |
| 37 | { |
| 38 | ZSTD_CStream* ctx; |
| 39 | unsigned windowLog = 18; |
| 40 | (void)argc; |
| 41 | (void)argv; |
| 42 | /* Create stream */ |
| 43 | ctx = ZSTD_createCCtx(); |
| 44 | if (!ctx) { return 1; } |
| 45 | /* Set parameters */ |
| 46 | if (ZSTD_isError(ZSTD_CCtx_setParameter(ctx, ZSTD_c_windowLog, windowLog))) |
| 47 | return 2; |
| 48 | if (ZSTD_isError(ZSTD_CCtx_setParameter(ctx, ZSTD_c_chainLog, 13))) |
| 49 | return 2; |
| 50 | if (ZSTD_isError(ZSTD_CCtx_setParameter(ctx, ZSTD_c_hashLog, 14))) |
| 51 | return 2; |
| 52 | if (ZSTD_isError(ZSTD_CCtx_setParameter(ctx, ZSTD_c_searchLog, 1))) |
| 53 | return 2; |
| 54 | if (ZSTD_isError(ZSTD_CCtx_setParameter(ctx, ZSTD_c_minMatch, 7))) |
| 55 | return 2; |
| 56 | if (ZSTD_isError(ZSTD_CCtx_setParameter(ctx, ZSTD_c_targetLength, 16))) |
| 57 | return 2; |
| 58 | if (ZSTD_isError(ZSTD_CCtx_setParameter(ctx, ZSTD_c_strategy, ZSTD_fast))) |
| 59 | return 2; |
| 60 | { |
| 61 | U64 compressed = 0; |
| 62 | const U64 toCompress = ((U64)1) << 33; |
| 63 | const size_t size = 1 << windowLog; |
| 64 | size_t pos = 0; |
| 65 | char *srcBuffer = (char*) malloc(1 << windowLog); |
| 66 | char *dstBuffer = (char*) malloc(ZSTD_compressBound(1 << windowLog)); |
| 67 | ZSTD_outBuffer out = { dstBuffer, ZSTD_compressBound(1 << windowLog), 0 }; |
| 68 | const char match[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
| 69 | const size_t randomData = (1 << windowLog) - 2*sizeof(match); |
| 70 | size_t i; |
| 71 | printf("\n === Long Match Test === \n"); |
| 72 | printf("Creating random data to produce long matches \n"); |
| 73 | for (i = 0; i < sizeof(match); ++i) { |
| 74 | srcBuffer[i] = match[i]; |
| 75 | } |
| 76 | for (i = 0; i < randomData; ++i) { |
| 77 | srcBuffer[sizeof(match) + i] = (char)(rand() & 0xFF); |
| 78 | } |
| 79 | for (i = 0; i < sizeof(match); ++i) { |
| 80 | srcBuffer[sizeof(match) + randomData + i] = match[i]; |
| 81 | } |
| 82 | printf("Compressing, trying to generate a segfault \n"); |
| 83 | if (compress(ctx, out, srcBuffer, size)) { |
| 84 | return 1; |
| 85 | } |
| 86 | compressed += size; |
| 87 | while (compressed < toCompress) { |
| 88 | const size_t block = rand() % (size - pos + 1); |
| 89 | if (pos == size) { pos = 0; } |
| 90 | if (compress(ctx, out, srcBuffer + pos, block)) { |
| 91 | return 1; |
| 92 | } |
| 93 | pos += block; |
| 94 | compressed += block; |
| 95 | } |
| 96 | printf("Compression completed successfully (no error triggered)\n"); |
| 97 | free(srcBuffer); |
| 98 | free(dstBuffer); |
| 99 | } |
| 100 | ZSTD_freeCCtx(ctx); |
| 101 | return 0; |
| 102 | } |