Bug Summary

File:decompress.c
Warning:line 163, column 3
Opened File never closed. Potential Resource leak

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name decompress.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -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 -mrelocation-model pic -pic-level 2 -pic-is-pie -mthread-model posix -mframe-pointer=all -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -resource-dir /usr/lib/clang/10.0.0 -I ./src -I ./src/inc -internal-isystem /usr/local/include -internal-isystem /usr/lib/clang/10.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-sign-compare -std=c11 -fdebug-compilation-dir /tmp/ssgctv09 -ferror-limit 19 -fmessage-length 0 -stack-protector 2 -fobjc-runtime=gcc -fdiagnostics-show-option -analyzer-checker alpha.core.CallAndMessageUnInitRefArg -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.Conversion -analyzer-checker alpha.core.FixedAddr -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.PointerArithm -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.core.TestAfterDivZero -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.BlockInCriticalSection -analyzer-checker alpha.unix.Chroot -analyzer-checker alpha.unix.PthreadLock -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.Stream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker valist.CopyToSelf -analyzer-checker valist.Uninitialized -analyzer-checker valist.Unterminated -analyzer-checker security.FloatLoopCounter -analyzer-checker security.insecureAPI.strcpy -analyzer-max-loop 1536 -analyzer-output=html -faddrsig -o /tmp/scan-build-2019-10-07-120410-3045-1 -x c src/decompress.c
1/*
2 ============================================================================
3 Name : decompress.c
4 Author : nanash1
5 Version : 0.9
6 Description : Decompresses Grandia Saturn graphics files
7 ============================================================================
8 */
9
10/**
11* This software is supplied "AS IS" without any warranties of
12* any kind. The author, nanash1, assumes no responsibility
13* or liability for the use of the software, conveys no license or rights under any
14* patent, copyright, mask work right, or any other intellectual property rights in
15* or to any products. The author also makes no
16* representation or warranty that such application will be suitable for the
17* specified use without further testing or modification.
18*
19* Permission to use, copy, modify, and distribute this software and its
20* documentation is hereby granted. This copyright, permission, and disclaimer
21* notice must appear in all copies of this code.
22*/
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <stdint.h>
27#include <string.h>
28#include <byteswap.h>
29
30#include "compression.h"
31
32const uint8_t lut_seed[9] = {0, 128, 64, 32, 16, 8, 4, 2, 1};
33static uint16_t decomp_lut[256];
34
35/**
36 * @brief Gets the next byte of encoded data and advances the pointer
37 * @param p_offset_code Next bit offset to advance the pointer
38 * @param pp_lut_data Pointer to current input data pointer
39 * @return Encoded data
40 */
41static uint16_t extract_lut_data(uint16_t* p_offset_code, uint8_t** pp_lut_data)
42{
43 uint16_t shift_code = *p_offset_code >> 4;
44 uint32_t fetched_source_data;
45
46 if (shift_code > 31){
47 *pp_lut_data += 4;
48 shift_code -= 32;
49 *p_offset_code = shift_code << 4;
50 }
51
52 uint8_t* p_source_data = *pp_lut_data;
53
54 if (shift_code < 25){
55 fetched_source_data = __bswap_32(*((uint32_t*) p_source_data)) >> (24 - shift_code);
56 } else {
57 fetched_source_data = __bswap_32(*((uint32_t*) p_source_data)) << (shift_code - 24);
58 fetched_source_data |= __bswap_32(*((uint32_t*) (p_source_data + 4))) >> (56 - shift_code); // or in bits from next pointer
59 }
60
61 return (uint16_t) ((fetched_source_data & 0xff) << 1);
62}
63
64/**
65 * @brief Generates the decompression lut
66 * @param p_comp_lut Pointer to the memory the table is written at
67 * @return Status 0:Success 1:Error
68 */
69static uint8_t generate_lut(uint8_t* p_comp_lut)
70{
71 uint8_t rtn = 0;
72 uint8_t bit_num;
73 uint8_t max_bit_num;
74 uint8_t decode_char;
75 uint16_t lut_elem;
76 uint16_t *p_decomp_lut = &decomp_lut[0];
77
78 for(uint_fast8_t j = 0; j < 17; j++){
79 max_bit_num = 0;
80 for(uint_fast8_t i = 0; i < 17; i++){
81 if (i%2){
82 bit_num = *(p_comp_lut + (i/2)) & 0xf;
83 } else {
84 bit_num = *(p_comp_lut + (i/2)) >> 4;
85 }
86
87 if (bit_num > max_bit_num){
88 max_bit_num = bit_num;
89 decode_char = i;
90 }
91 }
92
93 if (max_bit_num > 8){
94 rtn = 1;
95 break;
96 } else if (max_bit_num == 0){
97 break;
98 }
99
100 if (decode_char%2){
101 *(p_comp_lut + (decode_char/2)) &= 0xf0;
102 } else {
103 *(p_comp_lut + (decode_char/2)) &= 0xf;
104 }
105
106 lut_elem = decode_char << 8;
107 lut_elem |= max_bit_num << 4;
108 if (decode_char == 16){
109 lut_elem++;
110 }
111 for (uint_fast8_t i = 0; i < lut_seed[max_bit_num]; i++){
112
113 *p_decomp_lut = lut_elem;
114 p_decomp_lut++;
115 }
116 }
117
118 /* check if the table is within bounds */
119 if (p_decomp_lut != &decomp_lut[0] + 256){
120 rtn = 1;
121 }
122 return rtn;
123
124}
125
126/**
127 * @brief Decompresses the compressed data from the Grandia iso
128 * @param input Input file name as string
129 * @param output Output file name as string
130 * @param comp_data_offset Start offset of the compressed data in the input file
131 * @param p_mode The used decompression mode is written to this pointer
132 * @param p_lut The used look up table is written to this pointer
133 * @param p_rle_limit The used RLE limit is written to this pointer
134 * @return Status
135 */
136compression_status_t decompress(
137 const char* input,
138 const char* output,
139 uint32_t comp_data_offset,
140 enum comp_mode* p_mode,
141 uint8_t* p_lut,
142 uint8_t* p_rle_limit)
143{
144 uint8_t* p_iso;
145
146
147 /* read dumped file into memory */
148 int size = 0;
149 FILE *f = fopen(input, "rb");
150
151 if (f
0.1
'f' is not equal to NULL
== NULL((void*)0)){
1
Taking false branch
152 return FILE_NOT_FOUND;
153 }
154
155 fseek(f, 0, SEEK_END2);
156 size = ftell(f);
157 fseek(f, 0, SEEK_SET0);
158
159 p_iso = (uint8_t *) malloc(size+1);
160
161 if (size != fread(p_iso, sizeof(int8_t), size, f))
2
Assuming the condition is true
3
Taking true branch
162 {
163 free(p_iso);
4
Opened File never closed. Potential Resource leak
164 return INSUFFICIENT_MEM;
165 }
166 fclose(f);
167
168 /* read header */
169 uint8_t* p_rle_data = p_iso + comp_data_offset;
170 uint16_t head_data;
171 head_data = __bswap_16(*((uint16_t*) p_rle_data));
172 if ( (head_data >> 8) & 0x20){ // if the second bit is set
173 free(p_iso);
174 return INVALID_HEADER;
175 }
176
177 /* get mode */
178 uint8_t mode_bits = head_data >> 14;
179 enum comp_mode mode;
180 switch (mode_bits){
181 case 0b10:
182 mode = SUB_MODE;
183 break;
184 case 0b00:
185 mode = MOV_MODE;
186 break;
187 case 0b01:
188 mode = XOR_MODE;
189 break;
190 default:
191 free(p_iso);
192 return INVALID_HEADER;
193 }
194 *p_mode = mode;
195
196 /* write decompression table */
197 uint16_t table_offset = head_data;
198 table_offset = table_offset & 0x1fff;
199 uint8_t* p_table_data = p_rle_data + table_offset + 2;
200 memcpy(p_lut, p_table_data, 9);
201 if (generate_lut(p_table_data)){
202 free(p_iso);
203 return INVALID_TABLE;
204 }
205
206 /* reserve memory for decompressed data */
207 uint8_t* p_decompressed = (uint8_t*) calloc(64000, sizeof(uint8_t));
208 uint8_t* p_output = p_decompressed;
209
210 /* get pointer to lut encoded data */
211 uint8_t* p_lut_data = p_rle_data + table_offset + 0xb;
212 p_lut_data = (uint8_t*) (((uint32_t) p_lut_data) & 0xfffffffc); // probably to align for 32bit memory access, TODO: check if this works here
213
214 /* advance pointer to first RLE data */
215 p_rle_data += 2;
216
217 /* initialize decompression vars */
218 uint8_t rle_zeros_cntr = 0;
219 uint8_t rle_limit = 0;
220 uint16_t zero_num = 0;
221 uint16_t zero_diff;
222 uint32_t decoded_bits_num = 0;
223
224 uint16_t shift_code = ((table_offset + 0xb) & 0x3) << 7;
225 uint16_t decompressed_bits = 0;
226 uint8_t rle_prefix;
227 uint32_t lut_index = 0;
228 uint16_t lut_data;
229 uint_fast8_t is_aligned = 0;
230
231 uint_fast32_t run_cntr = 0;
232 while(1){
233
234 run_cntr++;
235
236 if (run_cntr > MAX_DECOMP_LEN(1500)){
237 free(p_decompressed);
238 free(p_iso);
239 return RUNAWAY_DATA;
240 }
241
242 /* get next rle bits */
243 if (is_aligned){
244 rle_prefix = *p_rle_data & 0xf;
245 p_rle_data++;
246 is_aligned = 0;
247 } else {
248 rle_prefix = *p_rle_data >> 4;
249 is_aligned = 1;
250 }
251
252 /* check the prefix code */
253 switch (rle_prefix){
254 case 0xD: // read next 4 bits as extended delta information
255 if (is_aligned){
256 zero_diff = *p_rle_data & 0xf;
257 is_aligned = 0;
258 p_rle_data++;
259 } else {
260 zero_diff = *p_rle_data >> 4;
261 is_aligned = 1;
262 }
263 if (zero_diff >= 8){
264 zero_num += (zero_diff - 1);
265 } else {
266 zero_num += zero_diff - 14;
267 }
268 break;
269
270 case 0xE: // read next 8 bits as number of zeros
271 if (is_aligned){
272 zero_num = (*p_rle_data & 0xf) << 4;
273 p_rle_data++;
274 zero_num |= *p_rle_data >> 4;
275 } else {
276 zero_num = *p_rle_data;
277 p_rle_data++;
278 }
279 break;
280
281 case 0xF: // read next 16 bits as number of zeros
282 if (is_aligned){
283 zero_num = (*p_rle_data & 0xf) << 12;
284 p_rle_data++;
285 zero_num |= *p_rle_data << 4;
286 p_rle_data++;
287 zero_num |= (*p_rle_data & 0xf0) >> 4;
288 } else {
289 zero_num = *p_rle_data << 8;
290 p_rle_data++;
291 zero_num |= *p_rle_data;
292 p_rle_data++;
293 }
294 break;
295
296 default: // read prefix as number of zeros offset
297 zero_num += rle_prefix - 6;
298 break;
299 }
300
301
302 /* write the determined number of zeros */
303 if (zero_num){
304
305 if (decoded_bits_num % 2){
306 p_output += (zero_num - 1) / 2;
307 } else {
308 p_output += zero_num / 2;
309 }
310 decoded_bits_num += zero_num;
311
312 } else {
313 break;
314 }
315
316 while (1){
317
318 /* use the generated table to read actual data from memory */
319 lut_index = extract_lut_data(&shift_code, &p_lut_data);
320 lut_data = decomp_lut[lut_index/2];
321
322 /* look for stop condition and write data to output */
323 if (!(lut_data & 0x1)){
324 shift_code += lut_data & 0xff;
325 lut_data >>= 8;
326 switch (mode){
327 case SUB_MODE:
328 decompressed_bits = (decompressed_bits - lut_data) & 0xf;
329 break;
330 case MOV_MODE:
331 decompressed_bits = lut_data & 0xf;
332 break;
333 case XOR_MODE:
334 decompressed_bits = (decompressed_bits ^ lut_data) & 0xf;
335 break;
336 }
337
338 if (decompressed_bits == 0){
339 rle_zeros_cntr++;
340 } else {
341 if (rle_limit < rle_zeros_cntr){
342 rle_limit = rle_zeros_cntr;
343 }
344 rle_zeros_cntr = 0;
345 }
346
347 if (decoded_bits_num % 2){
348 *p_output |= decompressed_bits;
349 p_output++;
350 decoded_bits_num++;
351 } else {
352 *p_output = decompressed_bits << 4;
353 decoded_bits_num++;
354 }
355
356 } else {
357 if (decoded_bits_num % 2){
358 p_output++;
359 }
360 shift_code += lut_data & 0xf0;
361 break;
362 }
363 }
364 }
365
366 f = fopen(output, "wb");
367 fwrite(p_decompressed, sizeof(uint8_t), (int32_t) (p_output - p_decompressed), f);
368 fclose(f);
369
370 free(p_decompressed);
371 free(p_iso);
372
373 *p_rle_limit = rle_limit + 1;
374
375 return SUCCESS;
376}