/src/libpng/contrib/oss-fuzz/libpng_read_fuzzer.cc
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | // libpng_read_fuzzer.cc  | 
2  |  | // Copyright 2017-2018 Glenn Randers-Pehrson  | 
3  |  | // Copyright 2015 The Chromium Authors. All rights reserved.  | 
4  |  | // Use of this source code is governed by a BSD-style license that may  | 
5  |  | // be found in the LICENSE file https://cs.chromium.org/chromium/src/LICENSE  | 
6  |  |  | 
7  |  | // The modifications in 2017 by Glenn Randers-Pehrson include  | 
8  |  | // 1. addition of a PNG_CLEANUP macro,  | 
9  |  | // 2. setting the option to ignore ADLER32 checksums,  | 
10  |  | // 3. adding "#include <string.h>" which is needed on some platforms  | 
11  |  | //    to provide memcpy().  | 
12  |  | // 4. adding read_end_info() and creating an end_info structure.  | 
13  |  | // 5. adding calls to png_set_*() transforms commonly used by browsers.  | 
14  |  |  | 
15  |  | #include <stddef.h>  | 
16  |  | #include <stdint.h>  | 
17  |  | #include <stdlib.h>  | 
18  |  | #include <string.h>  | 
19  |  |  | 
20  |  | #include <vector>  | 
21  |  |  | 
22  |  | #define PNG_INTERNAL  | 
23  |  | #include "png.h"  | 
24  |  |  | 
25  |  | #define PNG_CLEANUP \  | 
26  | 26.0k  |   if(png_handler.png_ptr) \  | 
27  | 26.0k  |   { \ | 
28  | 26.0k  |     if (png_handler.row_ptr) \  | 
29  | 26.0k  |       png_free(png_handler.png_ptr, png_handler.row_ptr); \  | 
30  | 26.0k  |     if (png_handler.end_info_ptr) \  | 
31  | 26.0k  |       png_destroy_read_struct(&png_handler.png_ptr, &png_handler.info_ptr,\  | 
32  | 26.0k  |         &png_handler.end_info_ptr); \  | 
33  | 26.0k  |     else if (png_handler.info_ptr) \  | 
34  | 0  |       png_destroy_read_struct(&png_handler.png_ptr, &png_handler.info_ptr,\  | 
35  | 0  |         nullptr); \  | 
36  | 0  |     else \  | 
37  | 0  |       png_destroy_read_struct(&png_handler.png_ptr, nullptr, nullptr); \  | 
38  | 26.0k  |     png_handler.png_ptr = nullptr; \  | 
39  | 26.0k  |     png_handler.row_ptr = nullptr; \  | 
40  | 26.0k  |     png_handler.info_ptr = nullptr; \  | 
41  | 26.0k  |     png_handler.end_info_ptr = nullptr; \  | 
42  | 26.0k  |   }  | 
43  |  |  | 
44  |  | struct BufState { | 
45  |  |   const uint8_t* data;  | 
46  |  |   size_t bytes_left;  | 
47  |  | };  | 
48  |  |  | 
49  |  | struct PngObjectHandler { | 
50  |  |   png_infop info_ptr = nullptr;  | 
51  |  |   png_structp png_ptr = nullptr;  | 
52  |  |   png_infop end_info_ptr = nullptr;  | 
53  |  |   png_voidp row_ptr = nullptr;  | 
54  |  |   BufState* buf_state = nullptr;  | 
55  |  |  | 
56  | 26.0k  |   ~PngObjectHandler() { | 
57  | 26.0k  |     if (row_ptr)  | 
58  | 0  |       png_free(png_ptr, row_ptr);  | 
59  | 26.0k  |     if (end_info_ptr)  | 
60  | 0  |       png_destroy_read_struct(&png_ptr, &info_ptr, &end_info_ptr);  | 
61  | 26.0k  |     else if (info_ptr)  | 
62  | 0  |       png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);  | 
63  | 26.0k  |     else  | 
64  | 26.0k  |       png_destroy_read_struct(&png_ptr, nullptr, nullptr);  | 
65  | 26.0k  |     delete buf_state;  | 
66  | 26.0k  |   }  | 
67  |  | };  | 
68  |  |  | 
69  | 561k  | void user_read_data(png_structp png_ptr, png_bytep data, size_t length) { | 
70  | 561k  |   BufState* buf_state = static_cast<BufState*>(png_get_io_ptr(png_ptr));  | 
71  | 561k  |   if (length > buf_state->bytes_left) { | 
72  | 4.67k  |     png_error(png_ptr, "read error");  | 
73  | 4.67k  |   }  | 
74  | 556k  |   memcpy(data, buf_state->data, length);  | 
75  | 556k  |   buf_state->bytes_left -= length;  | 
76  | 556k  |   buf_state->data += length;  | 
77  | 556k  | }  | 
78  |  |  | 
79  | 178k  | void* limited_malloc(png_structp, png_alloc_size_t size) { | 
80  |  |   // libpng may allocate large amounts of memory that the fuzzer reports as  | 
81  |  |   // an error. In order to silence these errors, make libpng fail when trying  | 
82  |  |   // to allocate a large amount. This allocator used to be in the Chromium  | 
83  |  |   // version of this fuzzer.  | 
84  |  |   // This number is chosen to match the default png_user_chunk_malloc_max.  | 
85  | 178k  |   if (size > 8000000)  | 
86  | 2  |     return nullptr;  | 
87  |  |  | 
88  | 178k  |   return malloc(size);  | 
89  | 178k  | }  | 
90  |  |  | 
91  | 256k  | void default_free(png_structp, png_voidp ptr) { | 
92  | 256k  |   return free(ptr);  | 
93  | 256k  | }  | 
94  |  |  | 
95  |  | static const int kPngHeaderSize = 8;  | 
96  |  |  | 
97  |  | // Entry point for LibFuzzer.  | 
98  |  | // Roughly follows the libpng book example:  | 
99  |  | // http://www.libpng.org/pub/png/book/chapter13.html  | 
100  | 26.0k  | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { | 
101  | 26.0k  |   if (size < kPngHeaderSize) { | 
102  | 4  |     return 0;  | 
103  | 4  |   }  | 
104  |  |  | 
105  | 26.0k  |   std::vector<unsigned char> v(data, data + size);  | 
106  | 26.0k  |   if (png_sig_cmp(v.data(), 0, kPngHeaderSize)) { | 
107  |  |     // not a PNG.  | 
108  | 72  |     return 0;  | 
109  | 72  |   }  | 
110  |  |  | 
111  | 26.0k  |   PngObjectHandler png_handler;  | 
112  | 26.0k  |   png_handler.png_ptr = nullptr;  | 
113  | 26.0k  |   png_handler.row_ptr = nullptr;  | 
114  | 26.0k  |   png_handler.info_ptr = nullptr;  | 
115  | 26.0k  |   png_handler.end_info_ptr = nullptr;  | 
116  |  |  | 
117  | 26.0k  |   png_handler.png_ptr = png_create_read_struct  | 
118  | 26.0k  |     (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);  | 
119  | 26.0k  |   if (!png_handler.png_ptr) { | 
120  | 0  |     return 0;  | 
121  | 0  |   }  | 
122  |  |  | 
123  | 26.0k  |   png_handler.info_ptr = png_create_info_struct(png_handler.png_ptr);  | 
124  | 26.0k  |   if (!png_handler.info_ptr) { | 
125  | 0  |     PNG_CLEANUP  | 
126  | 0  |     return 0;  | 
127  | 0  |   }  | 
128  |  |  | 
129  | 26.0k  |   png_handler.end_info_ptr = png_create_info_struct(png_handler.png_ptr);  | 
130  | 26.0k  |   if (!png_handler.end_info_ptr) { | 
131  | 0  |     PNG_CLEANUP  | 
132  | 0  |     return 0;  | 
133  | 0  |   }  | 
134  |  |  | 
135  |  |   // Use a custom allocator that fails for large allocations to avoid OOM.  | 
136  | 26.0k  |   png_set_mem_fn(png_handler.png_ptr, nullptr, limited_malloc, default_free);  | 
137  |  |  | 
138  | 26.0k  |   png_set_crc_action(png_handler.png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);  | 
139  |  | #ifdef PNG_IGNORE_ADLER32  | 
140  |  |   png_set_option(png_handler.png_ptr, PNG_IGNORE_ADLER32, PNG_OPTION_ON);  | 
141  |  | #endif  | 
142  |  |  | 
143  |  |   // Setting up reading from buffer.  | 
144  | 26.0k  |   png_handler.buf_state = new BufState();  | 
145  | 26.0k  |   png_handler.buf_state->data = data + kPngHeaderSize;  | 
146  | 26.0k  |   png_handler.buf_state->bytes_left = size - kPngHeaderSize;  | 
147  | 26.0k  |   png_set_read_fn(png_handler.png_ptr, png_handler.buf_state, user_read_data);  | 
148  | 26.0k  |   png_set_sig_bytes(png_handler.png_ptr, kPngHeaderSize);  | 
149  |  |  | 
150  | 26.0k  |   if (setjmp(png_jmpbuf(png_handler.png_ptr))) { | 
151  | 14.8k  |     PNG_CLEANUP  | 
152  | 14.8k  |     return 0;  | 
153  | 14.8k  |   }  | 
154  |  |  | 
155  |  |   // Reading.  | 
156  | 11.1k  |   png_read_info(png_handler.png_ptr, png_handler.info_ptr);  | 
157  |  |  | 
158  |  |   // reset error handler to put png_deleter into scope.  | 
159  | 11.1k  |   if (setjmp(png_jmpbuf(png_handler.png_ptr))) { | 
160  | 2.76k  |     PNG_CLEANUP  | 
161  | 2.76k  |     return 0;  | 
162  | 2.76k  |   }  | 
163  |  |  | 
164  | 8.42k  |   png_uint_32 width, height;  | 
165  | 8.42k  |   int bit_depth, color_type, interlace_type, compression_type;  | 
166  | 8.42k  |   int filter_type;  | 
167  |  |  | 
168  | 8.42k  |   if (!png_get_IHDR(png_handler.png_ptr, png_handler.info_ptr, &width,  | 
169  | 8.42k  |                     &height, &bit_depth, &color_type, &interlace_type,  | 
170  | 8.42k  |                     &compression_type, &filter_type)) { | 
171  | 0  |     PNG_CLEANUP  | 
172  | 0  |     return 0;  | 
173  | 0  |   }  | 
174  |  |  | 
175  |  |   // This is going to be too slow.  | 
176  | 11.1k  |   if (width && height > 100000000 / width) { | 
177  | 21  |     PNG_CLEANUP  | 
178  | 21  |     return 0;  | 
179  | 21  |   }  | 
180  |  |  | 
181  |  |   // Set several transforms that browsers typically use:  | 
182  | 8.40k  |   png_set_gray_to_rgb(png_handler.png_ptr);  | 
183  | 8.40k  |   png_set_expand(png_handler.png_ptr);  | 
184  | 8.40k  |   png_set_packing(png_handler.png_ptr);  | 
185  | 8.40k  |   png_set_scale_16(png_handler.png_ptr);  | 
186  | 8.40k  |   png_set_tRNS_to_alpha(png_handler.png_ptr);  | 
187  |  |  | 
188  | 8.40k  |   int passes = png_set_interlace_handling(png_handler.png_ptr);  | 
189  |  |  | 
190  | 8.40k  |   png_read_update_info(png_handler.png_ptr, png_handler.info_ptr);  | 
191  |  |  | 
192  | 8.40k  |   png_handler.row_ptr = png_malloc(  | 
193  | 8.40k  |       png_handler.png_ptr, png_get_rowbytes(png_handler.png_ptr,  | 
194  | 8.40k  |                                             png_handler.info_ptr));  | 
195  |  |  | 
196  | 49.3k  |   for (int pass = 0; pass < passes; ++pass) { | 
197  | 853k  |     for (png_uint_32 y = 0; y < height; ++y) { | 
198  | 812k  |       png_read_row(png_handler.png_ptr,  | 
199  | 812k  |                    static_cast<png_bytep>(png_handler.row_ptr), nullptr);  | 
200  | 812k  |     }  | 
201  | 40.9k  |   }  | 
202  |  |  | 
203  | 8.40k  |   png_read_end(png_handler.png_ptr, png_handler.end_info_ptr);  | 
204  |  |  | 
205  | 8.40k  |   PNG_CLEANUP  | 
206  |  |  | 
207  | 8.40k  | #ifdef PNG_SIMPLIFIED_READ_SUPPORTED  | 
208  |  |   // Simplified READ API  | 
209  | 8.40k  |   png_image image;  | 
210  | 8.40k  |   memset(&image, 0, (sizeof image));  | 
211  | 8.40k  |   image.version = PNG_IMAGE_VERSION;  | 
212  |  |  | 
213  | 8.40k  |   if (!png_image_begin_read_from_memory(&image, data, size)) { | 
214  | 11  |     return 0;  | 
215  | 11  |   }  | 
216  |  |  | 
217  | 8.39k  |   image.format = PNG_FORMAT_RGBA;  | 
218  | 8.39k  |   std::vector<png_byte> buffer(PNG_IMAGE_SIZE(image));  | 
219  | 8.39k  |   png_image_finish_read(&image, NULL, buffer.data(), 0, NULL);  | 
220  | 8.39k  | #endif  | 
221  |  |  | 
222  | 8.39k  |   return 0;  | 
223  | 8.40k  | } Line  | Count  | Source  |  100  | 18.3k  | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |  101  | 18.3k  |   if (size < kPngHeaderSize) { |  102  | 0  |     return 0;  |  103  | 0  |   }  |  104  |  |  |  105  | 18.3k  |   std::vector<unsigned char> v(data, data + size);  |  106  | 18.3k  |   if (png_sig_cmp(v.data(), 0, kPngHeaderSize)) { |  107  |  |     // not a PNG.  |  108  | 0  |     return 0;  |  109  | 0  |   }  |  110  |  |  |  111  | 18.3k  |   PngObjectHandler png_handler;  |  112  | 18.3k  |   png_handler.png_ptr = nullptr;  |  113  | 18.3k  |   png_handler.row_ptr = nullptr;  |  114  | 18.3k  |   png_handler.info_ptr = nullptr;  |  115  | 18.3k  |   png_handler.end_info_ptr = nullptr;  |  116  |  |  |  117  | 18.3k  |   png_handler.png_ptr = png_create_read_struct  |  118  | 18.3k  |     (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);  |  119  | 18.3k  |   if (!png_handler.png_ptr) { |  120  | 0  |     return 0;  |  121  | 0  |   }  |  122  |  |  |  123  | 18.3k  |   png_handler.info_ptr = png_create_info_struct(png_handler.png_ptr);  |  124  | 18.3k  |   if (!png_handler.info_ptr) { |  125  | 0  |     PNG_CLEANUP  |  126  | 0  |     return 0;  |  127  | 0  |   }  |  128  |  |  |  129  | 18.3k  |   png_handler.end_info_ptr = png_create_info_struct(png_handler.png_ptr);  |  130  | 18.3k  |   if (!png_handler.end_info_ptr) { |  131  | 0  |     PNG_CLEANUP  |  132  | 0  |     return 0;  |  133  | 0  |   }  |  134  |  |  |  135  |  |   // Use a custom allocator that fails for large allocations to avoid OOM.  |  136  | 18.3k  |   png_set_mem_fn(png_handler.png_ptr, nullptr, limited_malloc, default_free);  |  137  |  |  |  138  | 18.3k  |   png_set_crc_action(png_handler.png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);  |  139  |  | #ifdef PNG_IGNORE_ADLER32  |  140  |  |   png_set_option(png_handler.png_ptr, PNG_IGNORE_ADLER32, PNG_OPTION_ON);  |  141  |  | #endif  |  142  |  |  |  143  |  |   // Setting up reading from buffer.  |  144  | 18.3k  |   png_handler.buf_state = new BufState();  |  145  | 18.3k  |   png_handler.buf_state->data = data + kPngHeaderSize;  |  146  | 18.3k  |   png_handler.buf_state->bytes_left = size - kPngHeaderSize;  |  147  | 18.3k  |   png_set_read_fn(png_handler.png_ptr, png_handler.buf_state, user_read_data);  |  148  | 18.3k  |   png_set_sig_bytes(png_handler.png_ptr, kPngHeaderSize);  |  149  |  |  |  150  | 18.3k  |   if (setjmp(png_jmpbuf(png_handler.png_ptr))) { |  151  | 10.2k  |     PNG_CLEANUP  |  152  | 10.2k  |     return 0;  |  153  | 10.2k  |   }  |  154  |  |  |  155  |  |   // Reading.  |  156  | 8.07k  |   png_read_info(png_handler.png_ptr, png_handler.info_ptr);  |  157  |  |  |  158  |  |   // reset error handler to put png_deleter into scope.  |  159  | 8.07k  |   if (setjmp(png_jmpbuf(png_handler.png_ptr))) { |  160  | 1.65k  |     PNG_CLEANUP  |  161  | 1.65k  |     return 0;  |  162  | 1.65k  |   }  |  163  |  |  |  164  | 6.42k  |   png_uint_32 width, height;  |  165  | 6.42k  |   int bit_depth, color_type, interlace_type, compression_type;  |  166  | 6.42k  |   int filter_type;  |  167  |  |  |  168  | 6.42k  |   if (!png_get_IHDR(png_handler.png_ptr, png_handler.info_ptr, &width,  |  169  | 6.42k  |                     &height, &bit_depth, &color_type, &interlace_type,  |  170  | 6.42k  |                     &compression_type, &filter_type)) { |  171  | 0  |     PNG_CLEANUP  |  172  | 0  |     return 0;  |  173  | 0  |   }  |  174  |  |  |  175  |  |   // This is going to be too slow.  |  176  | 8.07k  |   if (width && height > 100000000 / width) { |  177  | 0  |     PNG_CLEANUP  |  178  | 0  |     return 0;  |  179  | 0  |   }  |  180  |  |  |  181  |  |   // Set several transforms that browsers typically use:  |  182  | 6.42k  |   png_set_gray_to_rgb(png_handler.png_ptr);  |  183  | 6.42k  |   png_set_expand(png_handler.png_ptr);  |  184  | 6.42k  |   png_set_packing(png_handler.png_ptr);  |  185  | 6.42k  |   png_set_scale_16(png_handler.png_ptr);  |  186  | 6.42k  |   png_set_tRNS_to_alpha(png_handler.png_ptr);  |  187  |  |  |  188  | 6.42k  |   int passes = png_set_interlace_handling(png_handler.png_ptr);  |  189  |  |  |  190  | 6.42k  |   png_read_update_info(png_handler.png_ptr, png_handler.info_ptr);  |  191  |  |  |  192  | 6.42k  |   png_handler.row_ptr = png_malloc(  |  193  | 6.42k  |       png_handler.png_ptr, png_get_rowbytes(png_handler.png_ptr,  |  194  | 6.42k  |                                             png_handler.info_ptr));  |  195  |  |  |  196  | 39.4k  |   for (int pass = 0; pass < passes; ++pass) { |  197  | 239k  |     for (png_uint_32 y = 0; y < height; ++y) { |  198  | 206k  |       png_read_row(png_handler.png_ptr,  |  199  | 206k  |                    static_cast<png_bytep>(png_handler.row_ptr), nullptr);  |  200  | 206k  |     }  |  201  | 33.0k  |   }  |  202  |  |  |  203  | 6.42k  |   png_read_end(png_handler.png_ptr, png_handler.end_info_ptr);  |  204  |  |  |  205  | 6.42k  |   PNG_CLEANUP  |  206  |  |  |  207  | 6.42k  | #ifdef PNG_SIMPLIFIED_READ_SUPPORTED  |  208  |  |   // Simplified READ API  |  209  | 6.42k  |   png_image image;  |  210  | 6.42k  |   memset(&image, 0, (sizeof image));  |  211  | 6.42k  |   image.version = PNG_IMAGE_VERSION;  |  212  |  |  |  213  | 6.42k  |   if (!png_image_begin_read_from_memory(&image, data, size)) { |  214  | 0  |     return 0;  |  215  | 0  |   }  |  216  |  |  |  217  | 6.42k  |   image.format = PNG_FORMAT_RGBA;  |  218  | 6.42k  |   std::vector<png_byte> buffer(PNG_IMAGE_SIZE(image));  |  219  | 6.42k  |   png_image_finish_read(&image, NULL, buffer.data(), 0, NULL);  |  220  | 6.42k  | #endif  |  221  |  |  |  222  | 6.42k  |   return 0;  |  223  | 6.42k  | }  |  
 Line  | Count  | Source  |  100  | 7.73k  | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |  101  | 7.73k  |   if (size < kPngHeaderSize) { |  102  | 4  |     return 0;  |  103  | 4  |   }  |  104  |  |  |  105  | 7.72k  |   std::vector<unsigned char> v(data, data + size);  |  106  | 7.72k  |   if (png_sig_cmp(v.data(), 0, kPngHeaderSize)) { |  107  |  |     // not a PNG.  |  108  | 72  |     return 0;  |  109  | 72  |   }  |  110  |  |  |  111  | 7.65k  |   PngObjectHandler png_handler;  |  112  | 7.65k  |   png_handler.png_ptr = nullptr;  |  113  | 7.65k  |   png_handler.row_ptr = nullptr;  |  114  | 7.65k  |   png_handler.info_ptr = nullptr;  |  115  | 7.65k  |   png_handler.end_info_ptr = nullptr;  |  116  |  |  |  117  | 7.65k  |   png_handler.png_ptr = png_create_read_struct  |  118  | 7.65k  |     (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);  |  119  | 7.65k  |   if (!png_handler.png_ptr) { |  120  | 0  |     return 0;  |  121  | 0  |   }  |  122  |  |  |  123  | 7.65k  |   png_handler.info_ptr = png_create_info_struct(png_handler.png_ptr);  |  124  | 7.65k  |   if (!png_handler.info_ptr) { |  125  | 0  |     PNG_CLEANUP  |  126  | 0  |     return 0;  |  127  | 0  |   }  |  128  |  |  |  129  | 7.65k  |   png_handler.end_info_ptr = png_create_info_struct(png_handler.png_ptr);  |  130  | 7.65k  |   if (!png_handler.end_info_ptr) { |  131  | 0  |     PNG_CLEANUP  |  132  | 0  |     return 0;  |  133  | 0  |   }  |  134  |  |  |  135  |  |   // Use a custom allocator that fails for large allocations to avoid OOM.  |  136  | 7.65k  |   png_set_mem_fn(png_handler.png_ptr, nullptr, limited_malloc, default_free);  |  137  |  |  |  138  | 7.65k  |   png_set_crc_action(png_handler.png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);  |  139  |  | #ifdef PNG_IGNORE_ADLER32  |  140  |  |   png_set_option(png_handler.png_ptr, PNG_IGNORE_ADLER32, PNG_OPTION_ON);  |  141  |  | #endif  |  142  |  |  |  143  |  |   // Setting up reading from buffer.  |  144  | 7.65k  |   png_handler.buf_state = new BufState();  |  145  | 7.65k  |   png_handler.buf_state->data = data + kPngHeaderSize;  |  146  | 7.65k  |   png_handler.buf_state->bytes_left = size - kPngHeaderSize;  |  147  | 7.65k  |   png_set_read_fn(png_handler.png_ptr, png_handler.buf_state, user_read_data);  |  148  | 7.65k  |   png_set_sig_bytes(png_handler.png_ptr, kPngHeaderSize);  |  149  |  |  |  150  | 7.65k  |   if (setjmp(png_jmpbuf(png_handler.png_ptr))) { |  151  | 4.53k  |     PNG_CLEANUP  |  152  | 4.53k  |     return 0;  |  153  | 4.53k  |   }  |  154  |  |  |  155  |  |   // Reading.  |  156  | 3.11k  |   png_read_info(png_handler.png_ptr, png_handler.info_ptr);  |  157  |  |  |  158  |  |   // reset error handler to put png_deleter into scope.  |  159  | 3.11k  |   if (setjmp(png_jmpbuf(png_handler.png_ptr))) { |  160  | 1.11k  |     PNG_CLEANUP  |  161  | 1.11k  |     return 0;  |  162  | 1.11k  |   }  |  163  |  |  |  164  | 2.00k  |   png_uint_32 width, height;  |  165  | 2.00k  |   int bit_depth, color_type, interlace_type, compression_type;  |  166  | 2.00k  |   int filter_type;  |  167  |  |  |  168  | 2.00k  |   if (!png_get_IHDR(png_handler.png_ptr, png_handler.info_ptr, &width,  |  169  | 2.00k  |                     &height, &bit_depth, &color_type, &interlace_type,  |  170  | 2.00k  |                     &compression_type, &filter_type)) { |  171  | 0  |     PNG_CLEANUP  |  172  | 0  |     return 0;  |  173  | 0  |   }  |  174  |  |  |  175  |  |   // This is going to be too slow.  |  176  | 3.11k  |   if (width && height > 100000000 / width) { |  177  | 21  |     PNG_CLEANUP  |  178  | 21  |     return 0;  |  179  | 21  |   }  |  180  |  |  |  181  |  |   // Set several transforms that browsers typically use:  |  182  | 1.98k  |   png_set_gray_to_rgb(png_handler.png_ptr);  |  183  | 1.98k  |   png_set_expand(png_handler.png_ptr);  |  184  | 1.98k  |   png_set_packing(png_handler.png_ptr);  |  185  | 1.98k  |   png_set_scale_16(png_handler.png_ptr);  |  186  | 1.98k  |   png_set_tRNS_to_alpha(png_handler.png_ptr);  |  187  |  |  |  188  | 1.98k  |   int passes = png_set_interlace_handling(png_handler.png_ptr);  |  189  |  |  |  190  | 1.98k  |   png_read_update_info(png_handler.png_ptr, png_handler.info_ptr);  |  191  |  |  |  192  | 1.98k  |   png_handler.row_ptr = png_malloc(  |  193  | 1.98k  |       png_handler.png_ptr, png_get_rowbytes(png_handler.png_ptr,  |  194  | 1.98k  |                                             png_handler.info_ptr));  |  195  |  |  |  196  | 9.88k  |   for (int pass = 0; pass < passes; ++pass) { |  197  | 614k  |     for (png_uint_32 y = 0; y < height; ++y) { |  198  | 606k  |       png_read_row(png_handler.png_ptr,  |  199  | 606k  |                    static_cast<png_bytep>(png_handler.row_ptr), nullptr);  |  200  | 606k  |     }  |  201  | 7.90k  |   }  |  202  |  |  |  203  | 1.98k  |   png_read_end(png_handler.png_ptr, png_handler.end_info_ptr);  |  204  |  |  |  205  | 1.98k  |   PNG_CLEANUP  |  206  |  |  |  207  | 1.98k  | #ifdef PNG_SIMPLIFIED_READ_SUPPORTED  |  208  |  |   // Simplified READ API  |  209  | 1.98k  |   png_image image;  |  210  | 1.98k  |   memset(&image, 0, (sizeof image));  |  211  | 1.98k  |   image.version = PNG_IMAGE_VERSION;  |  212  |  |  |  213  | 1.98k  |   if (!png_image_begin_read_from_memory(&image, data, size)) { |  214  | 11  |     return 0;  |  215  | 11  |   }  |  216  |  |  |  217  | 1.97k  |   image.format = PNG_FORMAT_RGBA;  |  218  | 1.97k  |   std::vector<png_byte> buffer(PNG_IMAGE_SIZE(image));  |  219  | 1.97k  |   png_image_finish_read(&image, NULL, buffer.data(), 0, NULL);  |  220  | 1.97k  | #endif  |  221  |  |  |  222  | 1.97k  |   return 0;  |  223  | 1.98k  | }  |  
  |