Bug Summary

File:solenv/bin/concat-deps.c
Location:line 433, column 16
Description:Access to field 'size' results in a dereference of a null pointer (loaded from variable 'hash')

Annotated Source Code

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * Copyright (C) 2011 Norbert Thiebaud
4 * License: GPLv3
5 */
6
7/* define to activate stats reporting on hash usage*/
8/* #define HASH_STAT */
9
10/* ===============================================
11 * Set-up: defines to identify the system and system related properties
12 * ===============================================
13 */
14
15#ifdef __APPLE__
16#ifdef __x86_64__
17#define CORE_BIG_ENDIAN0 0
18#define CORE_LITTLE_ENDIAN1 1
19#define USE_MEMORY_ALIGNMENT64 64 /* big value -> no alignment */
20#else
21#define CORE_BIG_ENDIAN0 1
22#define CORE_LITTLE_ENDIAN1 0
23#define USE_MEMORY_ALIGNMENT64 4
24#endif
25
26#endif
27#ifdef _AIX
28#define CORE_BIG_ENDIAN0 1
29#define CORE_LITTLE_ENDIAN1 0
30#define USE_MEMORY_ALIGNMENT64 4
31#endif /* Def _AIX */
32
33#ifdef __CYGWIN__
34#define __windows
35#define CORE_BIG_ENDIAN0 0
36#define CORE_LITTLE_ENDIAN1 1
37#define USE_MEMORY_ALIGNMENT64 64 /* big value -> no alignment */
38#endif /* Def __CYGWIN__ */
39
40#if defined(__linux1) || defined(__OpenBSD__) || \
41 defined(__FreeBSD__) || defined(__NetBSD__) || \
42 defined(__DragonFly__)
43#if __BYTE_ORDER1234 == __LITTLE_ENDIAN1234
44#define CORE_BIG_ENDIAN0 0
45#define CORE_LITTLE_ENDIAN1 1
46#if defined(__x86_64) || defined(__i3861)
47#define USE_MEMORY_ALIGNMENT64 64
48#else
49#define USE_MEMORY_ALIGNMENT64 4
50#endif
51#else /* !(__BYTE_ORDER == __LITTLE_ENDIAN) */
52#if __BYTE_ORDER1234 == __BIG_ENDIAN4321
53#define CORE_BIG_ENDIAN0 1
54#define CORE_LITTLE_ENDIAN1 0
55#define USE_MEMORY_ALIGNMENT64 4
56#endif /* __BYTE_ORDER == __BIG_ENDIAN */
57#endif /* !(__BYTE_ORDER == __LITTLE_ENDIAN) */
58#endif /* Def __linux || Def *BSD */
59
60#ifdef __sun
61#ifdef __sparc
62#define CORE_BIG_ENDIAN0 1
63#define CORE_LITTLE_ENDIAN1 0
64#define USE_MEMORY_ALIGNMENT64 4
65#else /* Ndef __sparc */
66#define CORE_BIG_ENDIAN0 0
67#define CORE_LITTLE_ENDIAN1 1
68#define USE_MEMORY_ALIGNMENT64 4
69#endif /* Ndef __sparc */
70#endif /* Def __sun */
71
72/* Note USE_MEMORY_ALIGNMENT is 4 for platform that allow short non-aligned but required int access to be aligned (e.g sparc, ppc, zos..)
73 * USE_MEMORY_ALIGNMENT is 2 for platform that require short and int access to be aligned (e.g hppa )
74 * if the platform does not have alignment requirement (x86/amd64) use a big value (i.e > 16)
75 */
76#ifndef USE_MEMORY_ALIGNMENT64
77#error "USE_MEMORY_ALIGNMENT must be defined to the proper alignment value for the platform"
78#endif
79
80#include <assert.h>
81#include <stdio.h>
82#include <stdlib.h>
83#include <sys/types.h>
84#include <sys/stat.h>
85#include <errno(*__errno_location ()).h>
86#include <fcntl.h>
87#include <string.h>
88#include <ctype.h>
89
90#ifdef __windows
91#include <io.h>
92#else
93#include <unistd.h>
94#endif
95
96/* modes */
97#ifdef __windows
98#define FILE_O_RDONLY00 _O_RDONLY
99#define FILE_O_BINARY0 _O_BINARY
100#else /* not windaube */
101#define FILE_O_RDONLY00 O_RDONLY00
102#define FILE_O_BINARY0 0
103#endif /* not windaube */
104
105#ifndef TRUE1
106#define TRUE1 1
107#endif
108#ifndef FALSE0
109#define FALSE0 0
110#endif
111
112static char* base_dir_var = "$(SRCDIR)";
113#define kBASE_DIR_VAR_LENGTH9 9
114static char* base_dir;
115
116#ifdef __GNUC__4
117#define clz__builtin_clz __builtin_clz
118#else
119static inline int clz__builtin_clz(unsigned int value)
120{
121int result = 32;
122
123 while(value)
124 {
125 value >>= 1;
126 result -= 1;
127 }
128 return result;
129}
130#endif
131
132#if (USE_MEMORY_ALIGNMENT64 > 4)
133#define get_unaligned_uint(str)(*(unsigned int*)(str)) (*(unsigned int*)(str))
134#else
135static inline unsigned int get_unaligned_uint(const unsigned char* cursor)(*(unsigned int*)(const unsigned char* cursor))
136{
137unsigned int result;
138
139 memcpy(&result, cursor, sizeof(unsigned int));
140 return result;
141}
142#endif
143
144/* ===============================================
145 * memory pool for fast fix-size allocation (non-tread-safe)
146 * ===============================================
147 */
148struct pool
149{
150 void* head_free; /**< head of a linked list of freed element */
151 char* fresh; /**< top of a memory block to dig new element */
152 char* tail; /**< to detect end of extent... when fresh pass tail */
153 void* extent; /**< pointer to the primary extent block */
154 int size_elem; /**< size of an element. */
155 int primary; /**< primary allocation in bytes */
156 int secondary; /**< secondary allocation in bytes */
157};
158#define POOL_ALIGN_INCREMENT8 8 /**< Alignement, must be a power of 2 and of size > to sizeof(void*) */
159
160
161static void* pool_take_extent(struct pool* pool, int allocate)
162{
163unsigned int size = 0;
164void* extent;
165void* data = NULL((void*)0);
166
167 if(pool->extent)
168 {
169 fputs("taking a pool extent\n", stderrstderr);
170 /* we already have an extent, so this is a secondary */
171 if(pool->secondary)
172 {
173 size = pool->secondary;
174 }
175 }
176 else
177 {
178 assert(pool->primary)((pool->primary) ? (void) (0) : __assert_fail ("pool->primary"
, "/usr/local/src/libreoffice/solenv/bin/concat-deps.c", 178,
__PRETTY_FUNCTION__))
;
179 size = pool->primary;
180 }
181 if(size)
182 {
183 extent = malloc(size);
184 if(extent)
185 {
186 *(void**)extent = pool->extent;
187 pool->extent = extent;
188 if(allocate)
189 {
190 data = ((char*)extent) + POOL_ALIGN_INCREMENT8;
191 pool->fresh = ((char*)data) + pool->size_elem;
192 pool->tail = pool->fresh + (size - pool->size_elem);
193 }
194 else
195 {
196 pool->fresh = ((char*)extent) + POOL_ALIGN_INCREMENT8;
197 pool->tail = pool->fresh + (size - pool->size_elem);
198 }
199 }
200 }
201 return data;
202}
203
204/* Create a memory pool for fix size objects
205 * this is a simplified implementation that
206 * is _not_ thread safe.
207 */
208struct pool* pool_create(int size_elem, int flags, int primary, int secondary)
209{
210struct pool* pool;
211
212 assert(primary > 0)((primary > 0) ? (void) (0) : __assert_fail ("primary > 0"
, "/usr/local/src/libreoffice/solenv/bin/concat-deps.c", 212,
__PRETTY_FUNCTION__))
;
213 assert(secondary >= 0)((secondary >= 0) ? (void) (0) : __assert_fail ("secondary >= 0"
, "/usr/local/src/libreoffice/solenv/bin/concat-deps.c", 213,
__PRETTY_FUNCTION__))
;
214 assert(size_elem > 0)((size_elem > 0) ? (void) (0) : __assert_fail ("size_elem > 0"
, "/usr/local/src/libreoffice/solenv/bin/concat-deps.c", 214,
__PRETTY_FUNCTION__))
;
215
216 pool = (struct pool*)calloc(1, sizeof(struct pool));
217 if(!pool) return NULL((void*)0);
218 /* Adjust the element size so that it be aligned, and so that an element could
219 * at least contain a void*
220 */
221 pool->size_elem = size_elem = (size_elem + POOL_ALIGN_INCREMENT8 - 1) & ~(POOL_ALIGN_INCREMENT8 - 1);
222
223 pool->primary = (size_elem * primary) + POOL_ALIGN_INCREMENT8;
224 pool->secondary = secondary > 0 ? (size_elem * secondary) + POOL_ALIGN_INCREMENT8 : 0;
225 pool_take_extent(pool, FALSE0);
226
227 return pool;
228
229}
230
231void pool_destroy(struct pool* pool)
232{
233void* extent;
234void* next;
235
236 if(pool != NULL((void*)0))
237 {
238 extent = pool->extent;
239 while(extent)
240 {
241 next = *(void**)extent;
242 free(extent);
243 extent = next;
244 }
245 free(pool);
246 }
247}
248
249static inline void* pool_alloc(struct pool* pool)
250{
251void* data;
252
253 data = pool->head_free;
254 if(data == NULL((void*)0))
255 {
256 /* we have no old-freed elem */
257 if(pool->fresh <= pool->tail)
258 {
259 /* pick a slice of the current extent */
260 data = (void*)pool->fresh;
261 pool->fresh += pool->size_elem;
262 }
263 else
264 {
265 /* allocate a new extent */
266 data = pool_take_extent(pool, TRUE1);
267 }
268 }
269 else
270 {
271 /* re-used old freed element by chopipng the head of the free list */
272 pool->head_free = *(void**)data;
273 }
274
275 return data;
276}
277
278
279static inline void pool_free(struct pool* pool, void* data)
280{
281 assert(pool && data)((pool && data) ? (void) (0) : __assert_fail ("pool && data"
, "/usr/local/src/libreoffice/solenv/bin/concat-deps.c", 281,
__PRETTY_FUNCTION__))
;
282
283 /* stack on top of the free list */
284 *(void**)data = pool->head_free;
285 pool->head_free = data;
286}
287
288
289/* ===============================================
290 * Hash implementation custumized to be just tracking
291 * a unique list of string (i.e no data associated
292 * with the key, no need for retrieval, etc..
293 *
294 * This is tuned for the particular use-case we have here
295 * measures in tail_build showed that
296 * we can get north of 4000 distinct values stored in a hash
297 * the collision rate is at worse around 2%
298 * the collision needing an expensive memcmp to resolve
299 * have a rate typically at 1 per 1000
300 * for tail_build we register 37229 unique key
301 * with a total of 377 extra memcmp needed
302 * which is completely negligible compared to the
303 * number of memcmp required to eliminate duplicate
304 * entry (north of 2.5 millions for tail_build)
305 * ===============================================
306 */
307
308struct hash_elem
309{
310 struct hash_elem* next;
311 const char* key;
312 int key_len;
313};
314
315struct hash
316{
317 struct hash_elem** array;
318 struct pool* elems_pool;
319 int flags;
320 unsigned int used;
321 unsigned int size;
322 unsigned int load_limit;
323#ifdef HASH_STAT
324 int stored;
325 int collisions;
326 int cost;
327 int memcmp;
328#endif
329};
330#define HASH_F_NO_RESIZE(1<<0) (1<<0)
331
332/* The following hash_compute function was adapted from :
333 * lookup3.c, by Bob Jenkins, May 2006, Public Domain.
334 *
335 * The changes from the original are mostly cosmetic
336 */
337#define hashsize(n)(1<<(n)) (1<<(n))
338#define hashmask(n)((1<<(n))-1) (hashsize(n)(1<<(n))-1)
339#define rot(x,k)(((x)<<(k)) | ((x)>>(32 -(k)))) (((x)<<(k)) | ((x)>>(32-(k))))
340
341
342#if CORE_BIG_ENDIAN0
343#define MASK_C10xFFFFFF 0xFFFFFF00
344#define MASK_C20xFFFF 0xFFFF0000
345#define MASK_C30xFF 0xFF000000
346#else
347#if CORE_LITTLE_ENDIAN1
348#define MASK_C10xFFFFFF 0xFFFFFF
349#define MASK_C20xFFFF 0xFFFF
350#define MASK_C30xFF 0xFF
351#else
352#error "Missing Endianness definition"
353#endif
354#endif
355
356
357#define mix(a,b,c){ a -= c; a ^= (((c)<<(4)) | ((c)>>(32 -(4)))); c
+= b; b -= a; b ^= (((a)<<(6)) | ((a)>>(32 -(6))
)); a += c; c -= b; c ^= (((b)<<(8)) | ((b)>>(32 -
(8)))); b += a; a -= c; a ^= (((c)<<(16)) | ((c)>>
(32 -(16)))); c += b; b -= a; b ^= (((a)<<(19)) | ((a)>>
(32 -(19)))); a += c; c -= b; c ^= (((b)<<(4)) | ((b)>>
(32 -(4)))); b += a; }
\
358{ \
359 a -= c; a ^= rot(c, 4)(((c)<<(4)) | ((c)>>(32 -(4)))); c += b; \
360 b -= a; b ^= rot(a, 6)(((a)<<(6)) | ((a)>>(32 -(6)))); a += c; \
361 c -= b; c ^= rot(b, 8)(((b)<<(8)) | ((b)>>(32 -(8)))); b += a; \
362 a -= c; a ^= rot(c,16)(((c)<<(16)) | ((c)>>(32 -(16)))); c += b; \
363 b -= a; b ^= rot(a,19)(((a)<<(19)) | ((a)>>(32 -(19)))); a += c; \
364 c -= b; c ^= rot(b, 4)(((b)<<(4)) | ((b)>>(32 -(4)))); b += a; \
365}
366#define final(a,b,c){ c ^= b; c -= (((b)<<(14)) | ((b)>>(32 -(14))));
a ^= c; a -= (((c)<<(11)) | ((c)>>(32 -(11)))); b
^= a; b -= (((a)<<(25)) | ((a)>>(32 -(25)))); c ^=
b; c -= (((b)<<(16)) | ((b)>>(32 -(16)))); a ^= c
; a -= (((c)<<(4)) | ((c)>>(32 -(4)))); b ^= a; b
-= (((a)<<(14)) | ((a)>>(32 -(14)))); c ^= b; c -=
(((b)<<(24)) | ((b)>>(32 -(24)))); }
\
367{ \
368 c ^= b; c -= rot(b,14)(((b)<<(14)) | ((b)>>(32 -(14)))); \
369 a ^= c; a -= rot(c,11)(((c)<<(11)) | ((c)>>(32 -(11)))); \
370 b ^= a; b -= rot(a,25)(((a)<<(25)) | ((a)>>(32 -(25)))); \
371 c ^= b; c -= rot(b,16)(((b)<<(16)) | ((b)>>(32 -(16)))); \
372 a ^= c; a -= rot(c,4)(((c)<<(4)) | ((c)>>(32 -(4)))); \
373 b ^= a; b -= rot(a,14)(((a)<<(14)) | ((a)>>(32 -(14)))); \
374 c ^= b; c -= rot(b,24)(((b)<<(24)) | ((b)>>(32 -(24)))); \
375}
376
377static unsigned int hash_compute( struct hash* hash, const char* key, int length)
378{
379 unsigned int a;
380 unsigned int b;
381 unsigned int c; /* internal state */
382 const unsigned char* uk = (const unsigned char*)key;
383
384 /* Set up the internal state */
385 a = b = c = 0xdeadbeef + (length << 2);
386
387 /* we use this to 'hash' full path with mostly a common root
388 * let's now waste too much cycles hashing mostly constant stuff
389 */
390 if(length > 36)
33
Taking false branch
391 {
392 uk += length - 36;
393 length = 36;
394 }
395 /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
396 while (length > 12)
34
Loop condition is false. Execution continues on line 415
397 {
398 a += get_unaligned_uint(uk)(*(unsigned int*)(uk));
399 b += get_unaligned_uint(uk+4)(*(unsigned int*)(uk+4));
400 c += get_unaligned_uint(uk+8)(*(unsigned int*)(uk+8));
401 mix(a,b,c){ a -= c; a ^= (((c)<<(4)) | ((c)>>(32 -(4)))); c
+= b; b -= a; b ^= (((a)<<(6)) | ((a)>>(32 -(6))
)); a += c; c -= b; c ^= (((b)<<(8)) | ((b)>>(32 -
(8)))); b += a; a -= c; a ^= (((c)<<(16)) | ((c)>>
(32 -(16)))); c += b; b -= a; b ^= (((a)<<(19)) | ((a)>>
(32 -(19)))); a += c; c -= b; c ^= (((b)<<(4)) | ((b)>>
(32 -(4)))); b += a; }
;
402 length -= 12;
403 uk += 12;
404 }
405
406 /*----------------------------- handle the last (probably partial) block */
407 /* Note: we possibly over-read, which would trigger complaint from VALGRIND
408 * but we mask the undefined stuff if any, so we are still good, thanks
409 * to alignment of memory allocation and tail-memory managment overhead
410 * we always can read 3 bytes past the official end without triggering
411 * a segfault -- if you find a platform/compiler couple for which that postulat
412 * is false, then you just need to over-allocate by 2 more bytes in file_load()
413 * file_load already over-allocate by 1 to sitck a \0 at the end of the buffer.
414 */
415 switch(length)
35
Control jumps to 'case 3:' at line 426
416 {
417 case 12: c+=get_unaligned_uint(uk+8)(*(unsigned int*)(uk+8)); b+=get_unaligned_uint(uk+4)(*(unsigned int*)(uk+4)); a+=get_unaligned_uint(uk)(*(unsigned int*)(uk)); break;
418 case 11: c+=get_unaligned_uint(uk+8)(*(unsigned int*)(uk+8)) & MASK_C10xFFFFFF; b+=get_unaligned_uint(uk+4)(*(unsigned int*)(uk+4)); a+=get_unaligned_uint(uk)(*(unsigned int*)(uk)); break;
419 case 10: c+=get_unaligned_uint(uk+8)(*(unsigned int*)(uk+8)) & MASK_C20xFFFF; b+=get_unaligned_uint(uk+4)(*(unsigned int*)(uk+4)); a+=get_unaligned_uint(uk)(*(unsigned int*)(uk)); break;
420 case 9 : c+=get_unaligned_uint(uk+8)(*(unsigned int*)(uk+8)) & MASK_C30xFF; b+=get_unaligned_uint(uk+4)(*(unsigned int*)(uk+4)); a+=get_unaligned_uint(uk)(*(unsigned int*)(uk)); break;
421 case 8 : b+=get_unaligned_uint(uk+4)(*(unsigned int*)(uk+4)); a+=get_unaligned_uint(uk)(*(unsigned int*)(uk)); break;
422 case 7 : b+=get_unaligned_uint(uk+4)(*(unsigned int*)(uk+4)) & MASK_C10xFFFFFF; a+=get_unaligned_uint(uk)(*(unsigned int*)(uk)); break;
423 case 6 : b+=get_unaligned_uint(uk+4)(*(unsigned int*)(uk+4)) & MASK_C20xFFFF; a+=get_unaligned_uint(uk)(*(unsigned int*)(uk)); break;
424 case 5 : b+=get_unaligned_uint(uk+4)(*(unsigned int*)(uk+4)) & MASK_C30xFF; a+=get_unaligned_uint(uk)(*(unsigned int*)(uk)); break;
425 case 4 : a+=get_unaligned_uint(uk)(*(unsigned int*)(uk)); break;
426 case 3 : a+=get_unaligned_uint(uk)(*(unsigned int*)(uk)) & MASK_C10xFFFFFF; break;
36
Execution continues on line 432
427 case 2 : a+=get_unaligned_uint(uk)(*(unsigned int*)(uk)) & MASK_C20xFFFF; break;
428 case 1 : a+=get_unaligned_uint(uk)(*(unsigned int*)(uk)) & MASK_C30xFF; break;
429 case 0 : return c & hash->size; /* zero length strings require no mixing */
430 }
431
432 final(a,b,c){ c ^= b; c -= (((b)<<(14)) | ((b)>>(32 -(14))));
a ^= c; a -= (((c)<<(11)) | ((c)>>(32 -(11)))); b
^= a; b -= (((a)<<(25)) | ((a)>>(32 -(25)))); c ^=
b; c -= (((b)<<(16)) | ((b)>>(32 -(16)))); a ^= c
; a -= (((c)<<(4)) | ((c)>>(32 -(4)))); b ^= a; b
-= (((a)<<(14)) | ((a)>>(32 -(14)))); c ^= b; c -=
(((b)<<(24)) | ((b)>>(32 -(24)))); }
;
433 return c & hash->size;
37
Access to field 'size' results in a dereference of a null pointer (loaded from variable 'hash')
434}
435
436static void hash_destroy(struct hash* hash)
437{
438 if(hash)
439 {
440 if(hash->array)
441 {
442 free(hash->array);
443 }
444 if(hash->elems_pool)
445 {
446 pool_destroy(hash->elems_pool);
447 }
448 free(hash);
449 }
450}
451
452static struct hash* hash_create(unsigned int size)
453{
454struct hash* hash;
455
456 assert(size > 0)((size > 0) ? (void) (0) : __assert_fail ("size > 0", "/usr/local/src/libreoffice/solenv/bin/concat-deps.c"
, 456, __PRETTY_FUNCTION__))
;
457 hash = calloc(1, sizeof(struct hash));
458 if(hash)
459 {
460 size += (size >> 2) + 1; /* ~ 75% load factor */
461 if(size >= 15)
462 {
463 hash->size = (((unsigned int)0xFFFFFFFF) >> clz__builtin_clz((unsigned int)size));
464 }
465 else
466 {
467 hash->size = size = 15;
468 }
469 hash->load_limit = hash->size - (hash->size >> 2);
470 hash->used = 0;
471 hash->array = (struct hash_elem**)calloc(hash->size + 1, sizeof(struct hash_elem*));
472 if(hash->array == NULL((void*)0))
473 {
474 hash_destroy(hash);
475 hash = NULL((void*)0);
476 }
477 }
478 if(hash)
479 {
480 hash->elems_pool = pool_create(sizeof(struct hash_elem),
481 0, size, size << 1);
482 if(!hash->elems_pool)
483 {
484 hash_destroy(hash);
485 hash = NULL((void*)0);
486 }
487 }
488 return hash;
489}
490
491static void hash_resize(struct hash* hash)
492{
493unsigned int old_size = hash->size;
494unsigned int hashed;
495struct hash_elem* hash_elem;
496struct hash_elem* next;
497struct hash_elem** array;
498int i;
499
500 hash->size = (old_size << 1) + 1;
501 /* we really should avoid to get there... so print a message to alert of the condition */
502 fprintf(stderrstderr, "resize hash %d -> %d\n", old_size, hash->size);
503 if(hash->size == old_size)
504 {
505 hash->flags |= HASH_F_NO_RESIZE(1<<0);
506 return;
507 }
508 array = calloc(hash->size + 1, sizeof(struct hash_elem*));
509 if(array)
510 {
511 hash->load_limit = hash->size - (hash->size >> 2);
512 for(i=0; i <= old_size; i++)
513 {
514 hash_elem = (struct hash_elem*)hash->array[i];
515 while(hash_elem)
516 {
517 next = hash_elem->next;
518
519 hashed = hash_compute(hash, hash_elem->key, hash_elem->key_len);
520 hash_elem->next = array[hashed];
521 array[hashed] = hash_elem;
522 hash_elem = next;
523 }
524 }
525 free(hash->array);
526 hash->array = (struct hash_elem**)array;
527 }
528 else
529 {
530 hash->size = old_size;
531 hash->flags |= HASH_F_NO_RESIZE(1<<0);
532 }
533}
534
535#ifdef HASH_STAT
536static inline int compare_key(struct hash* hash, const char* a, const char* b, int len, int* cost)memcmp(const char* a,const char* b,int len)
537{
538 *cost += 1;
539 hash->memcmp += 1;
540 return memcmp(a,b, len);
541}
542#else
543#define compare_key(h,a,b,l,c)memcmp(a,b,l) memcmp(a,b,l)
544#endif
545
546/* a customized hash_store function that just store the key and return
547 * TRUE if the key was effectively stored, or FALSE if the key was already there
548 */
549static int hash_store(struct hash* hash, const char* key, int key_len)
550{
551unsigned int hashed;
552struct hash_elem* hash_elem;
553int cost = 0;
554
555 hashed = hash_compute(hash, key, key_len);
32
Calling 'hash_compute'
556#ifdef HASH_STAT
557 hash->stored += 1;
558#endif
559 hash_elem = (struct hash_elem*)hash->array[hashed];
560 while(hash_elem && (hash_elem->key_len != key_len || compare_key(hash, hash_elem->key, key, key_len, &cost)memcmp(hash_elem->key,key,key_len)))
561 {
562 hash_elem = hash_elem->next;
563 }
564
565 if(!hash_elem)
566 {
567 hash_elem = pool_alloc(hash->elems_pool);
568 if(hash_elem)
569 {
570 hash_elem->key = key;
571 hash_elem->key_len = key_len;
572 hash_elem->next = hash->array[hashed];
573
574#ifdef HASH_STAT
575 if(hash_elem->next)
576 {
577 hash->collisions += 1;
578 hash->cost += cost;
579 }
580#endif
581 hash->array[hashed] = hash_elem;
582 hash->used += 1;
583 if(hash->used > hash->load_limit)
584 {
585 hash_resize(hash);
586 }
587 }
588 return TRUE1;
589 }
590 return FALSE0;
591}
592
593static int file_stat(const char* name, struct stat* buffer_stat, int* rc)
594{
595int rc_local = 0;
596
597 rc_local = stat(name, buffer_stat);
598 if (rc_local < 0)
599 {
600 *rc = errno(*__errno_location ());
601 }
602 return rc_local;
603}
604
605static off_t file_get_size(const char* name, int* rc)
606{
607struct stat buffer_stat;
608off_t size = -1;
609
610 if (!file_stat(name, &buffer_stat, rc))
611 {
612 if(S_ISREG(buffer_stat.st_mode)((((buffer_stat.st_mode)) & 0170000) == (0100000)))
613 {
614 size = buffer_stat.st_size;
615 }
616 else
617 {
618 *rc = EINVAL22;
619 }
620 }
621 return size;
622}
623
624static char* file_load(const char* name, off_t* size, int* return_rc)
625{
626off_t local_size = 0;
627int rc = 0;
628char* buffer = NULL((void*)0);
629int fd;
630
631 assert(name != NULL)((name != ((void*)0)) ? (void) (0) : __assert_fail ("name != ((void*)0)"
, "/usr/local/src/libreoffice/solenv/bin/concat-deps.c", 631,
__PRETTY_FUNCTION__))
;
632
633 if(!size)
634 {
635 size = &local_size;
636 }
637 *size = file_get_size(name, &rc);
638 if (!rc)
639 {
640 fd = open(name, FILE_O_RDONLY00 | FILE_O_BINARY0);
641 if (!(fd == -1))
642 {
643 buffer = malloc((size_t)(*size + 1));
644 if (buffer == NULL((void*)0))
645 {
646 rc = ENOMEM12;
647 }
648 else
649 {
650 ssize_t i;
651
652 REDO:
653 i = read(fd, buffer, (size_t)(*size));
654 if(i == -1)
655 {
656 if(errno(*__errno_location ()) == EINTR4)
657 {
658 goto REDO;
659 }
660 else
661 {
662 rc = errno(*__errno_location ());
663 }
664 }
665 else
666 {
667 if (i != *size)
668 {
669 rc = EIO5;
670 }
671 }
672 close(fd);
673 buffer[*size] = 0;
674 }
675 }
676 }
677
678 if(rc && buffer)
679 {
680 free(buffer);
681 buffer = NULL((void*)0);
682 }
683 if(return_rc)
684 {
685 *return_rc = rc;
686 }
687 return buffer;
688}
689
690static void _cancel_relative(char* base, char** ref_cursor, char** ref_cursor_out, char* end)
691{
692 char* cursor = *ref_cursor;
693 char* cursor_out = *ref_cursor_out;
694
695 do
696 {
697 cursor += 3;
698 while(cursor_out > base && cursor_out[-1] == '/')
699 cursor_out--;
700 while(cursor_out > base && *--cursor_out != '/');
701 }
702 while(cursor + 3 < end && !memcmp(cursor, "/../", 4));
703 *ref_cursor = cursor;
704 *ref_cursor_out = cursor_out;
705}
706
707static inline void eat_space(char ** token)
708{
709 while ((' ' == **token) || ('\t' == **token)) {
710 ++(*token);
711 }
712}
713
714/* prefix paths to absolute */
715static inline void print_fullpaths(char* line)
716{
717char* token;
718char* end;
719
720 token = line;
721 eat_space(&token);
722 while (*token)
723 {
724 end = token;
725 while (*end && (' ' != *end) && ('\t' != *end)) {
726 ++end;
727 }
728 if(*token == ':' || *token == '\\' || *token == '/' || *token == '$'
729 || ':' == token[1])
730 {
731 fwrite(token, end - token, 1, stdoutstdout);
732 }
733 else
734 {
735 fputs(base_dir_var, stdoutstdout);
736 fputc('/', stdoutstdout);
737 fwrite(token, end - token, 1, stdoutstdout);
738 }
739 fputc(' ', stdoutstdout);
740 token = end;
741 eat_space(&token);
742 }
743}
744
745static int _process(struct hash* dep_hash, char* fn)
746{
747int rc;
748char* buffer;
749char* end;
750char* cursor;
751char* cursor_out;
752char* base;
753int continuation = 0;
754char last_ns = 0;
755off_t size;
756
757 buffer = file_load(fn, &size, &rc);
758 /* Note: yes we are going to leak 'buffer'
759 * this is on purpose, to avoid cloning the 'key' out of it
760 * and our special 'hash' just store the pointer to the key
761 * inside of buffer, hence it need to remain allocated
762 */
763 if(!rc)
14
Taking true branch
764 {
765 base = cursor_out = cursor = end = buffer;
766 end += size;
767 while(cursor < end)
15
Loop condition is true. Entering loop body
19
Loop condition is true. Entering loop body
23
Loop condition is true. Entering loop body
28
Loop condition is false. Execution continues on line 837
768 {
769 if(*cursor == '\\')
16
Taking false branch
20
Taking false branch
24
Taking false branch
770 {
771 continuation = 1;
772 *cursor_out++ = *cursor++;
773 }
774 else if(*cursor == '/')
17
Taking false branch
21
Taking false branch
25
Taking false branch
775 {
776 if(cursor + 3 < end)
777 {
778 if(!memcmp(cursor, "/../", 4))
779 {
780 _cancel_relative(base, &cursor, &cursor_out, end);
781 }
782 }
783 *cursor_out++ = *cursor++;
784 }
785 else if(*cursor == '\n')
18
Taking false branch
22
Taking false branch
26
Taking false branch
786 {
787 if(!continuation)
788 {
789 *cursor_out = 0;
790 if(base < cursor)
791 {
792 /* here we have a complete rule */
793 if(last_ns == ':')
794 {
795 /* if the rule ended in ':' that is a no-dep rule
796 * these are the one for which we want to filter
797 * duplicate out
798 */
799 if(hash_store(dep_hash, base, (int)(cursor_out - base)))
800 {
801 /* DO NOT modify base after it has been added
802 as key by hash_store */
803 print_fullpaths(base);
804 putc('\n', stdout)_IO_putc ('\n', stdout);
805 }
806 }
807 else
808 {
809 /* rule with dep, just write it */
810 print_fullpaths(base);
811 putc('\n', stdout)_IO_putc ('\n', stdout);
812 }
813 }
814 cursor += 1;
815 base = cursor_out = cursor;
816 }
817 else
818 {
819 /* here we have a '\' followed by \n this is a continuation
820 * i.e not a complete rule yet
821 */
822 *cursor_out++ = *cursor++;
823 }
824 }
825 else
826 {
827 continuation = 0;
828 /* not using isspace() here save 25% of I refs and 75% of D refs based on cachegrind */
829 if(*cursor != ' ' && *cursor != '\n' && *cursor != '\t' )
27
Taking true branch
830 {
831 last_ns = *cursor;
832 }
833 *cursor_out++ = *cursor++;
834 }
835 }
836 /* just in case the file did not end with a \n, there may be a pending rule */
837 if(base < cursor_out)
29
Taking true branch
838 {
839 if(last_ns == ':')
30
Taking true branch
840 {
841 if(hash_store(dep_hash, base, (int)(cursor_out - base)))
31
Calling 'hash_store'
842 {
843 puts(base);
844 putc('\n', stdout)_IO_putc ('\n', stdout);
845 }
846 }
847 else
848 {
849 puts(base);
850 putc('\n', stdout)_IO_putc ('\n', stdout);
851 }
852 }
853 }
854 return rc;
855}
856
857static void _usage(void)
858{
859 fputs("Usage: concat-deps <file that contains dep_files>\n", stderrstderr);
860}
861
862#define kDEFAULT_HASH_SIZE4096 4096
863
864int main(int argc, char** argv)
865{
866int rc = 0;
867off_t in_list_size = 0;
868char* in_list;
869char* in_list_cursor;
870char* in_list_base;
871struct hash* dep_hash;
872
873 if(argc < 2)
1
Taking false branch
874 {
875 _usage();
876 return 1;
877 }
878 base_dir = getenv("SRCDIR");
879 if(!base_dir)
2
Taking false branch
880 {
881 fputs("Error: SRCDIR is missing in the environement\n", stderrstderr);
882 return 1;
883 }
884
885 in_list = file_load(argv[1], &in_list_size, &rc);
886 if(!rc)
3
Taking true branch
887 {
888 dep_hash = hash_create( kDEFAULT_HASH_SIZE4096);
889 in_list_base = in_list_cursor = in_list;
890
891 /* extract filename of dep file from a 'space' separated list */
892 while(*in_list_cursor)
4
Loop condition is true. Entering loop body
6
Loop condition is true. Entering loop body
8
Loop condition is true. Entering loop body
10
Loop condition is true. Entering loop body
893 {
894 if(*in_list_cursor == ' ' || *in_list_cursor == '\n')
5
Taking false branch
7
Taking false branch
9
Taking false branch
11
Taking true branch
895 {
896 *in_list_cursor = 0;
897 if(in_list_base < in_list_cursor)
12
Taking true branch
898 {
899 rc = _process(dep_hash, in_list_base);
13
Calling '_process'
900 if(rc)
901 {
902 break;
903 }
904 }
905 in_list_cursor += 1;
906 in_list_base = in_list_cursor;
907 }
908 else
909 {
910 in_list_cursor += 1;
911 }
912 }
913 if(!rc)
914 {
915 /* catch the last entry in case the input did not terminate with a 'space' */
916 if(in_list_base < in_list_cursor)
917 {
918 rc = _process(dep_hash, in_list_base);
919 }
920 }
921#ifdef HASH_STAT
922 fprintf(stderrstderr, "stats: u:%d s:%d l:%d t:%d c:%d m:%d $:%d\n",
923 dep_hash->used, dep_hash->size, dep_hash->load_limit, dep_hash->stored,
924 dep_hash->collisions, dep_hash->memcmp, dep_hash->cost);
925#endif
926 }
927 return rc;
928}
929
930/* vim:set shiftwidth=4 softtabstop=4 expandtab: */