Coverage Report

Created: 2025-10-12 07:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/simdutf/fuzz/roundtrip.cpp
Line
Count
Source
1
#include <cstring>
2
#include <fuzzer/FuzzedDataProvider.h>
3
#include <memory>
4
#include <string>
5
#include <iostream>
6
7
#include "simdutf.h"
8
9
// useful for debugging
10
static void print_input(const std::string& s,
11
0
                        const simdutf::implementation* const e) {
12
0
  printf("We are about to abort on the following input: ");
13
0
  for (auto c : s) {
14
0
    printf("%02x ", (unsigned char)c);
15
0
  }
16
0
  printf("\n");
17
0
  std::cout << "string length : " << s.size() << " bytes" << std::endl;
18
0
  std::cout << "implementation->name() = " << e->name() << std::endl;
19
0
}
20
21
/**
22
 * We do round trips from UTF-8 to UTF-16, from UTF-8 to UTF-32, from UTF-16 to
23
 * UTF-8.
24
 * We do round trips from Latin 1 to UTF-8, from Latin 1 to UTF-16, from Latin 1
25
 * to UTF-32. We test all available kernels. We also try to transcode invalid
26
 * inputs.
27
 */
28
5.45k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
29
5.45k
  FuzzedDataProvider fdp(data, size);
30
5.45k
  constexpr int kMaxStringSize = 1024;
31
5.45k
  std::string source = fdp.ConsumeRandomLengthString(kMaxStringSize);
32
21.8k
  for (auto& e : simdutf::get_available_implementations()) {
33
21.8k
    if (!e->supported_by_runtime_system()) {
34
5.45k
      continue;
35
5.45k
    }
36
    /**
37
     * Transcoding from UTF-8 to UTF-16LE.
38
     */
39
16.3k
    bool validutf8 = e->validate_utf8(source.c_str(), source.size());
40
16.3k
    auto rutf8 = e->validate_utf8_with_errors(source.c_str(), source.size());
41
16.3k
    if (validutf8 != (rutf8.error == simdutf::SUCCESS)) { // they should agree
42
0
      print_input(source, e);
43
0
      abort();
44
0
    }
45
16.3k
    if (validutf8) {
46
      // We need a buffer of size where to write the UTF-16LE words.
47
15.1k
      size_t expected_utf16words =
48
15.1k
          e->utf16_length_from_utf8(source.c_str(), source.size());
49
15.1k
      std::unique_ptr<char16_t[]> utf16_output{
50
15.1k
          new char16_t[expected_utf16words]};
51
      // convert to UTF-16LE
52
15.1k
      size_t utf16words = e->convert_utf8_to_utf16le(
53
15.1k
          source.c_str(), source.size(), utf16_output.get());
54
      // It wrote utf16words * sizeof(char16_t) bytes.
55
15.1k
      bool validutf16 = e->validate_utf16le(utf16_output.get(), utf16words);
56
15.1k
      if (!validutf16) {
57
0
        print_input(source, e);
58
0
        abort();
59
0
      }
60
      // convert it back:
61
      // We need a buffer of size where to write the UTF-8 words.
62
15.1k
      size_t expected_utf8words =
63
15.1k
          e->utf8_length_from_utf16le(utf16_output.get(), utf16words);
64
15.1k
      std::unique_ptr<char[]> utf8_output{new char[expected_utf8words]};
65
      // convert to UTF-8
66
15.1k
      size_t utf8words = e->convert_utf16le_to_utf8(
67
15.1k
          utf16_output.get(), utf16words, utf8_output.get());
68
15.1k
      std::string final_string(utf8_output.get(), utf8words);
69
15.1k
      if (final_string != source) {
70
0
        print_input(source, e);
71
0
        abort();
72
0
      }
73
15.1k
    } else {
74
      // invalid input!!!
75
      // We need a buffer of size where to write the UTF-16LE words.
76
1.19k
      size_t expected_utf16words =
77
1.19k
          e->utf16_length_from_utf8(source.c_str(), source.size());
78
1.19k
      std::unique_ptr<char16_t[]> utf16_output{
79
1.19k
          new char16_t[expected_utf16words]};
80
      // convert to UTF-16LE
81
1.19k
      size_t utf16words = e->convert_utf8_to_utf16le(
82
1.19k
          source.c_str(), source.size(), utf16_output.get());
83
1.19k
      if (utf16words != 0) {
84
0
        print_input(source, e);
85
0
        abort();
86
0
      }
87
1.19k
    }
88
89
    /**
90
     * Transcoding from UTF-8 to UTF-16BE.
91
     */
92
16.3k
    if (validutf8) {
93
      // We need a buffer of size where to write the UTF-16BE words.
94
15.1k
      size_t expected_utf16words =
95
15.1k
          e->utf16_length_from_utf8(source.c_str(), source.size());
96
15.1k
      std::unique_ptr<char16_t[]> utf16_output{
97
15.1k
          new char16_t[expected_utf16words]};
98
      // convert to UTF-16BE
99
15.1k
      size_t utf16words = e->convert_utf8_to_utf16be(
100
15.1k
          source.c_str(), source.size(), utf16_output.get());
101
      // It wrote utf16words * sizeof(char16_t) bytes.
102
15.1k
      bool validutf16 = e->validate_utf16be(utf16_output.get(), utf16words);
103
15.1k
      if (!validutf16) {
104
0
        print_input(source, e);
105
0
        abort();
106
0
      }
107
      // convert it back:
108
      // We need a buffer of size where to write the UTF-8 words.
109
15.1k
      size_t expected_utf8words =
110
15.1k
          e->utf8_length_from_utf16be(utf16_output.get(), utf16words);
111
15.1k
      std::unique_ptr<char[]> utf8_output{new char[expected_utf8words]};
112
      // convert to UTF-8
113
15.1k
      size_t utf8words = e->convert_utf16be_to_utf8(
114
15.1k
          utf16_output.get(), utf16words, utf8_output.get());
115
15.1k
      std::string final_string(utf8_output.get(), utf8words);
116
15.1k
      if (final_string != source) {
117
0
        print_input(source, e);
118
0
        abort();
119
0
      }
120
15.1k
    } else {
121
      // invalid input!!!
122
      // We need a buffer of size where to write the UTF-16BE words.
123
1.19k
      size_t expected_utf16words =
124
1.19k
          e->utf16_length_from_utf8(source.c_str(), source.size());
125
1.19k
      std::unique_ptr<char16_t[]> utf16_output{
126
1.19k
          new char16_t[expected_utf16words]};
127
      // convert to UTF-16BE
128
1.19k
      size_t utf16words = e->convert_utf8_to_utf16be(
129
1.19k
          source.c_str(), source.size(), utf16_output.get());
130
1.19k
      if (utf16words != 0) {
131
0
        print_input(source, e);
132
0
        abort();
133
0
      }
134
1.19k
    }
135
    /**
136
     * Transcoding from UTF-8 to UTF-32.
137
     */
138
16.3k
    if (validutf8) {
139
      // We need a buffer of size where to write the UTF-32 words.
140
15.1k
      size_t expected_utf32words =
141
15.1k
          e->utf32_length_from_utf8(source.c_str(), source.size());
142
15.1k
      std::unique_ptr<char32_t[]> utf32_output{
143
15.1k
          new char32_t[expected_utf32words]};
144
      // convert to UTF-32
145
15.1k
      size_t utf32words = e->convert_utf8_to_utf32(
146
15.1k
          source.c_str(), source.size(), utf32_output.get());
147
      // It wrote utf32words * sizeof(char32_t) bytes.
148
15.1k
      bool validutf32 = e->validate_utf32(utf32_output.get(), utf32words);
149
15.1k
      if (!validutf32) {
150
0
        return -1;
151
0
      }
152
      // convert it back:
153
      // We need a buffer of size where to write the UTF-8 words.
154
15.1k
      size_t expected_utf8words =
155
15.1k
          e->utf8_length_from_utf32(utf32_output.get(), utf32words);
156
15.1k
      std::unique_ptr<char[]> utf8_output{new char[expected_utf8words]};
157
      // convert to UTF-8
158
15.1k
      size_t utf8words = e->convert_utf32_to_utf8(
159
15.1k
          utf32_output.get(), utf32words, utf8_output.get());
160
15.1k
      std::string final_string(utf8_output.get(), utf8words);
161
15.1k
      if (source != final_string) {
162
0
        print_input(source, e);
163
0
        abort();
164
0
      }
165
15.1k
    } else {
166
      // invalid input!!!
167
1.19k
      size_t expected_utf32words =
168
1.19k
          e->utf32_length_from_utf8(source.c_str(), source.size());
169
1.19k
      std::unique_ptr<char32_t[]> utf32_output{
170
1.19k
          new char32_t[expected_utf32words]};
171
      // convert to UTF-32
172
1.19k
      size_t utf32words = e->convert_utf8_to_utf32(
173
1.19k
          source.c_str(), source.size(), utf32_output.get());
174
1.19k
      if (utf32words != 0) {
175
0
        print_input(source, e);
176
0
        abort();
177
0
      }
178
1.19k
    }
179
180
    /**
181
     * Transcoding from UTF-8 to Latin 1
182
     */
183
16.3k
    if (validutf8) {
184
      // We need a buffer of size where to write the UTF-16LE words.
185
15.1k
      size_t expected_latin1words =
186
15.1k
          e->latin1_length_from_utf8(source.c_str(), source.size());
187
15.1k
      std::unique_ptr<char[]> latin1_output{new char[expected_latin1words]};
188
      // convert to latin1
189
15.1k
      size_t latin1words = e->convert_utf8_to_latin1(
190
15.1k
          source.c_str(), source.size(), latin1_output.get());
191
15.1k
      if (latin1words != 0) {
192
        // convert it back:
193
        // We need a buffer of size where to write the UTF-8 words.
194
707
        size_t expected_utf8words =
195
707
            e->utf8_length_from_latin1(latin1_output.get(), latin1words);
196
707
        std::unique_ptr<char[]> utf8_output{new char[expected_utf8words]};
197
        // convert to UTF-8
198
707
        size_t utf8words = e->convert_latin1_to_utf8(
199
707
            latin1_output.get(), latin1words, utf8_output.get());
200
707
        std::string final_string(utf8_output.get(), utf8words);
201
707
        if (final_string != source) {
202
0
          print_input(source, e);
203
0
          abort();
204
0
        }
205
707
      }
206
15.1k
    } else {
207
      // invalid input!!!
208
      // We need a buffer of size where to write the Latin 1 words.
209
1.19k
      size_t expected_latin1words =
210
1.19k
          e->latin1_length_from_utf8(source.c_str(), source.size());
211
1.19k
      std::unique_ptr<char[]> latin1_output{new char[expected_latin1words]};
212
      // convert to Latin 1
213
1.19k
      size_t latin1words = e->convert_utf8_to_latin1(
214
1.19k
          source.c_str(), source.size(), latin1_output.get());
215
1.19k
      if (latin1words != 0) {
216
0
        print_input(source, e);
217
0
        abort();
218
0
      }
219
1.19k
    }
220
    /**
221
     * Transcoding from UTF-16LE to UTF-8.
222
     */
223
16.3k
    {
224
      // Get new source data here as this will allow the fuzzer to optimize it's
225
      // input for UTF16-LE.
226
16.3k
      source = fdp.ConsumeRandomLengthString(kMaxStringSize);
227
      // We copy to avoid alignment issues.
228
16.3k
      std::unique_ptr<char16_t[]> utf16_source{new char16_t[source.size() / 2]};
229
16.3k
      if (source.data() != nullptr) {
230
16.3k
        std::memcpy(utf16_source.get(), source.data(), source.size() / 2 * 2);
231
16.3k
      }
232
16.3k
      bool validutf16le =
233
16.3k
          e->validate_utf16le(utf16_source.get(), source.size() / 2);
234
16.3k
      auto rutf16le = e->validate_utf16le_with_errors(utf16_source.get(),
235
16.3k
                                                      source.size() / 2);
236
16.3k
      if (validutf16le !=
237
16.3k
          (rutf16le.error == simdutf::SUCCESS)) { // they should agree
238
0
        print_input(source, e);
239
0
        abort();
240
0
      }
241
16.3k
      if (validutf16le) {
242
        // We need a buffer of size where to write the UTF-16 words.
243
16.1k
        size_t expected_utf8words =
244
16.1k
            e->utf8_length_from_utf16le(utf16_source.get(), source.size() / 2);
245
16.1k
        std::unique_ptr<char[]> utf8_output{new char[expected_utf8words]};
246
16.1k
        size_t utf8words = e->convert_utf16le_to_utf8(
247
16.1k
            utf16_source.get(), source.size() / 2, utf8_output.get());
248
        // It wrote utf16words * sizeof(char16_t) bytes.
249
16.1k
        bool validutf8 = e->validate_utf8(utf8_output.get(), utf8words);
250
16.1k
        if (!validutf8) {
251
0
          print_input(source, e);
252
0
          abort();
253
0
        }
254
        // convert it back:
255
        // We need a buffer of size where to write the UTF-16 words.
256
16.1k
        size_t expected_utf16words =
257
16.1k
            e->utf16_length_from_utf8(utf8_output.get(), utf8words);
258
16.1k
        std::unique_ptr<char16_t[]> utf16_output{
259
16.1k
            new char16_t[expected_utf16words]};
260
        // convert to UTF-8
261
16.1k
        size_t utf16words = e->convert_utf8_to_utf16le(
262
16.1k
            utf8_output.get(), utf8words, utf16_output.get());
263
94.0k
        for (size_t i = 0; i < source.size() / 2; i++) {
264
77.9k
          if (utf16_output.get()[i] != (utf16_source.get())[i]) {
265
0
            print_input(source, e);
266
0
            abort();
267
0
          }
268
77.9k
        }
269
16.1k
      } else {
270
        // invalid input!!!
271
        // We need a buffer of size where to write the UTF-16 words.
272
238
        size_t expected_utf8words =
273
238
            e->utf8_length_from_utf16le(utf16_source.get(), source.size() / 2);
274
238
        std::unique_ptr<char[]> utf8_output{new char[expected_utf8words]};
275
238
        size_t utf8words = e->convert_utf16le_to_utf8(
276
238
            utf16_source.get(), source.size() / 2, utf8_output.get());
277
238
        if (utf8words != 0) {
278
0
          print_input(source, e);
279
0
          abort();
280
0
        }
281
238
      }
282
16.3k
    }
283
284
    /**
285
     * Transcoding from UTF-16BE to UTF-8.
286
     */
287
16.3k
    {
288
      // Get new source data here as this will allow the fuzzer to optimize it's
289
      // input for UTF16-BE.
290
16.3k
      source = fdp.ConsumeRandomLengthString(kMaxStringSize);
291
16.3k
      std::unique_ptr<char16_t[]> utf16_source{new char16_t[source.size() / 2]};
292
16.3k
      if (source.data() != nullptr) {
293
16.3k
        std::memcpy(utf16_source.get(), source.data(), source.size() / 2 * 2);
294
16.3k
      }
295
16.3k
      bool validutf16be =
296
16.3k
          e->validate_utf16be(utf16_source.get(), source.size() / 2);
297
16.3k
      auto rutf16be = e->validate_utf16be_with_errors(utf16_source.get(),
298
16.3k
                                                      source.size() / 2);
299
16.3k
      if (validutf16be !=
300
16.3k
          (rutf16be.error == simdutf::SUCCESS)) { // they should agree
301
0
        print_input(source, e);
302
0
        abort();
303
0
      }
304
16.3k
      if (validutf16be) {
305
        // We need a buffer of size where to write the UTF-16 words.
306
16.1k
        size_t expected_utf8words =
307
16.1k
            e->utf8_length_from_utf16be(utf16_source.get(), source.size() / 2);
308
16.1k
        std::unique_ptr<char[]> utf8_output{new char[expected_utf8words]};
309
16.1k
        size_t utf8words = e->convert_utf16be_to_utf8(
310
16.1k
            utf16_source.get(), source.size() / 2, utf8_output.get());
311
        // It wrote utf16words * sizeof(char16_t) bytes.
312
16.1k
        bool validutf8 = e->validate_utf8(utf8_output.get(), utf8words);
313
16.1k
        if (!validutf8) {
314
0
          print_input(source, e);
315
0
          abort();
316
0
        }
317
        // convert it back:
318
        // We need a buffer of size where to write the UTF-16 words.
319
16.1k
        size_t expected_utf16words =
320
16.1k
            e->utf16_length_from_utf8(utf8_output.get(), utf8words);
321
16.1k
        std::unique_ptr<char16_t[]> utf16_output{
322
16.1k
            new char16_t[expected_utf16words]};
323
        // convert to UTF-8
324
16.1k
        size_t utf16words = e->convert_utf8_to_utf16be(
325
16.1k
            utf8_output.get(), utf8words, utf16_output.get());
326
100k
        for (size_t i = 0; i < source.size() / 2; i++) {
327
83.9k
          if (utf16_output.get()[i] != (utf16_source.get())[i]) {
328
0
            print_input(source, e);
329
0
            abort();
330
0
          }
331
83.9k
        }
332
16.1k
      } else {
333
        // invalid input!!!
334
        // We need a buffer of size where to write the UTF-16 words.
335
224
        size_t expected_utf8words =
336
224
            e->utf8_length_from_utf16be(utf16_source.get(), source.size() / 2);
337
224
        std::unique_ptr<char[]> utf8_output{new char[expected_utf8words]};
338
224
        size_t utf8words = e->convert_utf16be_to_utf8(
339
224
            utf16_source.get(), source.size() / 2, utf8_output.get());
340
224
        if (utf8words != 0) {
341
0
          print_input(source, e);
342
0
          abort();
343
0
        }
344
224
      }
345
16.3k
    }
346
347
    /**
348
     * Transcoding from latin1 to UTF-8.
349
     */
350
    // Get new source data here as this will allow the fuzzer to optimize it's
351
    // input for latin1.
352
16.3k
    source = fdp.ConsumeRandomLengthString(kMaxStringSize);
353
16.3k
    bool validlatin1 = true; // has to be
354
16.3k
    if (validlatin1) {
355
      // We need a buffer of size where to write the UTF-8 words.
356
16.3k
      size_t expected_utf8words =
357
16.3k
          e->utf8_length_from_latin1(source.c_str(), source.size());
358
16.3k
      std::unique_ptr<char[]> utf8_output{new char[expected_utf8words]};
359
16.3k
      size_t utf8words = e->convert_latin1_to_utf8(
360
16.3k
          source.c_str(), source.size(), utf8_output.get());
361
      // It wrote utf8words * sizeof(char) bytes.
362
16.3k
      bool validutf8 = e->validate_utf8(utf8_output.get(), utf8words);
363
16.3k
      if (!validutf8) {
364
0
        print_input(source, e);
365
0
        abort();
366
0
      }
367
      // convert it back:
368
      // We need a buffer of size where to write the latin1 words.
369
16.3k
      size_t expected_latin1words =
370
16.3k
          e->latin1_length_from_utf8(utf8_output.get(), utf8words);
371
16.3k
      std::unique_ptr<char[]> latin1_output{new char[expected_latin1words]};
372
      // convert to latin1
373
16.3k
      size_t latin1words = e->convert_utf8_to_latin1(
374
16.3k
          utf8_output.get(), utf8words, latin1_output.get());
375
383k
      for (size_t i = 0; i < source.size(); i++) {
376
367k
        if (latin1_output.get()[i] != (source.c_str())[i]) {
377
0
          print_input(source, e);
378
0
          abort();
379
0
        }
380
367k
      }
381
16.3k
    }
382
16.3k
    if (validlatin1) {
383
      // We need a buffer of size where to write the UTF-16 words.
384
16.3k
      size_t expected_utf16words = e->utf16_length_from_latin1(source.size());
385
16.3k
      std::unique_ptr<char16_t[]> utf16_output{
386
16.3k
          new char16_t[expected_utf16words]};
387
16.3k
      size_t utf16words = e->convert_latin1_to_utf16le(
388
16.3k
          source.c_str(), source.size(), utf16_output.get());
389
      // It wrote utf16words * sizeof(char16_t) bytes.
390
16.3k
      bool validutf16 = e->validate_utf16le(utf16_output.get(), utf16words);
391
16.3k
      if (!validutf16) {
392
0
        print_input(source, e);
393
0
        abort();
394
0
      }
395
      // convert it back:
396
      // We need a buffer of size where to write the latin1 words.
397
16.3k
      size_t expected_latin1words = e->latin1_length_from_utf16(utf16words);
398
16.3k
      std::unique_ptr<char[]> latin1_output{new char[expected_latin1words]};
399
      // convert to latin1
400
16.3k
      size_t latin1words = e->convert_utf16le_to_latin1(
401
16.3k
          utf16_output.get(), utf16words, latin1_output.get());
402
383k
      for (size_t i = 0; i < source.size(); i++) {
403
367k
        if (latin1_output.get()[i] != (source.c_str())[i]) {
404
0
          print_input(source, e);
405
0
          abort();
406
0
        }
407
367k
      }
408
16.3k
    }
409
16.3k
    if (validlatin1) {
410
      // We need a buffer of size where to write the UTF-16 words.
411
16.3k
      size_t expected_utf16words = e->utf16_length_from_latin1(source.size());
412
16.3k
      std::unique_ptr<char16_t[]> utf16_output{
413
16.3k
          new char16_t[expected_utf16words]};
414
16.3k
      size_t utf16words = e->convert_latin1_to_utf16be(
415
16.3k
          source.c_str(), source.size(), utf16_output.get());
416
      // It wrote utf16words * sizeof(char16_t) bytes.
417
16.3k
      bool validutf16 = e->validate_utf16be(utf16_output.get(), utf16words);
418
16.3k
      if (!validutf16) {
419
0
        print_input(source, e);
420
0
        abort();
421
0
      }
422
      // convert it back:
423
      // We need a buffer of size where to write the latin1 words.
424
16.3k
      size_t expected_latin1words = e->latin1_length_from_utf16(utf16words);
425
16.3k
      std::unique_ptr<char[]> latin1_output{new char[expected_latin1words]};
426
      // convert to latin1
427
16.3k
      size_t latin1words = e->convert_utf16be_to_latin1(
428
16.3k
          utf16_output.get(), utf16words, latin1_output.get());
429
383k
      for (size_t i = 0; i < source.size(); i++) {
430
367k
        if (latin1_output.get()[i] != (source.c_str())[i]) {
431
0
          print_input(source, e);
432
0
          abort();
433
0
        }
434
367k
      }
435
16.3k
    }
436
437
16.3k
    if (validlatin1) {
438
      // We need a buffer of size where to write the UTF-16 words.
439
16.3k
      size_t expected_utf32words = e->utf32_length_from_latin1(source.size());
440
16.3k
      std::unique_ptr<char32_t[]> utf32_output{
441
16.3k
          new char32_t[expected_utf32words]};
442
16.3k
      size_t utf32words = e->convert_latin1_to_utf32(
443
16.3k
          source.c_str(), source.size(), utf32_output.get());
444
      // It wrote utf16words * sizeof(char16_t) bytes.
445
16.3k
      bool validutf32 = e->validate_utf32(utf32_output.get(), utf32words);
446
16.3k
      if (!validutf32) {
447
0
        print_input(source, e);
448
0
        abort();
449
0
      }
450
      // convert it back:
451
      // We need a buffer of size where to write the latin1 words.
452
16.3k
      size_t expected_latin1words = e->latin1_length_from_utf32(utf32words);
453
16.3k
      std::unique_ptr<char[]> latin1_output{new char[expected_latin1words]};
454
      // convert to latin1
455
16.3k
      size_t latin1words = e->convert_utf32_to_latin1(
456
16.3k
          utf32_output.get(), utf32words, latin1_output.get());
457
383k
      for (size_t i = 0; i < source.size(); i++) {
458
367k
        if (latin1_output.get()[i] != (source.c_str())[i]) {
459
0
          print_input(source, e);
460
0
          abort();
461
0
        }
462
367k
      }
463
16.3k
    }
464
465
    /// Base64 tests. We begin by trying to decode the input, even if we
466
    /// expect it to fail.
467
16.3k
    {
468
16.3k
      size_t max_length_needed =
469
16.3k
          e->maximal_binary_length_from_base64(source.data(), source.size());
470
16.3k
      std::vector<char> back(max_length_needed);
471
16.3k
      simdutf::result r =
472
16.3k
          e->base64_to_binary(source.data(), source.size(), back.data());
473
16.3k
      if (r.error == simdutf::error_code::SUCCESS) {
474
        // We expect failure but if we succeed, then we should have a roundtrip.
475
14.9k
        back.resize(r.count);
476
14.9k
        std::vector<char> back2(e->base64_length_from_binary(back.size()));
477
14.9k
        size_t base64size =
478
14.9k
            e->binary_to_base64(back.data(), back.size(), back2.data());
479
14.9k
        back2.resize(base64size);
480
14.9k
        std::vector<char> back3(
481
14.9k
            e->maximal_binary_length_from_base64(back2.data(), back2.size()));
482
14.9k
        simdutf::result r2 =
483
14.9k
            e->base64_to_binary(back2.data(), back2.size(), back3.data());
484
14.9k
        if (r2.error != simdutf::error_code::SUCCESS) {
485
0
          print_input(source, e);
486
0
          return false;
487
0
        }
488
14.9k
        if (r2.count != back.size()) {
489
0
          print_input(source, e);
490
0
          return false;
491
0
        }
492
14.9k
        if (back3.size() != back.size()) {
493
0
          print_input(source, e);
494
0
          return false;
495
0
        }
496
14.9k
      }
497
16.3k
    }
498
499
    // Same as above, but we use the safe decoder version.
500
16.3k
    {
501
16.3k
      size_t max_length_needed =
502
16.3k
          e->maximal_binary_length_from_base64(source.data(), source.size());
503
16.3k
      std::vector<char> back(max_length_needed);
504
16.3k
      simdutf::result r = simdutf::base64_to_binary_safe(
505
16.3k
          source.data(), source.size(), back.data(), max_length_needed);
506
16.3k
      if (r.error == simdutf::error_code::SUCCESS) {
507
        // We expect failure but if we succeed, then we should have a roundtrip.
508
14.9k
        back.resize(max_length_needed);
509
14.9k
        std::vector<char> back2(e->base64_length_from_binary(back.size()));
510
14.9k
        size_t base64size =
511
14.9k
            e->binary_to_base64(back.data(), back.size(), back2.data());
512
14.9k
        back2.resize(base64size);
513
14.9k
        size_t max_length_needed2 =
514
14.9k
            e->maximal_binary_length_from_base64(back2.data(), back2.size());
515
14.9k
        std::vector<char> back3(max_length_needed2);
516
14.9k
        simdutf::result r2 = simdutf::base64_to_binary_safe(
517
14.9k
            back2.data(), back2.size(), back3.data(), max_length_needed2);
518
14.9k
        if (r2.error != simdutf::error_code::SUCCESS) {
519
0
          print_input(source, e);
520
0
          return false;
521
0
        }
522
14.9k
        if (max_length_needed != back.size()) {
523
0
          print_input(source, e);
524
0
          return false;
525
0
        }
526
14.9k
        if (back3.size() != back.size()) {
527
0
          print_input(source, e);
528
0
          return false;
529
0
        }
530
14.9k
      }
531
16.3k
    }
532
    /// Base64 tests. We encode the content as binary in base64 and we decode
533
    /// it, it should always succeed.
534
16.3k
    {
535
16.3k
      source = fdp.ConsumeRandomLengthString(kMaxStringSize);
536
16.3k
      std::vector<char> base64buffer(
537
16.3k
          e->base64_length_from_binary(source.size()));
538
16.3k
      size_t base64size = e->binary_to_base64(source.data(), source.size(),
539
16.3k
                                              base64buffer.data());
540
16.3k
      if (base64size != base64buffer.size()) {
541
0
        print_input(source, e);
542
0
        abort();
543
0
      }
544
16.3k
      std::vector<char> back(e->maximal_binary_length_from_base64(
545
16.3k
          base64buffer.data(), base64buffer.size()));
546
16.3k
      simdutf::result r = e->base64_to_binary(base64buffer.data(),
547
16.3k
                                              base64buffer.size(), back.data());
548
16.3k
      if (r.error != simdutf::error_code::SUCCESS) {
549
0
        print_input(source, e);
550
0
        abort();
551
0
      }
552
16.3k
      if (r.count != source.size()) {
553
0
        print_input(source, e);
554
0
        abort();
555
0
      }
556
327k
      for (size_t i = 0; i < source.size(); i++) {
557
311k
        if (back[i] != (source.c_str())[i]) {
558
0
          print_input(source, e);
559
0
          abort();
560
0
        }
561
311k
      }
562
16.3k
      size_t max_length = back.size();
563
16.3k
      r = simdutf::base64_to_binary_safe(
564
16.3k
          base64buffer.data(), base64buffer.size(), back.data(), max_length);
565
16.3k
      if (r.error != simdutf::error_code::SUCCESS) {
566
0
        printf("base64 round trip failed, error code %d\n", r.error);
567
0
        print_input(source, e);
568
0
        return false;
569
0
      }
570
16.3k
      if (max_length != source.size()) {
571
0
        printf("base64 safe round trip failed, not the same size %zu %zu\n",
572
0
               max_length, source.size());
573
0
        print_input(source, e);
574
0
        return false;
575
0
      }
576
327k
      for (size_t i = 0; i < source.size(); i++) {
577
311k
        if (back[i] != (source.c_str())[i]) {
578
0
          printf("base64 round trip failed, same size, different content\n");
579
0
          print_input(source, e);
580
0
          return false;
581
0
        }
582
311k
      }
583
16.3k
    }
584
585
16.3k
  } // for (auto &e : simdutf::get_available_implementations()) {
586
587
5.45k
  return 0;
588
5.45k
} // extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {