1*01826a49SYabin Cui /*
2*01826a49SYabin Cui * Copyright (c) Meta Platforms, Inc. and affiliates.
3*01826a49SYabin Cui * All rights reserved.
4*01826a49SYabin Cui *
5*01826a49SYabin Cui * This source code is licensed under both the BSD-style license (found in the
6*01826a49SYabin Cui * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7*01826a49SYabin Cui * in the COPYING file in the root directory of this source tree).
8*01826a49SYabin Cui * You may select, at your option, one of the above-listed licenses.
9*01826a49SYabin Cui */
10*01826a49SYabin Cui #include <stddef.h>
11*01826a49SYabin Cui #include <stdio.h>
12*01826a49SYabin Cui #include <stdlib.h>
13*01826a49SYabin Cui #include <string.h>
14*01826a49SYabin Cui
15*01826a49SYabin Cui #include <linux/zstd.h>
16*01826a49SYabin Cui
17*01826a49SYabin Cui #define CONTROL(x) \
18*01826a49SYabin Cui do { \
19*01826a49SYabin Cui if (!(x)) { \
20*01826a49SYabin Cui fprintf(stderr, "%s:%u: %s failed!\n", __FUNCTION__, __LINE__, #x); \
21*01826a49SYabin Cui abort(); \
22*01826a49SYabin Cui } \
23*01826a49SYabin Cui } while (0)
24*01826a49SYabin Cui
25*01826a49SYabin Cui typedef struct {
26*01826a49SYabin Cui char *data;
27*01826a49SYabin Cui char *data2;
28*01826a49SYabin Cui size_t dataSize;
29*01826a49SYabin Cui char *comp;
30*01826a49SYabin Cui size_t compSize;
31*01826a49SYabin Cui } test_data_t;
32*01826a49SYabin Cui
create_test_data(void)33*01826a49SYabin Cui static test_data_t create_test_data(void) {
34*01826a49SYabin Cui test_data_t data;
35*01826a49SYabin Cui data.dataSize = 128 * 1024;
36*01826a49SYabin Cui data.data = (char*)malloc(data.dataSize);
37*01826a49SYabin Cui CONTROL(data.data != NULL);
38*01826a49SYabin Cui data.data2 = (char*)malloc(data.dataSize);
39*01826a49SYabin Cui CONTROL(data.data2 != NULL);
40*01826a49SYabin Cui data.compSize = zstd_compress_bound(data.dataSize);
41*01826a49SYabin Cui data.comp = (char*)malloc(data.compSize);
42*01826a49SYabin Cui CONTROL(data.comp != NULL);
43*01826a49SYabin Cui memset(data.data, 0, data.dataSize);
44*01826a49SYabin Cui return data;
45*01826a49SYabin Cui }
46*01826a49SYabin Cui
free_test_data(test_data_t const * data)47*01826a49SYabin Cui static void free_test_data(test_data_t const *data) {
48*01826a49SYabin Cui free(data->data);
49*01826a49SYabin Cui free(data->data2);
50*01826a49SYabin Cui free(data->comp);
51*01826a49SYabin Cui }
52*01826a49SYabin Cui
53*01826a49SYabin Cui #define MIN(a, b) ((a) < (b) ? (a) : (b))
54*01826a49SYabin Cui #define MAX(a, b) ((a) > (b) ? (a) : (b))
55*01826a49SYabin Cui
test_btrfs(test_data_t const * data)56*01826a49SYabin Cui static void test_btrfs(test_data_t const *data) {
57*01826a49SYabin Cui size_t const size = MIN(data->dataSize, 128 * 1024);
58*01826a49SYabin Cui fprintf(stderr, "testing btrfs use cases... ");
59*01826a49SYabin Cui for (int level = -1; level < 16; ++level) {
60*01826a49SYabin Cui zstd_parameters params = zstd_get_params(level, size);
61*01826a49SYabin Cui size_t const workspaceSize =
62*01826a49SYabin Cui MAX(zstd_cstream_workspace_bound(¶ms.cParams),
63*01826a49SYabin Cui zstd_dstream_workspace_bound(size));
64*01826a49SYabin Cui void *workspace = malloc(workspaceSize);
65*01826a49SYabin Cui
66*01826a49SYabin Cui char const *ip = data->data;
67*01826a49SYabin Cui char const *iend = ip + size;
68*01826a49SYabin Cui char *op = data->comp;
69*01826a49SYabin Cui char *oend = op + data->compSize;
70*01826a49SYabin Cui
71*01826a49SYabin Cui CONTROL(params.cParams.windowLog <= 17);
72*01826a49SYabin Cui CONTROL(workspace != NULL);
73*01826a49SYabin Cui {
74*01826a49SYabin Cui zstd_cstream *cctx = zstd_init_cstream(¶ms, size, workspace, workspaceSize);
75*01826a49SYabin Cui zstd_out_buffer out = {NULL, 0, 0};
76*01826a49SYabin Cui zstd_in_buffer in = {NULL, 0, 0};
77*01826a49SYabin Cui CONTROL(cctx != NULL);
78*01826a49SYabin Cui for (;;) {
79*01826a49SYabin Cui if (in.pos == in.size) {
80*01826a49SYabin Cui in.src = ip;
81*01826a49SYabin Cui in.size = MIN(4096, iend - ip);
82*01826a49SYabin Cui in.pos = 0;
83*01826a49SYabin Cui ip += in.size;
84*01826a49SYabin Cui }
85*01826a49SYabin Cui
86*01826a49SYabin Cui if (out.pos == out.size) {
87*01826a49SYabin Cui out.dst = op;
88*01826a49SYabin Cui out.size = MIN(4096, oend - op);
89*01826a49SYabin Cui out.pos = 0;
90*01826a49SYabin Cui op += out.size;
91*01826a49SYabin Cui }
92*01826a49SYabin Cui
93*01826a49SYabin Cui if (ip != iend || in.pos < in.size) {
94*01826a49SYabin Cui CONTROL(!zstd_is_error(zstd_compress_stream(cctx, &out, &in)));
95*01826a49SYabin Cui } else {
96*01826a49SYabin Cui size_t const ret = zstd_end_stream(cctx, &out);
97*01826a49SYabin Cui CONTROL(!zstd_is_error(ret));
98*01826a49SYabin Cui if (ret == 0) {
99*01826a49SYabin Cui break;
100*01826a49SYabin Cui }
101*01826a49SYabin Cui }
102*01826a49SYabin Cui }
103*01826a49SYabin Cui op += out.pos;
104*01826a49SYabin Cui }
105*01826a49SYabin Cui
106*01826a49SYabin Cui ip = data->comp;
107*01826a49SYabin Cui iend = op;
108*01826a49SYabin Cui op = data->data2;
109*01826a49SYabin Cui oend = op + size;
110*01826a49SYabin Cui {
111*01826a49SYabin Cui zstd_dstream *dctx = zstd_init_dstream(1ULL << params.cParams.windowLog, workspace, workspaceSize);
112*01826a49SYabin Cui zstd_out_buffer out = {NULL, 0, 0};
113*01826a49SYabin Cui zstd_in_buffer in = {NULL, 0, 0};
114*01826a49SYabin Cui CONTROL(dctx != NULL);
115*01826a49SYabin Cui for (;;) {
116*01826a49SYabin Cui if (in.pos == in.size) {
117*01826a49SYabin Cui in.src = ip;
118*01826a49SYabin Cui in.size = MIN(4096, iend - ip);
119*01826a49SYabin Cui in.pos = 0;
120*01826a49SYabin Cui ip += in.size;
121*01826a49SYabin Cui }
122*01826a49SYabin Cui
123*01826a49SYabin Cui if (out.pos == out.size) {
124*01826a49SYabin Cui out.dst = op;
125*01826a49SYabin Cui out.size = MIN(4096, oend - op);
126*01826a49SYabin Cui out.pos = 0;
127*01826a49SYabin Cui op += out.size;
128*01826a49SYabin Cui }
129*01826a49SYabin Cui {
130*01826a49SYabin Cui size_t const ret = zstd_decompress_stream(dctx, &out, &in);
131*01826a49SYabin Cui CONTROL(!zstd_is_error(ret));
132*01826a49SYabin Cui if (ret == 0) {
133*01826a49SYabin Cui break;
134*01826a49SYabin Cui }
135*01826a49SYabin Cui }
136*01826a49SYabin Cui }
137*01826a49SYabin Cui }
138*01826a49SYabin Cui CONTROL((size_t)(op - data->data2) == data->dataSize);
139*01826a49SYabin Cui CONTROL(!memcmp(data->data, data->data2, data->dataSize));
140*01826a49SYabin Cui free(workspace);
141*01826a49SYabin Cui }
142*01826a49SYabin Cui fprintf(stderr, "Ok\n");
143*01826a49SYabin Cui }
144*01826a49SYabin Cui
test_decompress_unzstd(test_data_t const * data)145*01826a49SYabin Cui static void test_decompress_unzstd(test_data_t const *data) {
146*01826a49SYabin Cui size_t cSize;
147*01826a49SYabin Cui fprintf(stderr, "Testing decompress unzstd... ");
148*01826a49SYabin Cui {
149*01826a49SYabin Cui zstd_parameters params = zstd_get_params(19, 0);
150*01826a49SYabin Cui size_t const wkspSize = zstd_cctx_workspace_bound(¶ms.cParams);
151*01826a49SYabin Cui void* wksp = malloc(wkspSize);
152*01826a49SYabin Cui zstd_cctx* cctx = zstd_init_cctx(wksp, wkspSize);
153*01826a49SYabin Cui CONTROL(wksp != NULL);
154*01826a49SYabin Cui CONTROL(cctx != NULL);
155*01826a49SYabin Cui cSize = zstd_compress_cctx(cctx, data->comp, data->compSize, data->data, data->dataSize, ¶ms);
156*01826a49SYabin Cui CONTROL(!zstd_is_error(cSize));
157*01826a49SYabin Cui free(wksp);
158*01826a49SYabin Cui }
159*01826a49SYabin Cui {
160*01826a49SYabin Cui size_t const wkspSize = zstd_dctx_workspace_bound();
161*01826a49SYabin Cui void* wksp = malloc(wkspSize);
162*01826a49SYabin Cui zstd_dctx* dctx = zstd_init_dctx(wksp, wkspSize);
163*01826a49SYabin Cui CONTROL(wksp != NULL);
164*01826a49SYabin Cui CONTROL(dctx != NULL);
165*01826a49SYabin Cui {
166*01826a49SYabin Cui size_t const dSize = zstd_decompress_dctx(dctx, data->data2, data->dataSize, data->comp, cSize);
167*01826a49SYabin Cui CONTROL(!zstd_is_error(dSize));
168*01826a49SYabin Cui CONTROL(dSize == data->dataSize);
169*01826a49SYabin Cui }
170*01826a49SYabin Cui CONTROL(!memcmp(data->data, data->data2, data->dataSize));
171*01826a49SYabin Cui free(wksp);
172*01826a49SYabin Cui }
173*01826a49SYabin Cui fprintf(stderr, "Ok\n");
174*01826a49SYabin Cui }
175*01826a49SYabin Cui
test_f2fs(void)176*01826a49SYabin Cui static void test_f2fs(void) {
177*01826a49SYabin Cui fprintf(stderr, "testing f2fs uses... ");
178*01826a49SYabin Cui CONTROL(zstd_min_clevel() < 0);
179*01826a49SYabin Cui CONTROL(zstd_max_clevel() == 22);
180*01826a49SYabin Cui fprintf(stderr, "Ok\n");
181*01826a49SYabin Cui }
182*01826a49SYabin Cui
183*01826a49SYabin Cui static char *g_stack = NULL;
184*01826a49SYabin Cui
use(void * x)185*01826a49SYabin Cui static void __attribute__((noinline)) use(void *x) {
186*01826a49SYabin Cui asm volatile("" : "+r"(x));
187*01826a49SYabin Cui }
188*01826a49SYabin Cui
fill_stack(void)189*01826a49SYabin Cui static void __attribute__((noinline)) fill_stack(void) {
190*01826a49SYabin Cui memset(g_stack, 0x33, 8192);
191*01826a49SYabin Cui }
192*01826a49SYabin Cui
set_stack(void)193*01826a49SYabin Cui static void __attribute__((noinline)) set_stack(void) {
194*01826a49SYabin Cui
195*01826a49SYabin Cui char stack[8192];
196*01826a49SYabin Cui g_stack = stack;
197*01826a49SYabin Cui use(g_stack);
198*01826a49SYabin Cui }
199*01826a49SYabin Cui
check_stack(void)200*01826a49SYabin Cui static void __attribute__((noinline)) check_stack(void) {
201*01826a49SYabin Cui size_t cleanStack = 0;
202*01826a49SYabin Cui while (cleanStack < 8192 && g_stack[cleanStack] == 0x33) {
203*01826a49SYabin Cui ++cleanStack;
204*01826a49SYabin Cui }
205*01826a49SYabin Cui {
206*01826a49SYabin Cui size_t const stackSize = 8192 - cleanStack;
207*01826a49SYabin Cui fprintf(stderr, "Maximum stack size: %zu\n", stackSize);
208*01826a49SYabin Cui CONTROL(stackSize <= 2048 + 512);
209*01826a49SYabin Cui }
210*01826a49SYabin Cui }
211*01826a49SYabin Cui
test_stack_usage(test_data_t const * data)212*01826a49SYabin Cui static void test_stack_usage(test_data_t const *data) {
213*01826a49SYabin Cui set_stack();
214*01826a49SYabin Cui fill_stack();
215*01826a49SYabin Cui test_f2fs();
216*01826a49SYabin Cui test_btrfs(data);
217*01826a49SYabin Cui test_decompress_unzstd(data);
218*01826a49SYabin Cui check_stack();
219*01826a49SYabin Cui }
220*01826a49SYabin Cui
main(void)221*01826a49SYabin Cui int main(void) {
222*01826a49SYabin Cui test_data_t data = create_test_data();
223*01826a49SYabin Cui test_f2fs();
224*01826a49SYabin Cui test_btrfs(&data);
225*01826a49SYabin Cui test_decompress_unzstd(&data);
226*01826a49SYabin Cui test_stack_usage(&data);
227*01826a49SYabin Cui free_test_data(&data);
228*01826a49SYabin Cui return 0;
229*01826a49SYabin Cui }
230