539932f13de9d58cfd33f2ff4ba9b271abe74521
[platform/upstream/libjpeg-turbo.git] / fuzz / compress.cc
1 /*
2  * Copyright (C)2021 D. R. Commander.  All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * - Redistributions of source code must retain the above copyright notice,
8  *   this list of conditions and the following disclaimer.
9  * - Redistributions in binary form must reproduce the above copyright notice,
10  *   this list of conditions and the following disclaimer in the documentation
11  *   and/or other materials provided with the distribution.
12  * - Neither the name of the libjpeg-turbo Project nor the names of its
13  *   contributors may be used to endorse or promote products derived from this
14  *   software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include <turbojpeg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <stdint.h>
33 #include <string.h>
34 #include <unistd.h>
35
36
37 #define NUMTESTS  7
38 /* Private flag that triggers different TurboJPEG API behavior when fuzzing */
39 #define TJFLAG_FUZZING  (1 << 30)
40
41
42 struct test {
43   enum TJPF pf;
44   enum TJSAMP subsamp;
45   int quality;
46 };
47
48
49 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
50 {
51   tjhandle handle = NULL;
52   unsigned char *srcBuf = NULL, *dstBuf = NULL;
53   int width = 0, height = 0, fd = -1, i, ti;
54   char filename[FILENAME_MAX] = { 0 };
55   struct test tests[NUMTESTS] = {
56     { TJPF_RGB, TJSAMP_444, 100 },
57     { TJPF_BGR, TJSAMP_422, 90 },
58     { TJPF_RGBX, TJSAMP_420, 80 },
59     { TJPF_BGRA, TJSAMP_411, 70 },
60     { TJPF_XRGB, TJSAMP_GRAY, 60 },
61     { TJPF_GRAY, TJSAMP_GRAY, 50 },
62     { TJPF_CMYK, TJSAMP_440, 40 }
63   };
64 #if defined(__has_feature) && __has_feature(memory_sanitizer)
65   char env[18] = "JSIMD_FORCENONE=1";
66
67   /* The libjpeg-turbo SIMD extensions produce false positives with
68      MemorySanitizer. */
69   putenv(env);
70 #endif
71
72   snprintf(filename, FILENAME_MAX, "/tmp/libjpeg-turbo_compress_fuzz.XXXXXX");
73   if ((fd = mkstemp(filename)) < 0 || write(fd, data, size) < 0)
74     goto bailout;
75
76   if ((handle = tjInitCompress()) == NULL)
77     goto bailout;
78
79   for (ti = 0; ti < NUMTESTS; ti++) {
80     int flags = TJFLAG_FUZZING, sum = 0, pf = tests[ti].pf;
81     unsigned long dstSize = 0, maxBufSize;
82
83     /* Test non-default compression options on specific iterations. */
84     if (ti == 0)
85       flags |= TJFLAG_BOTTOMUP | TJFLAG_ACCURATEDCT;
86     else if (ti == 1)
87       flags |= TJFLAG_PROGRESSIVE;
88     if (ti != 2)
89       flags |= TJFLAG_NOREALLOC;
90
91     /* tjLoadImage() refuses to load images larger than 1 Megapixel when
92        FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION is defined (yes, that's a dirty
93        hack), so we don't need to check the width and height here. */
94     if ((srcBuf = tjLoadImage(filename, &width, 1, &height, &pf,
95                               flags)) == NULL)
96       continue;
97
98     maxBufSize = tjBufSize(width, height, tests[ti].subsamp);
99     if (flags & TJFLAG_NOREALLOC) {
100       if ((dstBuf = (unsigned char *)malloc(maxBufSize)) == NULL)
101         goto bailout;
102     } else
103       dstBuf = NULL;
104
105     if (tjCompress2(handle, srcBuf, width, 0, height, pf, &dstBuf, &dstSize,
106                     tests[ti].subsamp, tests[ti].quality, flags) == 0) {
107       /* Touch all of the output pixels in order to catch uninitialized reads
108          when using MemorySanitizer. */
109       for (i = 0; i < dstSize; i++)
110         sum += dstBuf[i];
111     }
112
113     free(dstBuf);
114     dstBuf = NULL;
115     tjFree(srcBuf);
116     srcBuf = NULL;
117
118     /* Prevent the code above from being optimized out.  This test should never
119        be true, but the compiler doesn't know that. */
120     if (sum > 255 * maxBufSize)
121       goto bailout;
122   }
123
124 bailout:
125   free(dstBuf);
126   tjFree(srcBuf);
127   if (fd >= 0) {
128     close(fd);
129     if (strlen(filename) > 0) unlink(filename);
130   }
131   if (handle) tjDestroy(handle);
132   return 0;
133 }