Bug Summary

File:root/firefox-clang/media/libjpeg/src/jmemmgr.c
Warning:line 401, column 17
Access to field 'next' results in a dereference of a null pointer (loaded from variable 'hdr_ptr')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name jmemmgr.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/media/libjpeg -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/media/libjpeg -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_WITH_SIMD=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/media/libjpeg -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/media/libjpeg -I /root/firefox-clang/media/libjpeg -I /root/firefox-clang/media/libjpeg/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=tautological-type-limit-compare -Wno-range-loop-analysis -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-unknown-warning-option -Wno-character-conversion -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c /root/firefox-clang/media/libjpeg/src/jmemmgr.c
1/*
2 * jmemmgr.c
3 *
4 * This file was part of the Independent JPEG Group's software:
5 * Copyright (C) 1991-1997, Thomas G. Lane.
6 * libjpeg-turbo Modifications:
7 * Copyright (C) 2016, 2021-2022, 2024, D. R. Commander.
8 * For conditions of distribution and use, see the accompanying README.ijg
9 * file.
10 *
11 * This file contains the JPEG system-independent memory management
12 * routines. This code is usable across a wide variety of machines; most
13 * of the system dependencies have been isolated in a separate file.
14 * The major functions provided here are:
15 * * pool-based allocation and freeing of memory;
16 * * policy decisions about how to divide available memory among the
17 * virtual arrays;
18 * * control logic for swapping virtual arrays between main memory and
19 * backing storage.
20 * The separate system-dependent file provides the actual backing-storage
21 * access code, and it contains the policy decision about how much total
22 * main memory to use.
23 * This file is system-dependent in the sense that some of its functions
24 * are unnecessary in some systems. For example, if there is enough virtual
25 * memory so that backing storage will never be used, much of the virtual
26 * array control logic could be removed. (Of course, if you have that much
27 * memory then you shouldn't care about a little bit of unused code...)
28 */
29
30#define JPEG_INTERNALS
31#define AM_MEMORY_MANAGER /* we define jvirt_Xarray_control structs */
32#include "jinclude.h"
33#include "jpeglib.h"
34#include "jmemsys.h" /* import the system-dependent declarations */
35#if !defined(_MSC_VER) || _MSC_VER > 1600
36#include <stdint.h>
37#endif
38#include <limits.h>
39
40
41LOCAL(size_t)static size_t
42round_up_pow2(size_t a, size_t b)
43/* a rounded up to the next multiple of b, i.e. ceil(a/b)*b */
44/* Assumes a >= 0, b > 0, and b is a power of 2 */
45{
46 return ((a + b - 1) & (~(b - 1)));
47}
48
49
50/*
51 * Some important notes:
52 * The allocation routines provided here must never return NULL.
53 * They should exit to error_exit if unsuccessful.
54 *
55 * It's not a good idea to try to merge the sarray and barray routines,
56 * even though they are textually almost the same, because samples are
57 * usually stored as bytes while coefficients are shorts or ints. Thus,
58 * in machines where byte pointers have a different representation from
59 * word pointers, the resulting machine code could not be the same.
60 */
61
62
63/*
64 * Many machines require storage alignment: longs must start on 4-byte
65 * boundaries, doubles on 8-byte boundaries, etc. On such machines, malloc()
66 * always returns pointers that are multiples of the worst-case alignment
67 * requirement, and we had better do so too.
68 * There isn't any really portable way to determine the worst-case alignment
69 * requirement. This module assumes that the alignment requirement is
70 * multiples of ALIGN_SIZE.
71 * By default, we define ALIGN_SIZE as the maximum of sizeof(double) and
72 * sizeof(void *). This is necessary on some workstations (where doubles
73 * really do need 8-byte alignment) and will work fine on nearly everything.
74 * We use the maximum of sizeof(double) and sizeof(void *) since sizeof(double)
75 * may be insufficient, for example, on CHERI-enabled platforms with 16-byte
76 * pointers and a 16-byte alignment requirement. If your machine has lesser
77 * alignment needs, you can save a few bytes by making ALIGN_SIZE smaller.
78 * The only place I know of where this will NOT work is certain Macintosh
79 * 680x0 compilers that define double as a 10-byte IEEE extended float.
80 * Doing 10-byte alignment is counterproductive because longwords won't be
81 * aligned well. Put "#define ALIGN_SIZE 4" in jconfig.h if you have
82 * such a compiler.
83 */
84
85#ifndef ALIGN_SIZE32 /* so can override from jconfig.h */
86#ifndef WITH_SIMD1
87#define ALIGN_SIZE32 MAX(sizeof(void *), sizeof(double))((sizeof(void *)) > (sizeof(double)) ? (sizeof(void *)) : (
sizeof(double)))
88#else
89#define ALIGN_SIZE32 32 /* Most of the SIMD instructions we support require
90 16-byte (128-bit) alignment, but AVX2 requires
91 32-byte alignment. */
92#endif
93#endif
94
95/*
96 * We allocate objects from "pools", where each pool is gotten with a single
97 * request to jpeg_get_small() or jpeg_get_large(). There is no per-object
98 * overhead within a pool, except for alignment padding. Each pool has a
99 * header with a link to the next pool of the same class.
100 * Small and large pool headers are identical.
101 */
102
103typedef struct small_pool_struct *small_pool_ptr;
104
105typedef struct small_pool_struct {
106 small_pool_ptr next; /* next in list of pools */
107 size_t bytes_used; /* how many bytes already used within pool */
108 size_t bytes_left; /* bytes still available in this pool */
109} small_pool_hdr;
110
111typedef struct large_pool_struct *large_pool_ptr;
112
113typedef struct large_pool_struct {
114 large_pool_ptr next; /* next in list of pools */
115 size_t bytes_used; /* how many bytes already used within pool */
116 size_t bytes_left; /* bytes still available in this pool */
117} large_pool_hdr;
118
119/*
120 * Here is the full definition of a memory manager object.
121 */
122
123typedef struct {
124 struct jpeg_memory_mgr pub; /* public fields */
125
126 /* Each pool identifier (lifetime class) names a linked list of pools. */
127 small_pool_ptr small_list[JPOOL_NUMPOOLS2];
128 large_pool_ptr large_list[JPOOL_NUMPOOLS2];
129
130 /* Since we only have one lifetime class of virtual arrays, only one
131 * linked list is necessary (for each datatype). Note that the virtual
132 * array control blocks being linked together are actually stored somewhere
133 * in the small-pool list.
134 */
135 jvirt_sarray_ptr virt_sarray_list;
136 jvirt_barray_ptr virt_barray_list;
137
138 /* This counts total space obtained from jpeg_get_small/large */
139 size_t total_space_allocated;
140
141 /* alloc_sarray and alloc_barray set this value for use by virtual
142 * array routines.
143 */
144 JDIMENSION last_rowsperchunk; /* from most recent alloc_sarray/barray */
145} my_memory_mgr;
146
147typedef my_memory_mgr *my_mem_ptr;
148
149
150/*
151 * The control blocks for virtual arrays.
152 * Note that these blocks are allocated in the "small" pool area.
153 * System-dependent info for the associated backing store (if any) is hidden
154 * inside the backing_store_info struct.
155 */
156
157struct jvirt_sarray_control {
158 JSAMPARRAY mem_buffer; /* => the in-memory buffer (if
159 cinfo->data_precision > 8, then this is
160 actually a J12SAMPARRAY or a
161 J16SAMPARRAY) */
162 JDIMENSION rows_in_array; /* total virtual array height */
163 JDIMENSION samplesperrow; /* width of array (and of memory buffer) */
164 JDIMENSION maxaccess; /* max rows accessed by access_virt_sarray */
165 JDIMENSION rows_in_mem; /* height of memory buffer */
166 JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */
167 JDIMENSION cur_start_row; /* first logical row # in the buffer */
168 JDIMENSION first_undef_row; /* row # of first uninitialized row */
169 boolean pre_zero; /* pre-zero mode requested? */
170 boolean dirty; /* do current buffer contents need written? */
171 boolean b_s_open; /* is backing-store data valid? */
172 jvirt_sarray_ptr next; /* link to next virtual sarray control block */
173 backing_store_info b_s_info; /* System-dependent control info */
174};
175
176struct jvirt_barray_control {
177 JBLOCKARRAY mem_buffer; /* => the in-memory buffer */
178 JDIMENSION rows_in_array; /* total virtual array height */
179 JDIMENSION blocksperrow; /* width of array (and of memory buffer) */
180 JDIMENSION maxaccess; /* max rows accessed by access_virt_barray */
181 JDIMENSION rows_in_mem; /* height of memory buffer */
182 JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */
183 JDIMENSION cur_start_row; /* first logical row # in the buffer */
184 JDIMENSION first_undef_row; /* row # of first uninitialized row */
185 boolean pre_zero; /* pre-zero mode requested? */
186 boolean dirty; /* do current buffer contents need written? */
187 boolean b_s_open; /* is backing-store data valid? */
188 jvirt_barray_ptr next; /* link to next virtual barray control block */
189 backing_store_info b_s_info; /* System-dependent control info */
190};
191
192
193#ifdef MEM_STATS /* optional extra stuff for statistics */
194
195LOCAL(void)static void
196print_mem_stats(j_common_ptr cinfo, int pool_id)
197{
198 my_mem_ptr mem = (my_mem_ptr)cinfo->mem;
199 small_pool_ptr shdr_ptr;
200 large_pool_ptr lhdr_ptr;
201
202 /* Since this is only a debugging stub, we can cheat a little by using
203 * fprintf directly rather than going through the trace message code.
204 * This is helpful because message parm array can't handle longs.
205 */
206 fprintf(stderrstderr, "Freeing pool %d, total space = %ld\n",
207 pool_id, mem->total_space_allocated);
208
209 for (lhdr_ptr = mem->large_list[pool_id]; lhdr_ptr != NULL((void*)0);
210 lhdr_ptr = lhdr_ptr->next) {
211 fprintf(stderrstderr, " Large chunk used %ld\n", (long)lhdr_ptr->bytes_used);
212 }
213
214 for (shdr_ptr = mem->small_list[pool_id]; shdr_ptr != NULL((void*)0);
215 shdr_ptr = shdr_ptr->next) {
216 fprintf(stderrstderr, " Small chunk used %ld free %ld\n",
217 (long)shdr_ptr->bytes_used, (long)shdr_ptr->bytes_left);
218 }
219}
220
221#endif /* MEM_STATS */
222
223
224LOCAL(void)static void
225out_of_memory(j_common_ptr cinfo, int which)
226/* Report an out-of-memory error and stop execution */
227/* If we compiled MEM_STATS support, report alloc requests before dying */
228{
229#ifdef MEM_STATS
230 cinfo->err->trace_level = 2; /* force self_destruct to report stats */
231#endif
232 ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, which)((cinfo)->err->msg_code = (JERR_OUT_OF_MEMORY), (cinfo)
->err->msg_parm.i[0] = (which), (*(cinfo)->err->error_exit
) ((j_common_ptr)(cinfo)))
;
233}
234
235
236/*
237 * Allocation of "small" objects.
238 *
239 * For these, we use pooled storage. When a new pool must be created,
240 * we try to get enough space for the current request plus a "slop" factor,
241 * where the slop will be the amount of leftover space in the new pool.
242 * The speed vs. space tradeoff is largely determined by the slop values.
243 * A different slop value is provided for each pool class (lifetime),
244 * and we also distinguish the first pool of a class from later ones.
245 * NOTE: the values given work fairly well on both 16- and 32-bit-int
246 * machines, but may be too small if longs are 64 bits or more.
247 *
248 * Since we do not know what alignment malloc() gives us, we have to
249 * allocate ALIGN_SIZE-1 extra space per pool to have room for alignment
250 * adjustment.
251 */
252
253static const size_t first_pool_slop[JPOOL_NUMPOOLS2] = {
254 1600, /* first PERMANENT pool */
255 16000 /* first IMAGE pool */
256};
257
258static const size_t extra_pool_slop[JPOOL_NUMPOOLS2] = {
259 0, /* additional PERMANENT pools */
260 5000 /* additional IMAGE pools */
261};
262
263#define MIN_SLOP50 50 /* greater than 0 to avoid futile looping */
264
265
266METHODDEF(void *)static void *
267alloc_small(j_common_ptr cinfo, int pool_id, size_t sizeofobject)
268/* Allocate a "small" object */
269{
270 my_mem_ptr mem = (my_mem_ptr)cinfo->mem;
271 small_pool_ptr hdr_ptr, prev_hdr_ptr;
272 char *data_ptr;
273 size_t min_request, slop;
274
275 /*
276 * Round up the requested size to a multiple of ALIGN_SIZE in order
277 * to assure alignment for the next object allocated in the same pool
278 * and so that algorithms can straddle outside the proper area up
279 * to the next alignment.
280 */
281 if (sizeofobject > MAX_ALLOC_CHUNK1000000000L) {
282 /* This prevents overflow/wrap-around in round_up_pow2() if sizeofobject
283 is close to SIZE_MAX. */
284 out_of_memory(cinfo, 7);
285 }
286 sizeofobject = round_up_pow2(sizeofobject, ALIGN_SIZE32);
287
288 /* Check for unsatisfiable request (do now to ensure no overflow below) */
289 if ((sizeof(small_pool_hdr) + sizeofobject + ALIGN_SIZE32 - 1) >
290 MAX_ALLOC_CHUNK1000000000L)
291 out_of_memory(cinfo, 1); /* request exceeds malloc's ability */
292
293 /* See if space is available in any existing pool */
294 if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS2)
295 ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id)((cinfo)->err->msg_code = (JERR_BAD_POOL_ID), (cinfo)->
err->msg_parm.i[0] = (pool_id), (*(cinfo)->err->error_exit
) ((j_common_ptr)(cinfo)))
; /* safety check */
296 prev_hdr_ptr = NULL((void*)0);
297 hdr_ptr = mem->small_list[pool_id];
298 while (hdr_ptr != NULL((void*)0)) {
299 if (hdr_ptr->bytes_left >= sizeofobject)
300 break; /* found pool with enough space */
301 prev_hdr_ptr = hdr_ptr;
302 hdr_ptr = hdr_ptr->next;
303 }
304
305 /* Time to make a new pool? */
306 if (hdr_ptr == NULL((void*)0)) {
307 /* min_request is what we need now, slop is what will be leftover */
308 min_request = sizeof(small_pool_hdr) + sizeofobject + ALIGN_SIZE32 - 1;
309 if (prev_hdr_ptr == NULL((void*)0)) /* first pool in class? */
310 slop = first_pool_slop[pool_id];
311 else
312 slop = extra_pool_slop[pool_id];
313 /* Don't ask for more than MAX_ALLOC_CHUNK */
314 if (slop > (size_t)(MAX_ALLOC_CHUNK1000000000L - min_request))
315 slop = (size_t)(MAX_ALLOC_CHUNK1000000000L - min_request);
316 /* Try to get space, if fail reduce slop and try again */
317 for (;;) {
318 hdr_ptr = (small_pool_ptr)jpeg_get_small(cinfo, min_request + slop);
319 if (hdr_ptr != NULL((void*)0))
320 break;
321 slop /= 2;
322 if (slop < MIN_SLOP50) /* give up when it gets real small */
323 out_of_memory(cinfo, 2); /* jpeg_get_small failed */
324 }
325 mem->total_space_allocated += min_request + slop;
326 /* Success, initialize the new pool header and add to end of list */
327 hdr_ptr->next = NULL((void*)0);
328 hdr_ptr->bytes_used = 0;
329 hdr_ptr->bytes_left = sizeofobject + slop;
330 if (prev_hdr_ptr == NULL((void*)0)) /* first pool in class? */
331 mem->small_list[pool_id] = hdr_ptr;
332 else
333 prev_hdr_ptr->next = hdr_ptr;
334 }
335
336 /* OK, allocate the object from the current pool */
337 data_ptr = (char *)hdr_ptr; /* point to first data byte in pool... */
338 data_ptr += sizeof(small_pool_hdr); /* ...by skipping the header... */
339 if ((size_t)data_ptr % ALIGN_SIZE32) /* ...and adjust for alignment */
340 data_ptr += ALIGN_SIZE32 - (size_t)data_ptr % ALIGN_SIZE32;
341 data_ptr += hdr_ptr->bytes_used; /* point to place for object */
342 hdr_ptr->bytes_used += sizeofobject;
343 hdr_ptr->bytes_left -= sizeofobject;
344
345 return (void *)data_ptr;
346}
347
348
349/*
350 * Allocation of "large" objects.
351 *
352 * The external semantics of these are the same as "small" objects. However,
353 * the pool management heuristics are quite different. We assume that each
354 * request is large enough that it may as well be passed directly to
355 * jpeg_get_large; the pool management just links everything together
356 * so that we can free it all on demand.
357 * Note: the major use of "large" objects is in
358 * JSAMPARRAY/J12SAMPARRAY/J16SAMPARRAY and JBLOCKARRAY structures. The
359 * routines that create these structures (see below) deliberately bunch rows
360 * together to ensure a large request size.
361 */
362
363METHODDEF(void *)static void *
364alloc_large(j_common_ptr cinfo, int pool_id, size_t sizeofobject)
365/* Allocate a "large" object */
366{
367 my_mem_ptr mem = (my_mem_ptr)cinfo->mem;
368 large_pool_ptr hdr_ptr;
369 char *data_ptr;
370
371 /*
372 * Round up the requested size to a multiple of ALIGN_SIZE so that
373 * algorithms can straddle outside the proper area up to the next
374 * alignment.
375 */
376 if (sizeofobject > MAX_ALLOC_CHUNK1000000000L) {
38
Assuming 'sizeofobject' is <= MAX_ALLOC_CHUNK
39
Taking false branch
377 /* This prevents overflow/wrap-around in round_up_pow2() if sizeofobject
378 is close to SIZE_MAX. */
379 out_of_memory(cinfo, 8);
380 }
381 sizeofobject = round_up_pow2(sizeofobject, ALIGN_SIZE32);
382
383 /* Check for unsatisfiable request (do now to ensure no overflow below) */
384 if ((sizeof(large_pool_hdr) + sizeofobject + ALIGN_SIZE32 - 1) >
40
Assuming the condition is false
385 MAX_ALLOC_CHUNK1000000000L)
386 out_of_memory(cinfo, 3); /* request exceeds malloc's ability */
387
388 /* Always make a new pool */
389 if (pool_id
40.1
'pool_id' is >= 0
< 0 || pool_id
40.2
'pool_id' is < JPOOL_NUMPOOLS
>= JPOOL_NUMPOOLS2)
41
Taking false branch
390 ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id)((cinfo)->err->msg_code = (JERR_BAD_POOL_ID), (cinfo)->
err->msg_parm.i[0] = (pool_id), (*(cinfo)->err->error_exit
) ((j_common_ptr)(cinfo)))
; /* safety check */
391
392 hdr_ptr = (large_pool_ptr)jpeg_get_large(cinfo, sizeofobject +
42
Value assigned to 'hdr_ptr'
393 sizeof(large_pool_hdr) +
394 ALIGN_SIZE32 - 1);
395 if (hdr_ptr == NULL((void*)0))
43
Assuming 'hdr_ptr' is equal to NULL
44
Taking true branch
396 out_of_memory(cinfo, 4); /* jpeg_get_large failed */
397 mem->total_space_allocated += sizeofobject + sizeof(large_pool_hdr) +
398 ALIGN_SIZE32 - 1;
399
400 /* Success, initialize the new pool header and add to list */
401 hdr_ptr->next = mem->large_list[pool_id];
45
Access to field 'next' results in a dereference of a null pointer (loaded from variable 'hdr_ptr')
402 /* We maintain space counts in each pool header for statistical purposes,
403 * even though they are not needed for allocation.
404 */
405 hdr_ptr->bytes_used = sizeofobject;
406 hdr_ptr->bytes_left = 0;
407 mem->large_list[pool_id] = hdr_ptr;
408
409 data_ptr = (char *)hdr_ptr; /* point to first data byte in pool... */
410 data_ptr += sizeof(small_pool_hdr); /* ...by skipping the header... */
411 if ((size_t)data_ptr % ALIGN_SIZE32) /* ...and adjust for alignment */
412 data_ptr += ALIGN_SIZE32 - (size_t)data_ptr % ALIGN_SIZE32;
413
414 return (void *)data_ptr;
415}
416
417
418/*
419 * Creation of 2-D sample arrays.
420 *
421 * To minimize allocation overhead and to allow I/O of large contiguous
422 * blocks, we allocate the sample rows in groups of as many rows as possible
423 * without exceeding MAX_ALLOC_CHUNK total bytes per allocation request.
424 * NB: the virtual array control routines, later in this file, know about
425 * this chunking of rows. The rowsperchunk value is left in the mem manager
426 * object so that it can be saved away if this sarray is the workspace for
427 * a virtual array.
428 *
429 * Since we are often upsampling with a factor 2, we align the size (not
430 * the start) to 2 * ALIGN_SIZE so that the upsampling routines don't have
431 * to be as careful about size.
432 */
433
434METHODDEF(JSAMPARRAY)static JSAMPARRAY
435alloc_sarray(j_common_ptr cinfo, int pool_id, JDIMENSION samplesperrow,
436 JDIMENSION numrows)
437/* Allocate a 2-D sample array */
438{
439 my_mem_ptr mem = (my_mem_ptr)cinfo->mem;
440 JSAMPARRAY result;
441 JSAMPROW workspace;
442 JDIMENSION rowsperchunk, currow, i;
443 long ltemp;
444 J12SAMPARRAY result12;
445 J12SAMPROW workspace12;
446#if defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED)
447 J16SAMPARRAY result16;
448 J16SAMPROW workspace16;
449#endif
450 int data_precision = cinfo->is_decompressor ?
451 ((j_decompress_ptr)cinfo)->data_precision :
452 ((j_compress_ptr)cinfo)->data_precision;
453 size_t sample_size = data_precision > 12 ?
454 sizeof(J16SAMPLE) : (data_precision > 8 ?
455 sizeof(J12SAMPLE) :
456 sizeof(JSAMPLE));
457
458 /* Make sure each row is properly aligned */
459 if ((ALIGN_SIZE32 % sample_size) != 0)
460 out_of_memory(cinfo, 5); /* safety check */
461
462 if (samplesperrow > MAX_ALLOC_CHUNK1000000000L) {
463 /* This prevents overflow/wrap-around in round_up_pow2() if sizeofobject
464 is close to SIZE_MAX. */
465 out_of_memory(cinfo, 9);
466 }
467 samplesperrow = (JDIMENSION)round_up_pow2(samplesperrow, (2 * ALIGN_SIZE32) /
468 sample_size);
469
470 /* Calculate max # of rows allowed in one allocation chunk */
471 ltemp = (MAX_ALLOC_CHUNK1000000000L - sizeof(large_pool_hdr)) /
472 ((long)samplesperrow * (long)sample_size);
473 if (ltemp <= 0)
474 ERREXIT(cinfo, JERR_WIDTH_OVERFLOW)((cinfo)->err->msg_code = (JERR_WIDTH_OVERFLOW), (*(cinfo
)->err->error_exit) ((j_common_ptr)(cinfo)))
;
475 if (ltemp < (long)numrows)
476 rowsperchunk = (JDIMENSION)ltemp;
477 else
478 rowsperchunk = numrows;
479 mem->last_rowsperchunk = rowsperchunk;
480
481 if (data_precision <= 8) {
482 /* Get space for row pointers (small object) */
483 result = (JSAMPARRAY)alloc_small(cinfo, pool_id,
484 (size_t)(numrows * sizeof(JSAMPROW)));
485
486 /* Get the rows themselves (large objects) */
487 currow = 0;
488 while (currow < numrows) {
489 rowsperchunk = MIN(rowsperchunk, numrows - currow)((rowsperchunk) < (numrows - currow) ? (rowsperchunk) : (numrows
- currow))
;
490 workspace = (JSAMPROW)alloc_large(cinfo, pool_id,
491 (size_t)((size_t)rowsperchunk * (size_t)samplesperrow * sample_size));
492 for (i = rowsperchunk; i > 0; i--) {
493 result[currow++] = workspace;
494 workspace += samplesperrow;
495 }
496 }
497
498 return result;
499 } else if (data_precision <= 12) {
500 /* Get space for row pointers (small object) */
501 result12 = (J12SAMPARRAY)alloc_small(cinfo, pool_id,
502 (size_t)(numrows *
503 sizeof(J12SAMPROW)));
504
505 /* Get the rows themselves (large objects) */
506 currow = 0;
507 while (currow < numrows) {
508 rowsperchunk = MIN(rowsperchunk, numrows - currow)((rowsperchunk) < (numrows - currow) ? (rowsperchunk) : (numrows
- currow))
;
509 workspace12 = (J12SAMPROW)alloc_large(cinfo, pool_id,
510 (size_t)((size_t)rowsperchunk * (size_t)samplesperrow * sample_size));
511 for (i = rowsperchunk; i > 0; i--) {
512 result12[currow++] = workspace12;
513 workspace12 += samplesperrow;
514 }
515 }
516
517 return (JSAMPARRAY)result12;
518 } else {
519#if defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED)
520 /* Get space for row pointers (small object) */
521 result16 = (J16SAMPARRAY)alloc_small(cinfo, pool_id,
522 (size_t)(numrows *
523 sizeof(J16SAMPROW)));
524
525 /* Get the rows themselves (large objects) */
526 currow = 0;
527 while (currow < numrows) {
528 rowsperchunk = MIN(rowsperchunk, numrows - currow)((rowsperchunk) < (numrows - currow) ? (rowsperchunk) : (numrows
- currow))
;
529 workspace16 = (J16SAMPROW)alloc_large(cinfo, pool_id,
530 (size_t)((size_t)rowsperchunk * (size_t)samplesperrow * sample_size));
531 for (i = rowsperchunk; i > 0; i--) {
532 result16[currow++] = workspace16;
533 workspace16 += samplesperrow;
534 }
535 }
536
537 return (JSAMPARRAY)result16;
538#else
539 ERREXIT1(cinfo, JERR_BAD_PRECISION, data_precision)((cinfo)->err->msg_code = (JERR_BAD_PRECISION), (cinfo)
->err->msg_parm.i[0] = (data_precision), (*(cinfo)->
err->error_exit) ((j_common_ptr)(cinfo)))
;
540 return NULL((void*)0);
541#endif
542 }
543}
544
545
546/*
547 * Creation of 2-D coefficient-block arrays.
548 * This is essentially the same as the code for sample arrays, above.
549 */
550
551METHODDEF(JBLOCKARRAY)static JBLOCKARRAY
552alloc_barray(j_common_ptr cinfo, int pool_id, JDIMENSION blocksperrow,
553 JDIMENSION numrows)
554/* Allocate a 2-D coefficient-block array */
555{
556 my_mem_ptr mem = (my_mem_ptr)cinfo->mem;
557 JBLOCKARRAY result;
558 JBLOCKROW workspace;
559 JDIMENSION rowsperchunk, currow, i;
560 long ltemp;
561
562 /* Make sure each row is properly aligned */
563 if ((sizeof(JBLOCK) % ALIGN_SIZE32) != 0)
29
Taking false branch
564 out_of_memory(cinfo, 6); /* safety check */
565
566 /* Calculate max # of rows allowed in one allocation chunk */
567 ltemp = (MAX_ALLOC_CHUNK1000000000L - sizeof(large_pool_hdr)) /
568 ((long)blocksperrow * sizeof(JBLOCK));
569 if (ltemp <= 0)
30
Assuming 'ltemp' is > 0
31
Taking false branch
570 ERREXIT(cinfo, JERR_WIDTH_OVERFLOW)((cinfo)->err->msg_code = (JERR_WIDTH_OVERFLOW), (*(cinfo
)->err->error_exit) ((j_common_ptr)(cinfo)))
;
571 if (ltemp < (long)numrows)
32
Assuming 'ltemp' is < 'numrows'
33
Taking true branch
572 rowsperchunk = (JDIMENSION)ltemp;
573 else
574 rowsperchunk = numrows;
575 mem->last_rowsperchunk = rowsperchunk;
576
577 /* Get space for row pointers (small object) */
578 result = (JBLOCKARRAY)alloc_small(cinfo, pool_id,
579 (size_t)(numrows * sizeof(JBLOCKROW)));
580
581 /* Get the rows themselves (large objects) */
582 currow = 0;
583 while (currow < numrows) {
34
Assuming 'currow' is < 'numrows'
584 rowsperchunk = MIN(rowsperchunk, numrows - currow)((rowsperchunk) < (numrows - currow) ? (rowsperchunk) : (numrows
- currow))
;
35
Loop condition is true. Entering loop body
36
'?' condition is true
585 workspace = (JBLOCKROW)alloc_large(cinfo, pool_id,
37
Calling 'alloc_large'
586 (size_t)((size_t)rowsperchunk * (size_t)blocksperrow *
587 sizeof(JBLOCK)));
588 for (i = rowsperchunk; i > 0; i--) {
589 result[currow++] = workspace;
590 workspace += blocksperrow;
591 }
592 }
593
594 return result;
595}
596
597
598/*
599 * About virtual array management:
600 *
601 * The above "normal" array routines are only used to allocate strip buffers
602 * (as wide as the image, but just a few rows high). Full-image-sized buffers
603 * are handled as "virtual" arrays. The array is still accessed a strip at a
604 * time, but the memory manager must save the whole array for repeated
605 * accesses. The intended implementation is that there is a strip buffer in
606 * memory (as high as is possible given the desired memory limit), plus a
607 * backing file that holds the rest of the array.
608 *
609 * The request_virt_array routines are told the total size of the image and
610 * the maximum number of rows that will be accessed at once. The in-memory
611 * buffer must be at least as large as the maxaccess value.
612 *
613 * The request routines create control blocks but not the in-memory buffers.
614 * That is postponed until realize_virt_arrays is called. At that time the
615 * total amount of space needed is known (approximately, anyway), so free
616 * memory can be divided up fairly.
617 *
618 * The access_virt_array routines are responsible for making a specific strip
619 * area accessible (after reading or writing the backing file, if necessary).
620 * Note that the access routines are told whether the caller intends to modify
621 * the accessed strip; during a read-only pass this saves having to rewrite
622 * data to disk. The access routines are also responsible for pre-zeroing
623 * any newly accessed rows, if pre-zeroing was requested.
624 *
625 * In current usage, the access requests are usually for nonoverlapping
626 * strips; that is, successive access start_row numbers differ by exactly
627 * num_rows = maxaccess. This means we can get good performance with simple
628 * buffer dump/reload logic, by making the in-memory buffer be a multiple
629 * of the access height; then there will never be accesses across bufferload
630 * boundaries. The code will still work with overlapping access requests,
631 * but it doesn't handle bufferload overlaps very efficiently.
632 */
633
634
635METHODDEF(jvirt_sarray_ptr)static jvirt_sarray_ptr
636request_virt_sarray(j_common_ptr cinfo, int pool_id, boolean pre_zero,
637 JDIMENSION samplesperrow, JDIMENSION numrows,
638 JDIMENSION maxaccess)
639/* Request a virtual 2-D sample array */
640{
641 my_mem_ptr mem = (my_mem_ptr)cinfo->mem;
642 jvirt_sarray_ptr result;
643
644 /* Only IMAGE-lifetime virtual arrays are currently supported */
645 if (pool_id != JPOOL_IMAGE1)
646 ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id)((cinfo)->err->msg_code = (JERR_BAD_POOL_ID), (cinfo)->
err->msg_parm.i[0] = (pool_id), (*(cinfo)->err->error_exit
) ((j_common_ptr)(cinfo)))
; /* safety check */
647
648 /* get control block */
649 result = (jvirt_sarray_ptr)alloc_small(cinfo, pool_id,
650 sizeof(struct jvirt_sarray_control));
651
652 result->mem_buffer = NULL((void*)0); /* marks array not yet realized */
653 result->rows_in_array = numrows;
654 result->samplesperrow = samplesperrow;
655 result->maxaccess = maxaccess;
656 result->pre_zero = pre_zero;
657 result->b_s_open = FALSE0; /* no associated backing-store object */
658 result->next = mem->virt_sarray_list; /* add to list of virtual arrays */
659 mem->virt_sarray_list = result;
660
661 return result;
662}
663
664
665METHODDEF(jvirt_barray_ptr)static jvirt_barray_ptr
666request_virt_barray(j_common_ptr cinfo, int pool_id, boolean pre_zero,
667 JDIMENSION blocksperrow, JDIMENSION numrows,
668 JDIMENSION maxaccess)
669/* Request a virtual 2-D coefficient-block array */
670{
671 my_mem_ptr mem = (my_mem_ptr)cinfo->mem;
672 jvirt_barray_ptr result;
673
674 /* Only IMAGE-lifetime virtual arrays are currently supported */
675 if (pool_id != JPOOL_IMAGE1)
676 ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id)((cinfo)->err->msg_code = (JERR_BAD_POOL_ID), (cinfo)->
err->msg_parm.i[0] = (pool_id), (*(cinfo)->err->error_exit
) ((j_common_ptr)(cinfo)))
; /* safety check */
677
678 /* get control block */
679 result = (jvirt_barray_ptr)alloc_small(cinfo, pool_id,
680 sizeof(struct jvirt_barray_control));
681
682 result->mem_buffer = NULL((void*)0); /* marks array not yet realized */
683 result->rows_in_array = numrows;
684 result->blocksperrow = blocksperrow;
685 result->maxaccess = maxaccess;
686 result->pre_zero = pre_zero;
687 result->b_s_open = FALSE0; /* no associated backing-store object */
688 result->next = mem->virt_barray_list; /* add to list of virtual arrays */
689 mem->virt_barray_list = result;
690
691 return result;
692}
693
694
695METHODDEF(void)static void
696realize_virt_arrays(j_common_ptr cinfo)
697/* Allocate the in-memory buffers for any unrealized virtual arrays */
698{
699 my_mem_ptr mem = (my_mem_ptr)cinfo->mem;
700 size_t space_per_minheight, maximum_space, avail_mem;
701 size_t minheights, max_minheights;
702 jvirt_sarray_ptr sptr;
703 jvirt_barray_ptr bptr;
704 int data_precision = cinfo->is_decompressor ?
1
Assuming field 'is_decompressor' is 0
2
'?' condition is false
705 ((j_decompress_ptr)cinfo)->data_precision :
706 ((j_compress_ptr)cinfo)->data_precision;
707 size_t sample_size = data_precision > 12 ?
3
Assuming 'data_precision' is <= 12
4
'?' condition is false
708 sizeof(J16SAMPLE) : (data_precision > 8 ?
5
Assuming 'data_precision' is <= 8
6
'?' condition is false
709 sizeof(J12SAMPLE) :
710 sizeof(JSAMPLE));
711
712 /* Compute the minimum space needed (maxaccess rows in each buffer)
713 * and the maximum space needed (full image height in each buffer).
714 * These may be of use to the system-dependent jpeg_mem_available routine.
715 */
716 space_per_minheight = 0;
717 maximum_space = 0;
718 for (sptr = mem->virt_sarray_list; sptr != NULL((void*)0); sptr = sptr->next) {
7
Assuming 'sptr' is equal to NULL
8
Loop condition is false. Execution continues on line 730
719 if (sptr->mem_buffer == NULL((void*)0)) { /* if not realized yet */
720 size_t new_space = (size_t)sptr->rows_in_array *
721 (size_t)sptr->samplesperrow * sample_size;
722
723 space_per_minheight += (size_t)sptr->maxaccess *
724 (size_t)sptr->samplesperrow * sample_size;
725 if (SIZE_MAX(18446744073709551615UL) - maximum_space < new_space)
726 out_of_memory(cinfo, 10);
727 maximum_space += new_space;
728 }
729 }
730 for (bptr = mem->virt_barray_list; bptr != NULL((void*)0); bptr = bptr->next) {
9
Assuming 'bptr' is not equal to NULL
10
Loop condition is true. Entering loop body
15
Assuming 'bptr' is equal to NULL
16
Loop condition is false. Execution continues on line 743
731 if (bptr->mem_buffer == NULL((void*)0)) { /* if not realized yet */
11
Assuming field 'mem_buffer' is equal to NULL
12
Taking true branch
732 size_t new_space = (size_t)bptr->rows_in_array *
733 (size_t)bptr->blocksperrow * sizeof(JBLOCK);
734
735 space_per_minheight += (size_t)bptr->maxaccess *
736 (size_t)bptr->blocksperrow * sizeof(JBLOCK);
737 if (SIZE_MAX(18446744073709551615UL) - maximum_space < new_space)
13
Assuming the condition is false
14
Taking false branch
738 out_of_memory(cinfo, 11);
739 maximum_space += new_space;
740 }
741 }
742
743 if (space_per_minheight <= 0)
17
Assuming 'space_per_minheight' is > 0
18
Taking false branch
744 return; /* no unrealized arrays, no work */
745
746 /* Determine amount of memory to actually use; this is system-dependent. */
747 avail_mem = jpeg_mem_available(cinfo, space_per_minheight, maximum_space,
748 mem->total_space_allocated);
749
750 /* If the maximum space needed is available, make all the buffers full
751 * height; otherwise parcel it out with the same number of minheights
752 * in each buffer.
753 */
754 if (avail_mem >= maximum_space)
19
Assuming 'avail_mem' is < 'maximum_space'
20
Taking false branch
755 max_minheights = 1000000000L;
756 else {
757 max_minheights = avail_mem / space_per_minheight;
758 /* If there doesn't seem to be enough space, try to get the minimum
759 * anyway. This allows a "stub" implementation of jpeg_mem_available().
760 */
761 if (max_minheights <= 0)
21
Assuming 'max_minheights' is > 0
22
Taking false branch
762 max_minheights = 1;
763 }
764
765 /* Allocate the in-memory buffers and initialize backing store as needed. */
766
767 for (sptr = mem->virt_sarray_list; sptr != NULL((void*)0); sptr = sptr->next) {
23
Loop condition is false. Execution continues on line 791
768 if (sptr->mem_buffer == NULL((void*)0)) { /* if not realized yet */
769 minheights = ((long)sptr->rows_in_array - 1L) / sptr->maxaccess + 1L;
770 if (minheights <= max_minheights) {
771 /* This buffer fits in memory */
772 sptr->rows_in_mem = sptr->rows_in_array;
773 } else {
774 /* It doesn't fit in memory, create backing store. */
775 sptr->rows_in_mem = (JDIMENSION)(max_minheights * sptr->maxaccess);
776 jpeg_open_backing_store(cinfo, &sptr->b_s_info,
777 (long)((size_t)sptr->rows_in_array *
778 (size_t)sptr->samplesperrow *
779 sample_size));
780 sptr->b_s_open = TRUE1;
781 }
782 sptr->mem_buffer = alloc_sarray(cinfo, JPOOL_IMAGE1,
783 sptr->samplesperrow, sptr->rows_in_mem);
784 sptr->rowsperchunk = mem->last_rowsperchunk;
785 sptr->cur_start_row = 0;
786 sptr->first_undef_row = 0;
787 sptr->dirty = FALSE0;
788 }
789 }
790
791 for (bptr = mem->virt_barray_list; bptr
23.1
'bptr' is not equal to NULL
!= NULL((void*)0); bptr = bptr->next) {
24
Loop condition is true. Entering loop body
792 if (bptr->mem_buffer
24.1
Field 'mem_buffer' is equal to NULL
== NULL((void*)0)) { /* if not realized yet */
25
Taking true branch
793 minheights = ((long)bptr->rows_in_array - 1L) / bptr->maxaccess + 1L;
794 if (minheights <= max_minheights) {
26
Assuming 'minheights' is <= 'max_minheights'
27
Taking true branch
795 /* This buffer fits in memory */
796 bptr->rows_in_mem = bptr->rows_in_array;
797 } else {
798 /* It doesn't fit in memory, create backing store. */
799 bptr->rows_in_mem = (JDIMENSION)(max_minheights * bptr->maxaccess);
800 jpeg_open_backing_store(cinfo, &bptr->b_s_info,
801 (long)((size_t)bptr->rows_in_array *
802 (size_t)bptr->blocksperrow *
803 sizeof(JBLOCK)));
804 bptr->b_s_open = TRUE1;
805 }
806 bptr->mem_buffer = alloc_barray(cinfo, JPOOL_IMAGE1,
28
Calling 'alloc_barray'
807 bptr->blocksperrow, bptr->rows_in_mem);
808 bptr->rowsperchunk = mem->last_rowsperchunk;
809 bptr->cur_start_row = 0;
810 bptr->first_undef_row = 0;
811 bptr->dirty = FALSE0;
812 }
813 }
814}
815
816
817LOCAL(void)static void
818do_sarray_io(j_common_ptr cinfo, jvirt_sarray_ptr ptr, boolean writing)
819/* Do backing store read or write of a virtual sample array */
820{
821 long bytesperrow, file_offset, byte_count, rows, thisrow, i;
822 int data_precision = cinfo->is_decompressor ?
823 ((j_decompress_ptr)cinfo)->data_precision :
824 ((j_compress_ptr)cinfo)->data_precision;
825 size_t sample_size = data_precision > 12 ?
826 sizeof(J16SAMPLE) : (data_precision > 8 ?
827 sizeof(J12SAMPLE) :
828 sizeof(JSAMPLE));
829
830 bytesperrow = (long)ptr->samplesperrow * (long)sample_size;
831 file_offset = ptr->cur_start_row * bytesperrow;
832 /* Loop to read or write each allocation chunk in mem_buffer */
833 for (i = 0; i < (long)ptr->rows_in_mem; i += ptr->rowsperchunk) {
834 /* One chunk, but check for short chunk at end of buffer */
835 rows = MIN((long)ptr->rowsperchunk, (long)ptr->rows_in_mem - i)(((long)ptr->rowsperchunk) < ((long)ptr->rows_in_mem
- i) ? ((long)ptr->rowsperchunk) : ((long)ptr->rows_in_mem
- i))
;
836 /* Transfer no more than is currently defined */
837 thisrow = (long)ptr->cur_start_row + i;
838 rows = MIN(rows, (long)ptr->first_undef_row - thisrow)((rows) < ((long)ptr->first_undef_row - thisrow) ? (rows
) : ((long)ptr->first_undef_row - thisrow))
;
839 /* Transfer no more than fits in file */
840 rows = MIN(rows, (long)ptr->rows_in_array - thisrow)((rows) < ((long)ptr->rows_in_array - thisrow) ? (rows)
: ((long)ptr->rows_in_array - thisrow))
;
841 if (rows <= 0) /* this chunk might be past end of file! */
842 break;
843 byte_count = rows * bytesperrow;
844 if (data_precision <= 8) {
845 if (writing)
846 (*ptr->b_s_info.write_backing_store) (cinfo, &ptr->b_s_info,
847 (void *)ptr->mem_buffer[i],
848 file_offset, byte_count);
849 else
850 (*ptr->b_s_info.read_backing_store) (cinfo, &ptr->b_s_info,
851 (void *)ptr->mem_buffer[i],
852 file_offset, byte_count);
853 } else if (data_precision <= 12) {
854 J12SAMPARRAY mem_buffer12 = (J12SAMPARRAY)ptr->mem_buffer;
855
856 if (writing)
857 (*ptr->b_s_info.write_backing_store) (cinfo, &ptr->b_s_info,
858 (void *)mem_buffer12[i],
859 file_offset, byte_count);
860 else
861 (*ptr->b_s_info.read_backing_store) (cinfo, &ptr->b_s_info,
862 (void *)mem_buffer12[i],
863 file_offset, byte_count);
864 } else {
865#if defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED)
866 J16SAMPARRAY mem_buffer16 = (J16SAMPARRAY)ptr->mem_buffer;
867
868 if (writing)
869 (*ptr->b_s_info.write_backing_store) (cinfo, &ptr->b_s_info,
870 (void *)mem_buffer16[i],
871 file_offset, byte_count);
872 else
873 (*ptr->b_s_info.read_backing_store) (cinfo, &ptr->b_s_info,
874 (void *)mem_buffer16[i],
875 file_offset, byte_count);
876#else
877 ERREXIT1(cinfo, JERR_BAD_PRECISION, data_precision)((cinfo)->err->msg_code = (JERR_BAD_PRECISION), (cinfo)
->err->msg_parm.i[0] = (data_precision), (*(cinfo)->
err->error_exit) ((j_common_ptr)(cinfo)))
;
878#endif
879 }
880 file_offset += byte_count;
881 }
882}
883
884
885LOCAL(void)static void
886do_barray_io(j_common_ptr cinfo, jvirt_barray_ptr ptr, boolean writing)
887/* Do backing store read or write of a virtual coefficient-block array */
888{
889 long bytesperrow, file_offset, byte_count, rows, thisrow, i;
890
891 bytesperrow = (long)ptr->blocksperrow * sizeof(JBLOCK);
892 file_offset = ptr->cur_start_row * bytesperrow;
893 /* Loop to read or write each allocation chunk in mem_buffer */
894 for (i = 0; i < (long)ptr->rows_in_mem; i += ptr->rowsperchunk) {
895 /* One chunk, but check for short chunk at end of buffer */
896 rows = MIN((long)ptr->rowsperchunk, (long)ptr->rows_in_mem - i)(((long)ptr->rowsperchunk) < ((long)ptr->rows_in_mem
- i) ? ((long)ptr->rowsperchunk) : ((long)ptr->rows_in_mem
- i))
;
897 /* Transfer no more than is currently defined */
898 thisrow = (long)ptr->cur_start_row + i;
899 rows = MIN(rows, (long)ptr->first_undef_row - thisrow)((rows) < ((long)ptr->first_undef_row - thisrow) ? (rows
) : ((long)ptr->first_undef_row - thisrow))
;
900 /* Transfer no more than fits in file */
901 rows = MIN(rows, (long)ptr->rows_in_array - thisrow)((rows) < ((long)ptr->rows_in_array - thisrow) ? (rows)
: ((long)ptr->rows_in_array - thisrow))
;
902 if (rows <= 0) /* this chunk might be past end of file! */
903 break;
904 byte_count = rows * bytesperrow;
905 if (writing)
906 (*ptr->b_s_info.write_backing_store) (cinfo, &ptr->b_s_info,
907 (void *)ptr->mem_buffer[i],
908 file_offset, byte_count);
909 else
910 (*ptr->b_s_info.read_backing_store) (cinfo, &ptr->b_s_info,
911 (void *)ptr->mem_buffer[i],
912 file_offset, byte_count);
913 file_offset += byte_count;
914 }
915}
916
917
918METHODDEF(JSAMPARRAY)static JSAMPARRAY
919access_virt_sarray(j_common_ptr cinfo, jvirt_sarray_ptr ptr,
920 JDIMENSION start_row, JDIMENSION num_rows, boolean writable)
921/* Access the part of a virtual sample array starting at start_row */
922/* and extending for num_rows rows. writable is true if */
923/* caller intends to modify the accessed area. */
924{
925 JDIMENSION end_row = start_row + num_rows;
926 JDIMENSION undef_row;
927 int data_precision = cinfo->is_decompressor ?
928 ((j_decompress_ptr)cinfo)->data_precision :
929 ((j_compress_ptr)cinfo)->data_precision;
930 size_t sample_size = data_precision > 12 ?
931 sizeof(J16SAMPLE) : (data_precision > 8 ?
932 sizeof(J12SAMPLE) :
933 sizeof(JSAMPLE));
934
935 /* debugging check */
936 if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess ||
937 ptr->mem_buffer == NULL((void*)0))
938 ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS)((cinfo)->err->msg_code = (JERR_BAD_VIRTUAL_ACCESS), (*
(cinfo)->err->error_exit) ((j_common_ptr)(cinfo)))
;
939
940 /* Make the desired part of the virtual array accessible */
941 if (start_row < ptr->cur_start_row ||
942 end_row > ptr->cur_start_row + ptr->rows_in_mem) {
943 if (!ptr->b_s_open)
944 ERREXIT(cinfo, JERR_VIRTUAL_BUG)((cinfo)->err->msg_code = (JERR_VIRTUAL_BUG), (*(cinfo)
->err->error_exit) ((j_common_ptr)(cinfo)))
;
945 /* Flush old buffer contents if necessary */
946 if (ptr->dirty) {
947 do_sarray_io(cinfo, ptr, TRUE1);
948 ptr->dirty = FALSE0;
949 }
950 /* Decide what part of virtual array to access.
951 * Algorithm: if target address > current window, assume forward scan,
952 * load starting at target address. If target address < current window,
953 * assume backward scan, load so that target area is top of window.
954 * Note that when switching from forward write to forward read, will have
955 * start_row = 0, so the limiting case applies and we load from 0 anyway.
956 */
957 if (start_row > ptr->cur_start_row) {
958 ptr->cur_start_row = start_row;
959 } else {
960 /* use long arithmetic here to avoid overflow & unsigned problems */
961 long ltemp;
962
963 ltemp = (long)end_row - (long)ptr->rows_in_mem;
964 if (ltemp < 0)
965 ltemp = 0; /* don't fall off front end of file */
966 ptr->cur_start_row = (JDIMENSION)ltemp;
967 }
968 /* Read in the selected part of the array.
969 * During the initial write pass, we will do no actual read
970 * because the selected part is all undefined.
971 */
972 do_sarray_io(cinfo, ptr, FALSE0);
973 }
974 /* Ensure the accessed part of the array is defined; prezero if needed.
975 * To improve locality of access, we only prezero the part of the array
976 * that the caller is about to access, not the entire in-memory array.
977 */
978 if (ptr->first_undef_row < end_row) {
979 if (ptr->first_undef_row < start_row) {
980 if (writable) /* writer skipped over a section of array */
981 ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS)((cinfo)->err->msg_code = (JERR_BAD_VIRTUAL_ACCESS), (*
(cinfo)->err->error_exit) ((j_common_ptr)(cinfo)))
;
982 undef_row = start_row; /* but reader is allowed to read ahead */
983 } else {
984 undef_row = ptr->first_undef_row;
985 }
986 if (writable)
987 ptr->first_undef_row = end_row;
988 if (ptr->pre_zero) {
989 size_t bytesperrow = (size_t)ptr->samplesperrow * sample_size;
990 undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */
991 end_row -= ptr->cur_start_row;
992 while (undef_row < end_row) {
993 jzero_far((void *)ptr->mem_buffer[undef_row], bytesperrow);
994 undef_row++;
995 }
996 } else {
997 if (!writable) /* reader looking at undefined data */
998 ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS)((cinfo)->err->msg_code = (JERR_BAD_VIRTUAL_ACCESS), (*
(cinfo)->err->error_exit) ((j_common_ptr)(cinfo)))
;
999 }
1000 }
1001 /* Flag the buffer dirty if caller will write in it */
1002 if (writable)
1003 ptr->dirty = TRUE1;
1004 /* Return address of proper part of the buffer */
1005 return ptr->mem_buffer + (start_row - ptr->cur_start_row);
1006}
1007
1008
1009METHODDEF(JBLOCKARRAY)static JBLOCKARRAY
1010access_virt_barray(j_common_ptr cinfo, jvirt_barray_ptr ptr,
1011 JDIMENSION start_row, JDIMENSION num_rows, boolean writable)
1012/* Access the part of a virtual block array starting at start_row */
1013/* and extending for num_rows rows. writable is true if */
1014/* caller intends to modify the accessed area. */
1015{
1016 JDIMENSION end_row = start_row + num_rows;
1017 JDIMENSION undef_row;
1018
1019 /* debugging check */
1020 if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess ||
1021 ptr->mem_buffer == NULL((void*)0))
1022 ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS)((cinfo)->err->msg_code = (JERR_BAD_VIRTUAL_ACCESS), (*
(cinfo)->err->error_exit) ((j_common_ptr)(cinfo)))
;
1023
1024 /* Make the desired part of the virtual array accessible */
1025 if (start_row < ptr->cur_start_row ||
1026 end_row > ptr->cur_start_row + ptr->rows_in_mem) {
1027 if (!ptr->b_s_open)
1028 ERREXIT(cinfo, JERR_VIRTUAL_BUG)((cinfo)->err->msg_code = (JERR_VIRTUAL_BUG), (*(cinfo)
->err->error_exit) ((j_common_ptr)(cinfo)))
;
1029 /* Flush old buffer contents if necessary */
1030 if (ptr->dirty) {
1031 do_barray_io(cinfo, ptr, TRUE1);
1032 ptr->dirty = FALSE0;
1033 }
1034 /* Decide what part of virtual array to access.
1035 * Algorithm: if target address > current window, assume forward scan,
1036 * load starting at target address. If target address < current window,
1037 * assume backward scan, load so that target area is top of window.
1038 * Note that when switching from forward write to forward read, will have
1039 * start_row = 0, so the limiting case applies and we load from 0 anyway.
1040 */
1041 if (start_row > ptr->cur_start_row) {
1042 ptr->cur_start_row = start_row;
1043 } else {
1044 /* use long arithmetic here to avoid overflow & unsigned problems */
1045 long ltemp;
1046
1047 ltemp = (long)end_row - (long)ptr->rows_in_mem;
1048 if (ltemp < 0)
1049 ltemp = 0; /* don't fall off front end of file */
1050 ptr->cur_start_row = (JDIMENSION)ltemp;
1051 }
1052 /* Read in the selected part of the array.
1053 * During the initial write pass, we will do no actual read
1054 * because the selected part is all undefined.
1055 */
1056 do_barray_io(cinfo, ptr, FALSE0);
1057 }
1058 /* Ensure the accessed part of the array is defined; prezero if needed.
1059 * To improve locality of access, we only prezero the part of the array
1060 * that the caller is about to access, not the entire in-memory array.
1061 */
1062 if (ptr->first_undef_row < end_row) {
1063 if (ptr->first_undef_row < start_row) {
1064 if (writable) /* writer skipped over a section of array */
1065 ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS)((cinfo)->err->msg_code = (JERR_BAD_VIRTUAL_ACCESS), (*
(cinfo)->err->error_exit) ((j_common_ptr)(cinfo)))
;
1066 undef_row = start_row; /* but reader is allowed to read ahead */
1067 } else {
1068 undef_row = ptr->first_undef_row;
1069 }
1070 if (writable)
1071 ptr->first_undef_row = end_row;
1072 if (ptr->pre_zero) {
1073 size_t bytesperrow = (size_t)ptr->blocksperrow * sizeof(JBLOCK);
1074 undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */
1075 end_row -= ptr->cur_start_row;
1076 while (undef_row < end_row) {
1077 jzero_far((void *)ptr->mem_buffer[undef_row], bytesperrow);
1078 undef_row++;
1079 }
1080 } else {
1081 if (!writable) /* reader looking at undefined data */
1082 ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS)((cinfo)->err->msg_code = (JERR_BAD_VIRTUAL_ACCESS), (*
(cinfo)->err->error_exit) ((j_common_ptr)(cinfo)))
;
1083 }
1084 }
1085 /* Flag the buffer dirty if caller will write in it */
1086 if (writable)
1087 ptr->dirty = TRUE1;
1088 /* Return address of proper part of the buffer */
1089 return ptr->mem_buffer + (start_row - ptr->cur_start_row);
1090}
1091
1092
1093/*
1094 * Release all objects belonging to a specified pool.
1095 */
1096
1097METHODDEF(void)static void
1098free_pool(j_common_ptr cinfo, int pool_id)
1099{
1100 my_mem_ptr mem = (my_mem_ptr)cinfo->mem;
1101 small_pool_ptr shdr_ptr;
1102 large_pool_ptr lhdr_ptr;
1103 size_t space_freed;
1104
1105 if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS2)
1106 ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id)((cinfo)->err->msg_code = (JERR_BAD_POOL_ID), (cinfo)->
err->msg_parm.i[0] = (pool_id), (*(cinfo)->err->error_exit
) ((j_common_ptr)(cinfo)))
; /* safety check */
1107
1108#ifdef MEM_STATS
1109 if (cinfo->err->trace_level > 1)
1110 print_mem_stats(cinfo, pool_id); /* print pool's memory usage statistics */
1111#endif
1112
1113 /* If freeing IMAGE pool, close any virtual arrays first */
1114 if (pool_id == JPOOL_IMAGE1) {
1115 jvirt_sarray_ptr sptr;
1116 jvirt_barray_ptr bptr;
1117
1118 for (sptr = mem->virt_sarray_list; sptr != NULL((void*)0); sptr = sptr->next) {
1119 if (sptr->b_s_open) { /* there may be no backing store */
1120 sptr->b_s_open = FALSE0; /* prevent recursive close if error */
1121 (*sptr->b_s_info.close_backing_store) (cinfo, &sptr->b_s_info);
1122 }
1123 }
1124 mem->virt_sarray_list = NULL((void*)0);
1125 for (bptr = mem->virt_barray_list; bptr != NULL((void*)0); bptr = bptr->next) {
1126 if (bptr->b_s_open) { /* there may be no backing store */
1127 bptr->b_s_open = FALSE0; /* prevent recursive close if error */
1128 (*bptr->b_s_info.close_backing_store) (cinfo, &bptr->b_s_info);
1129 }
1130 }
1131 mem->virt_barray_list = NULL((void*)0);
1132 }
1133
1134 /* Release large objects */
1135 lhdr_ptr = mem->large_list[pool_id];
1136 mem->large_list[pool_id] = NULL((void*)0);
1137
1138 while (lhdr_ptr != NULL((void*)0)) {
1139 large_pool_ptr next_lhdr_ptr = lhdr_ptr->next;
1140 space_freed = lhdr_ptr->bytes_used +
1141 lhdr_ptr->bytes_left +
1142 sizeof(large_pool_hdr) + ALIGN_SIZE32 - 1;
1143 jpeg_free_large(cinfo, (void *)lhdr_ptr, space_freed);
1144 mem->total_space_allocated -= space_freed;
1145 lhdr_ptr = next_lhdr_ptr;
1146 }
1147
1148 /* Release small objects */
1149 shdr_ptr = mem->small_list[pool_id];
1150 mem->small_list[pool_id] = NULL((void*)0);
1151
1152 while (shdr_ptr != NULL((void*)0)) {
1153 small_pool_ptr next_shdr_ptr = shdr_ptr->next;
1154 space_freed = shdr_ptr->bytes_used + shdr_ptr->bytes_left +
1155 sizeof(small_pool_hdr) + ALIGN_SIZE32 - 1;
1156 jpeg_free_small(cinfo, (void *)shdr_ptr, space_freed);
1157 mem->total_space_allocated -= space_freed;
1158 shdr_ptr = next_shdr_ptr;
1159 }
1160}
1161
1162
1163/*
1164 * Close up shop entirely.
1165 * Note that this cannot be called unless cinfo->mem is non-NULL.
1166 */
1167
1168METHODDEF(void)static void
1169self_destruct(j_common_ptr cinfo)
1170{
1171 int pool;
1172
1173 /* Close all backing store, release all memory.
1174 * Releasing pools in reverse order might help avoid fragmentation
1175 * with some (brain-damaged) malloc libraries.
1176 */
1177 for (pool = JPOOL_NUMPOOLS2 - 1; pool >= JPOOL_PERMANENT0; pool--) {
1178 free_pool(cinfo, pool);
1179 }
1180
1181 /* Release the memory manager control block too. */
1182 jpeg_free_small(cinfo, (void *)cinfo->mem, sizeof(my_memory_mgr));
1183 cinfo->mem = NULL((void*)0); /* ensures I will be called only once */
1184
1185 jpeg_mem_term(cinfo); /* system-dependent cleanup */
1186}
1187
1188
1189/*
1190 * Memory manager initialization.
1191 * When this is called, only the error manager pointer is valid in cinfo!
1192 */
1193
1194GLOBAL(void)void
1195jinit_memory_mgr(j_common_ptr cinfo)
1196{
1197 my_mem_ptr mem;
1198 long max_to_use;
1199 int pool;
1200 size_t test_mac;
1201
1202 cinfo->mem = NULL((void*)0); /* for safety if init fails */
1203
1204 /* Check for configuration errors.
1205 * sizeof(ALIGN_TYPE) should be a power of 2; otherwise, it probably
1206 * doesn't reflect any real hardware alignment requirement.
1207 * The test is a little tricky: for X>0, X and X-1 have no one-bits
1208 * in common if and only if X is a power of 2, ie has only one one-bit.
1209 * Some compilers may give an "unreachable code" warning here; ignore it.
1210 */
1211 if ((ALIGN_SIZE32 & (ALIGN_SIZE32 - 1)) != 0)
1212 ERREXIT(cinfo, JERR_BAD_ALIGN_TYPE)((cinfo)->err->msg_code = (JERR_BAD_ALIGN_TYPE), (*(cinfo
)->err->error_exit) ((j_common_ptr)(cinfo)))
;
1213 /* MAX_ALLOC_CHUNK must be representable as type size_t, and must be
1214 * a multiple of ALIGN_SIZE.
1215 * Again, an "unreachable code" warning may be ignored here.
1216 * But a "constant too large" warning means you need to fix MAX_ALLOC_CHUNK.
1217 */
1218 test_mac = (size_t)MAX_ALLOC_CHUNK1000000000L;
1219 if ((long)test_mac != MAX_ALLOC_CHUNK1000000000L ||
1220 (MAX_ALLOC_CHUNK1000000000L % ALIGN_SIZE32) != 0)
1221 ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK)((cinfo)->err->msg_code = (JERR_BAD_ALLOC_CHUNK), (*(cinfo
)->err->error_exit) ((j_common_ptr)(cinfo)))
;
1222
1223 max_to_use = jpeg_mem_init(cinfo); /* system-dependent initialization */
1224
1225 /* Attempt to allocate memory manager's control block */
1226 mem = (my_mem_ptr)jpeg_get_small(cinfo, sizeof(my_memory_mgr));
1227
1228 if (mem == NULL((void*)0)) {
1229 jpeg_mem_term(cinfo); /* system-dependent cleanup */
1230 ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0)((cinfo)->err->msg_code = (JERR_OUT_OF_MEMORY), (cinfo)
->err->msg_parm.i[0] = (0), (*(cinfo)->err->error_exit
) ((j_common_ptr)(cinfo)))
;
1231 }
1232
1233 /* OK, fill in the method pointers */
1234 mem->pub.alloc_small = alloc_small;
1235 mem->pub.alloc_large = alloc_large;
1236 mem->pub.alloc_sarray = alloc_sarray;
1237 mem->pub.alloc_barray = alloc_barray;
1238 mem->pub.request_virt_sarray = request_virt_sarray;
1239 mem->pub.request_virt_barray = request_virt_barray;
1240 mem->pub.realize_virt_arrays = realize_virt_arrays;
1241 mem->pub.access_virt_sarray = access_virt_sarray;
1242 mem->pub.access_virt_barray = access_virt_barray;
1243 mem->pub.free_pool = free_pool;
1244 mem->pub.self_destruct = self_destruct;
1245
1246 /* Make MAX_ALLOC_CHUNK accessible to other modules */
1247 mem->pub.max_alloc_chunk = MAX_ALLOC_CHUNK1000000000L;
1248
1249 /* Initialize working state */
1250 mem->pub.max_memory_to_use = max_to_use;
1251
1252 for (pool = JPOOL_NUMPOOLS2 - 1; pool >= JPOOL_PERMANENT0; pool--) {
1253 mem->small_list[pool] = NULL((void*)0);
1254 mem->large_list[pool] = NULL((void*)0);
1255 }
1256 mem->virt_sarray_list = NULL((void*)0);
1257 mem->virt_barray_list = NULL((void*)0);
1258
1259 mem->total_space_allocated = sizeof(my_memory_mgr);
1260
1261 /* Declare ourselves open for business */
1262 cinfo->mem = &mem->pub;
1263
1264 /* Check for an environment variable JPEGMEM; if found, override the
1265 * default max_memory setting from jpeg_mem_init. Note that the
1266 * surrounding application may again override this value.
1267 * If your system doesn't support getenv(), define NO_GETENV to disable
1268 * this feature.
1269 */
1270#ifndef NO_GETENV
1271 {
1272 char memenv[30] = { 0 };
1273
1274 if (!GETENV_S(memenv, 30, "JPEGMEM") && strlen(memenv) > 0) {
1275 char ch = 'x';
1276
1277#ifdef _MSC_VER
1278 if (sscanf_s(memenv, "%ld%c", &max_to_use, &ch, 1) > 0) {
1279#else
1280 if (sscanf(memenv, "%ld%c", &max_to_use, &ch) > 0) {
1281#endif
1282 if (ch == 'm' || ch == 'M')
1283 max_to_use *= 1000L;
1284 mem->pub.max_memory_to_use = max_to_use * 1000L;
1285 }
1286 }
1287 }
1288#endif
1289
1290}