Bug Summary

File:solenv/bin/concat-deps.c
Location:line 892, column 15
Description:Dereference of null pointer (loaded from variable 'in_list_cursor')

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)
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)
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)
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;
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;
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);
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)
764 {
765 base = cursor_out = cursor = end = buffer;
766 end += size;
767 while(cursor < end)
768 {
769 if(*cursor == '\\')
770 {
771 continuation = 1;
772 *cursor_out++ = *cursor++;
773 }
774 else if(*cursor == '/')
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')
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' )
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)
838 {
839 if(last_ns == ':')
840 {
841 if(hash_store(dep_hash, base, (int)(cursor_out - base)))
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
Dereference of null pointer (loaded from variable 'in_list_cursor')
893 {
894 if(*in_list_cursor == ' ' || *in_list_cursor == '\n')
895 {
896 *in_list_cursor = 0;
897 if(in_list_base < in_list_cursor)
898 {
899 rc = _process(dep_hash, in_list_base);
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: */