Bug Summary

File:solenv/bin/concat-deps.c
Location:line 1037, 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__) || defined(__FreeBSD_kernel__)
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
112int internal_boost = 0;
113static char* base_dir;
114static char* out_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 /* we already have an extent, so this is a secondary */
170 if(pool->secondary)
171 {
172 size = pool->secondary;
173 }
174 }
175 else
176 {
177 assert(pool->primary)((pool->primary) ? (void) (0) : __assert_fail ("pool->primary"
, "/usr/local/src/libreoffice/solenv/bin/concat-deps.c", 177,
__PRETTY_FUNCTION__))
;
178 size = pool->primary;
179 }
180 if(size)
181 {
182 extent = malloc(size);
183 if(extent)
184 {
185 *(void**)extent = pool->extent;
186 pool->extent = extent;
187 if(allocate)
188 {
189 data = ((char*)extent) + POOL_ALIGN_INCREMENT8;
190 pool->fresh = ((char*)data) + pool->size_elem;
191 pool->tail = pool->fresh + (size - pool->size_elem);
192 }
193 else
194 {
195 pool->fresh = ((char*)extent) + POOL_ALIGN_INCREMENT8;
196 pool->tail = pool->fresh + (size - pool->size_elem);
197 }
198 }
199 }
200 return data;
201}
202
203/* Create a memory pool for fix size objects
204 * this is a simplified implementation that
205 * is _not_ thread safe.
206 */
207struct pool* pool_create(int size_elem, int flags, int primary, int secondary)
208{
209struct pool* pool;
210
211 assert(primary > 0)((primary > 0) ? (void) (0) : __assert_fail ("primary > 0"
, "/usr/local/src/libreoffice/solenv/bin/concat-deps.c", 211,
__PRETTY_FUNCTION__))
;
212 assert(secondary >= 0)((secondary >= 0) ? (void) (0) : __assert_fail ("secondary >= 0"
, "/usr/local/src/libreoffice/solenv/bin/concat-deps.c", 212,
__PRETTY_FUNCTION__))
;
213 assert(size_elem > 0)((size_elem > 0) ? (void) (0) : __assert_fail ("size_elem > 0"
, "/usr/local/src/libreoffice/solenv/bin/concat-deps.c", 213,
__PRETTY_FUNCTION__))
;
214
215 pool = (struct pool*)calloc(1, sizeof(struct pool));
216 if(!pool) return NULL((void*)0);
217 /* Adjust the element size so that it be aligned, and so that an element could
218 * at least contain a void*
219 */
220 pool->size_elem = size_elem = (size_elem + POOL_ALIGN_INCREMENT8 - 1) & ~(POOL_ALIGN_INCREMENT8 - 1);
221
222 pool->primary = (size_elem * primary) + POOL_ALIGN_INCREMENT8;
223 pool->secondary = secondary > 0 ? (size_elem * secondary) + POOL_ALIGN_INCREMENT8 : 0;
224 pool_take_extent(pool, FALSE0);
225
226 return pool;
227
228}
229
230void pool_destroy(struct pool* pool)
231{
232void* extent;
233void* next;
234
235 if(pool != NULL((void*)0))
236 {
237 extent = pool->extent;
238 while(extent)
239 {
240 next = *(void**)extent;
241 free(extent);
242 extent = next;
243 }
244 free(pool);
245 }
246}
247
248static inline void* pool_alloc(struct pool* pool)
249{
250void* data;
251
252 data = pool->head_free;
253 if(data == NULL((void*)0))
254 {
255 /* we have no old-freed elem */
256 if(pool->fresh <= pool->tail)
257 {
258 /* pick a slice of the current extent */
259 data = (void*)pool->fresh;
260 pool->fresh += pool->size_elem;
261 }
262 else
263 {
264 /* allocate a new extent */
265 data = pool_take_extent(pool, TRUE1);
266 }
267 }
268 else
269 {
270 /* re-used old freed element by chopipng the head of the free list */
271 pool->head_free = *(void**)data;
272 }
273
274 return data;
275}
276
277
278static inline void pool_free(struct pool* pool, void* data)
279{
280 assert(pool && data)((pool && data) ? (void) (0) : __assert_fail ("pool && data"
, "/usr/local/src/libreoffice/solenv/bin/concat-deps.c", 280,
__PRETTY_FUNCTION__))
;
281
282 /* stack on top of the free list */
283 *(void**)data = pool->head_free;
284 pool->head_free = data;
285}
286
287
288/* ===============================================
289 * Hash implementation custumized to be just tracking
290 * a unique list of string (i.e no data associated
291 * with the key, no need for retrieval, etc..
292 *
293 * This is tuned for the particular use-case we have here
294 * measures in tail_build showed that
295 * we can get north of 4000 distinct values stored in a hash
296 * the collision rate is at worse around 2%
297 * the collision needing an expensive memcmp to resolve
298 * have a rate typically at 1 per 1000
299 * for tail_build we register 37229 unique key
300 * with a total of 377 extra memcmp needed
301 * which is completely negligible compared to the
302 * number of memcmp required to eliminate duplicate
303 * entry (north of 2.5 millions for tail_build)
304 * ===============================================
305 */
306
307struct hash_elem
308{
309 struct hash_elem* next;
310 const char* key;
311 int key_len;
312};
313
314struct hash
315{
316 struct hash_elem** array;
317 struct pool* elems_pool;
318 int flags;
319 unsigned int used;
320 unsigned int size;
321 unsigned int load_limit;
322#ifdef HASH_STAT
323 int stored;
324 int collisions;
325 int cost;
326 int memcmp;
327#endif
328};
329#define HASH_F_NO_RESIZE(1<<0) (1<<0)
330
331/* The following hash_compute function was adapted from :
332 * lookup3.c, by Bob Jenkins, May 2006, Public Domain.
333 *
334 * The changes from the original are mostly cosmetic
335 */
336#define hashsize(n)(1<<(n)) (1<<(n))
337#define hashmask(n)((1<<(n))-1) (hashsize(n)(1<<(n))-1)
338#define rot(x,k)(((x)<<(k)) | ((x)>>(32 -(k)))) (((x)<<(k)) | ((x)>>(32-(k))))
339
340
341#if CORE_BIG_ENDIAN0
342#define MASK_C10xFFFFFF 0xFFFFFF00
343#define MASK_C20xFFFF 0xFFFF0000
344#define MASK_C30xFF 0xFF000000
345#else
346#if CORE_LITTLE_ENDIAN1
347#define MASK_C10xFFFFFF 0xFFFFFF
348#define MASK_C20xFFFF 0xFFFF
349#define MASK_C30xFF 0xFF
350#else
351#error "Missing Endianness definition"
352#endif
353#endif
354
355
356#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; }
\
357{ \
358 a -= c; a ^= rot(c, 4)(((c)<<(4)) | ((c)>>(32 -(4)))); c += b; \
359 b -= a; b ^= rot(a, 6)(((a)<<(6)) | ((a)>>(32 -(6)))); a += c; \
360 c -= b; c ^= rot(b, 8)(((b)<<(8)) | ((b)>>(32 -(8)))); b += a; \
361 a -= c; a ^= rot(c,16)(((c)<<(16)) | ((c)>>(32 -(16)))); c += b; \
362 b -= a; b ^= rot(a,19)(((a)<<(19)) | ((a)>>(32 -(19)))); a += c; \
363 c -= b; c ^= rot(b, 4)(((b)<<(4)) | ((b)>>(32 -(4)))); b += a; \
364}
365#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)))); }
\
366{ \
367 c ^= b; c -= rot(b,14)(((b)<<(14)) | ((b)>>(32 -(14)))); \
368 a ^= c; a -= rot(c,11)(((c)<<(11)) | ((c)>>(32 -(11)))); \
369 b ^= a; b -= rot(a,25)(((a)<<(25)) | ((a)>>(32 -(25)))); \
370 c ^= b; c -= rot(b,16)(((b)<<(16)) | ((b)>>(32 -(16)))); \
371 a ^= c; a -= rot(c,4)(((c)<<(4)) | ((c)>>(32 -(4)))); \
372 b ^= a; b -= rot(a,14)(((a)<<(14)) | ((a)>>(32 -(14)))); \
373 c ^= b; c -= rot(b,24)(((b)<<(24)) | ((b)>>(32 -(24)))); \
374}
375
376static unsigned int hash_compute( struct hash* hash, const char* key, int length)
377{
378 unsigned int a;
379 unsigned int b;
380 unsigned int c; /* internal state */
381 const unsigned char* uk = (const unsigned char*)key;
382
383 /* Set up the internal state */
384 a = b = c = 0xdeadbeef + (length << 2);
385
386 /* we use this to 'hash' full path with mostly a common root
387 * let's now waste too much cycles hashing mostly constant stuff
388 */
389 if(length > 36)
390 {
391 uk += length - 36;
392 length = 36;
393 }
394 /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
395 while (length > 12)
396 {
397 a += get_unaligned_uint(uk)(*(unsigned int*)(uk));
398 b += get_unaligned_uint(uk+4)(*(unsigned int*)(uk+4));
399 c += get_unaligned_uint(uk+8)(*(unsigned int*)(uk+8));
400 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; }
;
401 length -= 12;
402 uk += 12;
403 }
404
405 /*----------------------------- handle the last (probably partial) block */
406 /* Note: we possibly over-read, which would trigger complaint from VALGRIND
407 * but we mask the undefined stuff if any, so we are still good, thanks
408 * to alignment of memory allocation and tail-memory managment overhead
409 * we always can read 3 bytes past the official end without triggering
410 * a segfault -- if you find a platform/compiler couple for which that postulat
411 * is false, then you just need to over-allocate by 2 more bytes in file_load()
412 * file_load already over-allocate by 1 to sitck a \0 at the end of the buffer.
413 */
414 switch(length)
415 {
416 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;
417 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;
418 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;
419 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;
420 case 8 : b+=get_unaligned_uint(uk+4)(*(unsigned int*)(uk+4)); a+=get_unaligned_uint(uk)(*(unsigned int*)(uk)); break;
421 case 7 : b+=get_unaligned_uint(uk+4)(*(unsigned int*)(uk+4)) & MASK_C10xFFFFFF; a+=get_unaligned_uint(uk)(*(unsigned int*)(uk)); break;
422 case 6 : b+=get_unaligned_uint(uk+4)(*(unsigned int*)(uk+4)) & MASK_C20xFFFF; a+=get_unaligned_uint(uk)(*(unsigned int*)(uk)); break;
423 case 5 : b+=get_unaligned_uint(uk+4)(*(unsigned int*)(uk+4)) & MASK_C30xFF; a+=get_unaligned_uint(uk)(*(unsigned int*)(uk)); break;
424 case 4 : a+=get_unaligned_uint(uk)(*(unsigned int*)(uk)); break;
425 case 3 : a+=get_unaligned_uint(uk)(*(unsigned int*)(uk)) & MASK_C10xFFFFFF; break;
426 case 2 : a+=get_unaligned_uint(uk)(*(unsigned int*)(uk)) & MASK_C20xFFFF; break;
427 case 1 : a+=get_unaligned_uint(uk)(*(unsigned int*)(uk)) & MASK_C30xFF; break;
428 case 0 : return c & hash->size; /* zero length strings require no mixing */
429 }
430
431 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)))); }
;
432 return c & hash->size;
433}
434
435static void hash_destroy(struct hash* hash)
436{
437 if(hash)
438 {
439 if(hash->array)
440 {
441 free(hash->array);
442 }
443 if(hash->elems_pool)
444 {
445 pool_destroy(hash->elems_pool);
446 }
447 free(hash);
448 }
449}
450
451static struct hash* hash_create(unsigned int size)
452{
453struct hash* hash;
454
455 assert(size > 0)((size > 0) ? (void) (0) : __assert_fail ("size > 0", "/usr/local/src/libreoffice/solenv/bin/concat-deps.c"
, 455, __PRETTY_FUNCTION__))
;
456 hash = calloc(1, sizeof(struct hash));
457 if(hash)
458 {
459 size += (size >> 2) + 1; /* ~ 75% load factor */
460 if(size >= 15)
461 {
462 hash->size = (((unsigned int)0xFFFFFFFF) >> clz__builtin_clz((unsigned int)size));
463 }
464 else
465 {
466 hash->size = size = 15;
467 }
468 hash->load_limit = hash->size - (hash->size >> 2);
469 hash->used = 0;
470 hash->array = (struct hash_elem**)calloc(hash->size + 1, sizeof(struct hash_elem*));
471 if(hash->array == NULL((void*)0))
472 {
473 hash_destroy(hash);
474 hash = NULL((void*)0);
475 }
476 }
477 if(hash)
478 {
479 hash->elems_pool = pool_create(sizeof(struct hash_elem),
480 0, size, size << 1);
481 if(!hash->elems_pool)
482 {
483 hash_destroy(hash);
484 hash = NULL((void*)0);
485 }
486 }
487 return hash;
488}
489
490static void hash_resize(struct hash* hash)
491{
492unsigned int old_size = hash->size;
493unsigned int hashed;
494struct hash_elem* hash_elem;
495struct hash_elem* next;
496struct hash_elem** array;
497int i;
498
499 hash->size = (old_size << 1) + 1;
500 /* we really should avoid to get there... so print a message to alert of the condition */
501 fprintf(stderrstderr, "resize hash %d -> %d\n", old_size, hash->size);
502 if(hash->size == old_size)
503 {
504 hash->flags |= HASH_F_NO_RESIZE(1<<0);
505 return;
506 }
507 array = calloc(hash->size + 1, sizeof(struct hash_elem*));
508 if(array)
509 {
510 hash->load_limit = hash->size - (hash->size >> 2);
511 for(i=0; i <= old_size; i++)
512 {
513 hash_elem = (struct hash_elem*)hash->array[i];
514 while(hash_elem)
515 {
516 next = hash_elem->next;
517
518 hashed = hash_compute(hash, hash_elem->key, hash_elem->key_len);
519 hash_elem->next = array[hashed];
520 array[hashed] = hash_elem;
521 hash_elem = next;
522 }
523 }
524 free(hash->array);
525 hash->array = (struct hash_elem**)array;
526 }
527 else
528 {
529 hash->size = old_size;
530 hash->flags |= HASH_F_NO_RESIZE(1<<0);
531 }
532}
533
534#ifdef HASH_STAT
535static 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)
536{
537 *cost += 1;
538 hash->memcmp += 1;
539 return memcmp(a,b, len);
540}
541#else
542#define compare_key(h,a,b,l,c)memcmp(a,b,l) memcmp(a,b,l)
543#endif
544
545/* a customized hash_store function that just store the key and return
546 * TRUE if the key was effectively stored, or FALSE if the key was already there
547 */
548static int hash_store(struct hash* hash, const char* key, int key_len)
549{
550unsigned int hashed;
551struct hash_elem* hash_elem;
552int cost = 0;
553
554 hashed = hash_compute(hash, key, key_len);
555#ifdef HASH_STAT
556 hash->stored += 1;
557#endif
558 hash_elem = (struct hash_elem*)hash->array[hashed];
559 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)))
560 {
561 hash_elem = hash_elem->next;
562 }
563
564 if(!hash_elem)
565 {
566 hash_elem = pool_alloc(hash->elems_pool);
567 if(hash_elem)
568 {
569 hash_elem->key = key;
570 hash_elem->key_len = key_len;
571 hash_elem->next = hash->array[hashed];
572
573#ifdef HASH_STAT
574 if(hash_elem->next)
575 {
576 hash->collisions += 1;
577 hash->cost += cost;
578 }
579#endif
580 hash->array[hashed] = hash_elem;
581 hash->used += 1;
582 if(hash->used > hash->load_limit)
583 {
584 hash_resize(hash);
585 }
586 }
587 return TRUE1;
588 }
589 return FALSE0;
590}
591
592static int file_stat(const char* name, struct stat* buffer_stat, int* rc)
593{
594int rc_local = 0;
595
596 rc_local = stat(name, buffer_stat);
597 if (rc_local < 0)
598 {
599 *rc = errno(*__errno_location ());
600 }
601 return rc_local;
602}
603
604static off_t file_get_size(const char* name, int* rc)
605{
606struct stat buffer_stat;
607off_t size = -1;
608
609 if (!file_stat(name, &buffer_stat, rc))
610 {
611 if(S_ISREG(buffer_stat.st_mode)((((buffer_stat.st_mode)) & 0170000) == (0100000)))
612 {
613 size = buffer_stat.st_size;
614 }
615 else
616 {
617 *rc = EINVAL22;
618 }
619 }
620 return size;
621}
622
623static char* file_load(const char* name, off_t* size, int* return_rc)
624{
625off_t local_size = 0;
626int rc = 0;
627char* buffer = NULL((void*)0);
628int fd;
629
630 assert(name != NULL)((name != ((void*)0)) ? (void) (0) : __assert_fail ("name != ((void*)0)"
, "/usr/local/src/libreoffice/solenv/bin/concat-deps.c", 630,
__PRETTY_FUNCTION__))
;
631
632 if(!size)
633 {
634 size = &local_size;
635 }
636 *size = file_get_size(name, &rc);
637 if (!rc)
638 {
639 fd = open(name, FILE_O_RDONLY00 | FILE_O_BINARY0);
640 if (!(fd == -1))
641 {
642 buffer = malloc((size_t)(*size + 1));
643 if (buffer == NULL((void*)0))
644 {
645 rc = ENOMEM12;
646 }
647 else
648 {
649 ssize_t i;
650
651 REDO:
652 i = read(fd, buffer, (size_t)(*size));
653 if(i == -1)
654 {
655 if(errno(*__errno_location ()) == EINTR4)
656 {
657 goto REDO;
658 }
659 else
660 {
661 rc = errno(*__errno_location ());
662 }
663 }
664 else
665 {
666 if (i != *size)
667 {
668 rc = EIO5;
669 }
670 }
671 close(fd);
672 buffer[*size] = 0;
673 }
674 }
675 }
676
677 if(rc && buffer)
678 {
679 free(buffer);
680 buffer = NULL((void*)0);
681 }
682 if(return_rc)
683 {
684 *return_rc = rc;
685 }
686 return buffer;
687}
688
689static void _cancel_relative(char* base, char** ref_cursor, char** ref_cursor_out, char* end)
690{
691 char* cursor = *ref_cursor;
692 char* cursor_out = *ref_cursor_out;
693
694 do
695 {
696 cursor += 3;
697 while(cursor_out > base && cursor_out[-1] == '/')
698 cursor_out--;
699 while(cursor_out > base && *--cursor_out != '/');
700 }
701 while(cursor + 3 < end && !memcmp(cursor, "/../", 4));
702 *ref_cursor = cursor;
703 *ref_cursor_out = cursor_out;
704}
705
706static inline void eat_space(char ** token)
707{
708 while ((' ' == **token) || ('\t' == **token)) {
709 ++(*token);
710 }
711}
712
713/*
714 * Prune LibreOffice specific duplicate dependencies to improve
715 * gnumake startup time, and shrink the disk-space footprint.
716 */
717static inline int
718elide_dependency(const char* key, int key_len,
719 int *boost_count, const char **unpacked_end)
720{
721#if 0
722 {
723 int i;
724 fprintf (stderrstderr, "elide?%d!: '", internal_boost);
725 for (i = 0; i < key_len; i++) {
726 fprintf (stderrstderr, "%c", key[i]);
727 }
728 fprintf (stderrstderr, "'\n");
729 }
730#endif
731
732 /* .hdl files are always matched by .hpp */
733 if (key_len > 4 && !strncmp(key + key_len - 4, ".hdl", 4))
734 return 1;
735
736 /* boost brings a plague of header files */
737 int i;
738 int boost = 0;
739 int unpacked = 0;
740 /* walk down path elements */
741 for (i = 0; i < key_len - 1; i++)
742 {
743 if (key[i] == '/')
744 {
745 if (internal_boost)
746 {
747 if (0 == boost)
748 {
749 if (!strncmp(key + i + 1, "solver/", 7))
750 {
751 boost++;
752 continue;
753 }
754 }
755 else if (!strncmp(key + i + 1, "inc/external/boost/", 19))
756 {
757 if (boost_count)
758 (*boost_count)++;
759 return 1;
760 }
761 }
762 if (0 == unpacked)
763 {
764 if (!strncmp(key + i + 1, "workdir/", 8))
765 {
766 unpacked = 1;
767 continue;
768 }
769 }
770 else
771 {
772 if (!strncmp(key + i + 1, "UnpackedTarball/", 16))
773 {
774 if (unpacked_end)
775 *unpacked_end = strchr(key + i + 17, '/');
776 return 1;
777 }
778 }
779 }
780 }
781
782 return 0;
783}
784
785/*
786 * We collapse tens of internal boost headers to a single one, such
787 * that you can re-compile / install boost and all is well.
788 */
789static void emit_single_boost_header(void)
790{
791#define BOOST_HEADER"/inc/external/boost/bind.hpp" "/inc/external/boost/bind.hpp"
792 fprintf(stdoutstdout, "%s" BOOST_HEADER"/inc/external/boost/bind.hpp" " ", out_dir);
793}
794
795static void emit_unpacked_target(char const*const token, char const*const end)
796{
797 /* is there some obvious way to printf N characters that i'm missing? */
798 size_t size = end - token + 1;
799 char tmp[size];
800 snprintf(tmp, size, "%s", token);
801 fputs(tmp, stdoutstdout);
802 fputs(".done ", stdoutstdout);
803}
804
805/* prefix paths to absolute */
806static inline void print_fullpaths(char* line)
807{
808 char* token;
809 char* end;
810 int boost_count = 0;
811 const char * unpacked_end = 0; /* end of UnpackedTarget match (if any) */
812 int first = 1; /* for UnpackedTarget the first (target) is GenCxxObject! */
813
814 token = line;
815 eat_space(&token);
816 while (*token)
817 {
818 end = token;
819 while (*end && (' ' != *end) && ('\t' != *end)) {
820 ++end;
821 }
822 int token_len = end - token;
823 if (!first &&
824 elide_dependency(token, token_len, &boost_count, &unpacked_end))
825 {
826 if (unpacked_end)
827 {
828 emit_unpacked_target(token, unpacked_end);
829 unpacked_end = 0;
830 }
831 else if (boost_count == 1)
832 emit_single_boost_header();
833 else
834 {
835 /* don't output, and swallow trailing \\\n if any */
836 token = end;
837 eat_space(&token);
838 if (token[0] == '\\' && token[1] == '\n')
839 end = token + 2;
840 }
841 }
842 else if(*token == ':' || *token == '\\' || *token == '/' ||
843 *token == '$' || ':' == token[1])
844 {
845 if(fwrite(token, token_len, 1, stdoutstdout) != 1)
846 abort();
847 fputc(' ', stdoutstdout);
848 }
849 else
850 {
851 if(fwrite(token, end - token, 1, stdoutstdout) != 1)
852 abort();
853 fputc(' ', stdoutstdout);
854 }
855 first = 0;
856 token = end;
857 eat_space(&token);
858 }
859}
860
861static inline char * eat_space_at_end(char * end)
862{
863 assert('\0' == *end)(('\0' == *end) ? (void) (0) : __assert_fail ("'\\0' == *end"
, "/usr/local/src/libreoffice/solenv/bin/concat-deps.c", 863,
__PRETTY_FUNCTION__))
;
864 char * real_end = end - 1;
865 while (' ' == *real_end || '\t' == *real_end || '\n' == *real_end
866 || ':' == *real_end)
867 { /* eat colon and whitespace at end */
868 --real_end;
869 }
870 return real_end;
871}
872
873static int _process(struct hash* dep_hash, char* fn)
874{
875int rc;
876char* buffer;
877char* end;
878char* cursor;
879char* cursor_out;
880char* base;
881int continuation = 0;
882char last_ns = 0;
883off_t size;
884
885 buffer = file_load(fn, &size, &rc);
886 /* Note: yes we are going to leak 'buffer'
887 * this is on purpose, to avoid cloning the 'key' out of it
888 * and our special 'hash' just store the pointer to the key
889 * inside of buffer, hence it need to remain allocated
890 */
891 if(!rc)
892 {
893 base = cursor_out = cursor = end = buffer;
894 end += size;
895 while(cursor < end)
896 {
897 if(*cursor == '\\')
898 {
899 continuation = 1;
900 *cursor_out++ = *cursor++;
901 }
902 else if(*cursor == '/')
903 {
904 if(cursor + 3 < end)
905 {
906 if(!memcmp(cursor, "/../", 4))
907 {
908 _cancel_relative(base, &cursor, &cursor_out, end);
909 }
910 }
911 *cursor_out++ = *cursor++;
912 }
913 else if(*cursor == '\n')
914 {
915 if(!continuation)
916 {
917 *cursor_out = 0;
918 if(base < cursor)
919 {
920 /* here we have a complete rule */
921 if(last_ns == ':')
922 {
923 /* if the rule ended in ':' that is a no-dep rule
924 * these are the one for which we want to filter
925 * duplicate out
926 */
927 int key_len = eat_space_at_end(cursor_out) - base;
928 if (!elide_dependency(base,key_len + 1, NULL((void*)0), NULL((void*)0))
929 && hash_store(dep_hash, base, key_len))
930 {
931 /* DO NOT modify base after it has been added
932 as key by hash_store */
933 print_fullpaths(base);
934 putc('\n', stdout)_IO_putc ('\n', stdout);
935 }
936 }
937 else
938 {
939 /* rule with dep, just write it */
940 print_fullpaths(base);
941 putc('\n', stdout)_IO_putc ('\n', stdout);
942 }
943 last_ns = ' '; // cannot hurt to reset it
944 }
945 cursor += 1;
946 base = cursor_out = cursor;
947 }
948 else
949 {
950 /* here we have a '\' followed by \n this is a continuation
951 * i.e not a complete rule yet
952 */
953 *cursor_out++ = *cursor++;
954 continuation = 0; // cancel current one (empty lines!)
955 }
956 }
957 else
958 {
959 continuation = 0;
960 /* not using isspace() here save 25% of I refs and 75% of D refs based on cachegrind */
961 if(*cursor != ' ' && *cursor != '\n' && *cursor != '\t' )
962 {
963 last_ns = *cursor;
964 }
965 *cursor_out++ = *cursor++;
966 }
967 }
968 /* just in case the file did not end with a \n, there may be a pending rule */
969 if(base < cursor_out)
970 {
971 if(last_ns == ':')
972 {
973 int key_len = eat_space_at_end(cursor_out) - base;
974 if (!elide_dependency(base,key_len + 1, NULL((void*)0), NULL((void*)0)) &&
975 hash_store(dep_hash, base, key_len))
976 {
977 puts(base);
978 putc('\n', stdout)_IO_putc ('\n', stdout);
979 }
980 }
981 else
982 {
983 puts(base);
984 putc('\n', stdout)_IO_putc ('\n', stdout);
985 }
986 }
987 }
988 return rc;
989}
990
991static void _usage(void)
992{
993 fputs("Usage: concat-deps <file that contains dep_files>\n", stderrstderr);
994}
995
996#define kDEFAULT_HASH_SIZE4096 4096
997
998static int get_var(char **var, const char *name)
999{
1000 *var = (char *)getenv(name);
1001 if(!*var)
1002 {
1003 fprintf(stderrstderr,"Error: %s is missing in the environement\n", name);
1004 return 1;
1005 }
1006 return 0;
1007}
1008
1009int main(int argc, char** argv)
1010{
1011int rc = 0;
1012off_t in_list_size = 0;
1013char* in_list;
1014char* in_list_cursor;
1015char* in_list_base;
1016struct hash* dep_hash;
1017const char *env_str;
1018
1019 if(argc < 2)
1
Assuming 'argc' is >= 2
2
Taking false branch
1020 {
1021 _usage();
1022 return 1;
1023 }
1024 if(get_var(&base_dir, "SRCDIR") || get_var(&out_dir, "OUTDIR"))
3
Taking false branch
1025 return 1;
1026
1027 env_str = getenv("SYSTEM_BOOST");
1028 internal_boost = !env_str || strcmp(env_str,"TRUE");
4
Assuming 'env_str' is non-null
1029
1030 in_list = file_load(argv[1], &in_list_size, &rc);
1031 if(!rc)
5
Taking true branch
1032 {
1033 dep_hash = hash_create( kDEFAULT_HASH_SIZE4096);
1034 in_list_base = in_list_cursor = in_list;
6
Null pointer value stored to 'in_list_cursor'
1035
1036 /* extract filename of dep file from a 'space' separated list */
1037 while(*in_list_cursor)
7
Dereference of null pointer (loaded from variable 'in_list_cursor')
1038 {
1039 if(*in_list_cursor == ' ' || *in_list_cursor == '\n')
1040 {
1041 *in_list_cursor = 0;
1042 if(in_list_base < in_list_cursor)
1043 {
1044 rc = _process(dep_hash, in_list_base);
1045 if(rc)
1046 {
1047 break;
1048 }
1049 }
1050 in_list_cursor += 1;
1051 in_list_base = in_list_cursor;
1052 }
1053 else
1054 {
1055 in_list_cursor += 1;
1056 }
1057 }
1058 if(!rc)
1059 {
1060 /* catch the last entry in case the input did not terminate with a 'space' */
1061 if(in_list_base < in_list_cursor)
1062 {
1063 rc = _process(dep_hash, in_list_base);
1064 }
1065 }
1066#ifdef HASH_STAT
1067 fprintf(stderrstderr, "stats: u:%d s:%d l:%d t:%d c:%d m:%d $:%d\n",
1068 dep_hash->used, dep_hash->size, dep_hash->load_limit, dep_hash->stored,
1069 dep_hash->collisions, dep_hash->memcmp, dep_hash->cost);
1070#endif
1071 }
1072 return rc;
1073}
1074
1075/* vim:set shiftwidth=4 softtabstop=4 expandtab: */