Bug Summary

File:dmake/unix/arlib.c
Location:line 505, column 7
Description:Access to field 'lb_name' results in a dereference of a null pointer (loaded from variable 'lp')

Annotated Source Code

1/*
2--
3-- SYNOPSIS
4-- Unix archive manipulation code.
5--
6-- DESCRIPTION
7-- Originally this code was provided by Eric Gisin of MKS. I took
8-- his code and completely rewrote it adding cacheing of lib members
9-- and other various optimizations. I kept the overal functional
10-- idea of the library routines as they are similar to those in GNU
11-- make and felt it advantageous to maintain a similar interface.
12--
13-- AUTHOR
14-- Dennis Vadura, dvadura@dmake.wticorp.com
15--
16-- WWW
17-- http://dmake.wticorp.com/
18--
19-- COPYRIGHT
20-- Copyright (c) 1996,1997 by WTI Corp. All rights reserved.
21--
22-- This program is NOT free software; you can redistribute it and/or
23-- modify it under the terms of the Software License Agreement Provided
24-- in the file <distribution-root>/readme/license.txt.
25--
26-- LOG
27-- Use cvs log to obtain detailed change logs.
28*/
29
30/* Sun unix on 386i's has a broken ar.h that does not assume PORTAR format
31 * by default, so we fix it here. */
32#if defined(i3861) || defined(__DGUX__)
33#define PORTAR1 1
34#endif
35
36#if !defined (COHERENT) && !defined(__COHERENT__)
37#include <ar.h>
38#else
39#include <arcoff.h>
40#endif /* COHERENT, __COHERENT__ */
41#include "extern.h"
42#include "sysintf.h"
43
44/* By defining the defines below it is possible to configure the library
45 * code for library cacheing/non-cacheing, ASCII archive headers, and a full
46 * decode of the ar_hdr fields in the scan_ar function. */
47
48#ifndef ASCARCH1
49#define ASCARCH1 1 /* ASCII time stored in archive */
50#endif
51
52#ifndef LC1
53#define LC1 1 /* Turn on library cacheing */
54#endif
55
56#ifndef CHECKELF1
57#define CHECKELF1 1 /* Enable Elf long member names */
58#endif
59
60#ifndef DECODE_ALL_AR_FIELDS0
61#define DECODE_ALL_AR_FIELDS0 0 /* decode only fields make needs*/
62#endif
63
64#ifndef AR_TRUNCATE_MEMBER_NAMES0
65#define AR_TRUNCATE_MEMBER_NAMES0 0 /* truncate member names for */
66#endif /* comparison. */
67
68#if LC1
69# define FOUND_MEMBER0 FALSE0
70#else
71# define FOUND_MEMBER0 TRUE1
72# define _cache_member(a, b, c)
73# define _check_cache(a, b, c, d) FALSE0
74#endif
75
76#define MAXFNAME255 255 /* Max length of member name */
77#define MAXMNAME8 8 /* Max module name < MAXFNAME */
78
79
80/* This struct is used to pass the library and member inrmation about the
81 * routines that perform the library seeking/cacheing */
82struct ar_args {
83 char *lib;
84 char *member;
85 time_t time;
86};
87
88
89typedef struct AR {
90 char ar_name[MAXFNAME255+1]; /* File name */
91 long ar_size; /* Size in bytes */
92 time_t ar_time; /* Modification time */
93
94#ifdef DOS
95 char ar_modname[MAXMNAME8+1]; /* DOS module name */
96#endif
97
98#if DECODE_ALL_AR_FIELDS0
99 uint16 ar_mode; /* File mode */
100 uint16 ar_uid; /* File owner */
101 uint16 ar_gid; /* File group owner */
102#endif
103} AR, *ARPTR;
104
105
106static int ar_scan ANSI((FILE *,(FILE *, int (*) (FILE *, struct AR *,struct ar_args *), struct
ar_args *)
107 int (*) ANSI((FILE *, struct AR *,struct ar_args *)),(FILE *, int (*) (FILE *, struct AR *,struct ar_args *), struct
ar_args *)
108 struct ar_args *))(FILE *, int (*) (FILE *, struct AR *,struct ar_args *), struct
ar_args *)
;
109static int ar_touch ANSI(( FILE *, time_t ))( FILE *, time_t );
110static int time_function ANSI(( FILE *, struct AR *, struct ar_args * ))( FILE *, struct AR *, struct ar_args * );
111static int touch_function ANSI(( FILE *, struct AR *, struct ar_args * ))( FILE *, struct AR *, struct ar_args * );
112static int ar_name_equal ANSI((char *, char *))(char *, char *);
113
114#if LC1
115static int _cache_member ANSI((char *, char *, time_t))(char *, char *, time_t);
116static int _check_cache ANSI((char *, char *, time_t *, int))(char *, char *, time_t *, int);
117#endif
118
119/* decoded archive header */
120static AR _ar;
121static off_t arhdroffset; /* member seek offset */
122
123
124PUBLIC time_t
125seek_arch(name, lib)/*
126======================
127 Look for module 'name' inside 'lib'. If compiled with cacheing then first
128 check to see if the specified lib is cached. If so then return that time
129 stamp instead of looking into the library. */
130char *name;
131char *lib;
132{
133 FILE *f;
134 int rv;
135 time_t mtime;
136 struct ar_args args;
137
138 /* Check the cache first (if there is a cache) */
139 if( _check_cache(name, lib, &mtime, FALSE0) ) return( mtime );
140
141 /* Open the lib file and perform the scan of the members, looking
142 * for our particular member. If cacheing is enabled it will be
143 * taken care of automatically during the scan. */
144
145 args.lib = lib;
146 args.member = name;
147 args.time = (time_t)0L;
148
149 if( (f = fopen(lib, "r")) == NIL(FILE)((FILE*)((void*)0)) ) return( (time_t)0L );
150 rv = ar_scan(f, time_function, &args );
151 fclose( f );
152
153 if( rv < 0 ) Fatal("(%s): Invalid library format", lib);
154
155 return( args.time );
156}
157
158
159PUBLIC int
160touch_arch(name, lib)/*
161=======================
162 Look for module 'name' inside 'lib'. If compiled with cacheing then first
163 check to see if the specified lib is cached. If so then set that time
164 stamp and write it into the library. Returns 0 on success, non-zero
165 on failure. */
166char *name;
167char *lib;
168{
169 FILE *f;
170 int rv;
171 struct ar_args args;
172
173 /* Open the lib file and perform the scan of the members, looking
174 * for our particular member. If cacheing is enabled it will be
175 * taken care of automatically during the scan. */
176
177 args.lib = lib;
178 args.member = name;
179 args.time = (time_t)0L;
180
181 if( (f = fopen(lib, "r+")) == NIL(FILE)((FILE*)((void*)0)) ) return( (time_t)1L );
182 rv = ar_scan(f, touch_function, &args );
183 fclose( f );
184
185 if( rv < 0 ) Fatal("(%s): Invalid library format", lib);
186
187 return( 0 );
188}
189
190
191
192static int
193time_function(f, arp, argp)/*
194=============================
195 get library member's time, if it matches than return it in argp, if
196 cacheing is enabled than cache the library members also. */
197FILE *f; /* library file */
198struct AR *arp; /* library member header */
199struct ar_args *argp;
200{
201 int rv = _cache_member( arp->ar_name, argp->lib, arp->ar_time );
202
203 if( ar_name_equal (argp->member, arp->ar_name)) {
204 argp->time = arp->ar_time;
205
206 if( arp->ar_time == 0 && !(Glob_attr & A_SILENT0x00002) )
207 Warning( "(%s): Can't extract library member timestamp; using EPOCH",
208 argp->member);
209
210 return( rv ); /* 1 => no cacheing, 0 => cacheing */
211 }
212
213 return( FALSE0 ); /* continue scan */
214}
215
216
217
218static int
219touch_function(f, arp, argp)/*
220==============================
221 Update library member's time stamp, and write new time value into cache
222 if required. */
223FILE *f; /* library file */
224struct AR *arp; /* library member header */
225struct ar_args *argp;
226{
227 extern time_t time ANSI(( time_t * ))( time_t * );
228 time_t now = time((time_t*) NULL((void*)0)); /* Current time. */
229
230 if( ar_name_equal(argp->member, arp->ar_name) ) {
231 _check_cache( argp->member, argp->lib, &now, TRUE1 );
232 ar_touch(f, now );
233
234 return( TRUE1 );
235 }
236
237 return( FALSE0 ); /* continue scan */
238}
239
240
241static int
242ar_name_equal (char * name1, char * name2)
243{
244 int equal;
245
246#if AR_TRUNCATE_MEMBER_NAMES0
247 struct ar_hdr hdr;
248
249 equal = !strncmp (name1, name2, sizeof (hdr.ar_name)-1);
250#else
251 equal = !strcmp (name1, name2);
252#endif
253
254 return equal;
255}
256
257
258static int
259ar_scan(f, function, arg)/*
260===========================
261 Scan the opened archive, and call the given function for each member found.
262 The function will be called with the file positioned at the beginning of
263 the member and it can read up to arp->ar_size bytes of the archive member.
264 If the function returns 1, we stop and return 1. We return 0 at the end
265 of the archive, or -1 if the archive has invalid format. This interface
266 is more general than required by "make", but it can be used by other
267 utilities. */
268register FILE *f;
269int (*function) ANSI((FILE *, struct AR *, struct ar_args *))(FILE *, struct AR *, struct ar_args *);
270struct ar_args *arg;
271{
272 extern long atol ();
273 register char *p;
274 struct ar_hdr arhdr; /* archive member header */
275 long nsize; /* size of member name */
276 long arind=0; /* archive index offset */
277 int process;
278#if defined(_AIX)
279 struct fl_hdr flhdr; /* archive file header */
280 char magic[SAIAMAG]; /* size of magic string */
281#else
282#if ASCARCH1
283 char magic[SARMAG8];
284#else
285 unsigned short word;
286#endif
287#endif
288
289 fseek( f, 0L, 0 ); /* Start at the beginning of the archive file */
290
291#if ASCARCH1
292#if defined(_AIX)
293 if( fread( (char *)&flhdr, sizeof(flhdr), 1, f ) != 1 ) return (-1);
294 if( strncmp(flhdr.fl_magic,AIAMAG, SAIAMAG) != 0 ) return(-1);
295 fseek(f, atol(flhdr.fl_fstmoff), 0 ); /* postition to first member */
296#else
297 if( fread( magic, sizeof(magic), 1, f ) != 1 ) return( -1 );
298 if( strncmp(magic, ARMAG"!<arch>\n", SARMAG8) != 0 ) return( -1 );
299#endif
300#else
301 if( fread( (char*)&word, sizeof(word), 1, f ) != 1 ) return( -1 );
302 if( word != ARMAG"!<arch>\n" ) return( -1 );
303#endif
304
305 /* scan the library, calling `function' for each member
306 */
307 while( 1 ) {
308 arhdroffset = ftell(f);
309#if defined(_AIX)
310 if( fread((char*)&arhdr,sizeof(arhdr)-sizeof(arhdr._ar_name),1,f)!=1)
311 break;
312 nsize = atoi(arhdr.ar_namlen);
313 fseek(f, arhdroffset+(unsigned long)(((struct ar_hdr *)0)->_ar_name.ar_name), 0);
314 if( fread((char*)_ar.ar_name,nsize,1,f)!=1)
315 break;
316 _ar.ar_name[nsize]='\0';
317#else
318 if( fread((char*) &arhdr, sizeof(arhdr), 1, f) != 1 ) break;
319 strncpy(_ar.ar_name, arhdr.ar_name, nsize = sizeof(arhdr.ar_name));
320#endif
321
322 for( p = &_ar.ar_name[nsize];
323 --p >= _ar.ar_name && *p == ' ';);
324
325 p[1] = '\0';
326 if( *p == '/' ) *p = 0; /* SysV has trailing '/' */
327
328 /* check to see if this is an archive index using SsysV Index scheme.
329 * see ar(4) man page for more info */
330#if CHECKELF1
331 if( _ar.ar_name[0] == '/' && _ar.ar_name[1] == '\0' ) {
332 arind = arhdroffset+sizeof(arhdr);
333 process = 0;
334 }
335 else
336#endif
337 process = 1;
338
339#if !defined(_AIX)
340#if ASCARCH1
341 if( strncmp(arhdr.ar_fmag, ARFMAG"`\n", sizeof(arhdr.ar_fmag)) != 0 )
342 return( -1 );
343 _ar.ar_time = atol(arhdr.ar_date);
344 _ar.ar_size = atol(arhdr.ar_size);
345#else
346 _ar.ar_time = arhdr.ar_date;
347 _ar.ar_size = arhdr.ar_size;
348#endif
349#if CHECKELF1
350 /* check for names of the form /xxxx where xxxx is an offset into the
351 * name table pointed at by arind. */
352 if(arind && _ar.ar_name[0] == '/') {
353 long offset = atol(_ar.ar_name+1);
354 long here = ftell(f);
355 int c;
356
357 fseek(f, arind+offset, 0);
358 p = _ar.ar_name;
359 while((c=fgetc(f)) != EOF(-1)) {
360 *p++ = c;
361 if(c == '/') {
362 p[-1] = '\0';
363 break;
364 }
365 }
366
367 if (c==EOF(-1)) return(-1); /* 'c' should never be EOF */
368 fseek(f, here, 0);
369 }
370#endif
371#else
372#if ASCARCH1
373 _ar.ar_time = atol(arhdr.ar_date);
374 _ar.ar_size = atol(arhdr.ar_nxtmem);
375#else
376 _ar.ar_time = arhdr.ar_date;
377 _ar.ar_size = arhdr.ar_nxtmem;
378#endif
379#endif
380
381
382#if DECODE_ALL_AR_FIELDS0
383#if ASCARCH1
384 _ar.ar_mode = atoi(arhdr.ar_mode);
385 _ar.ar_uid = atoi(arhdr.ar_uid);
386 _ar.ar_gid = atoi(arhdr.ar_gid);
387#else
388 _ar.ar_mode = arhdr.ar_mode;
389 _ar.ar_uid = arhdr.ar_uid;
390 _ar.ar_gid = arhdr.ar_gid;
391#endif
392#endif
393 if( process && (*function)(f, &_ar, arg) ) return( 1 );
394
395#if defined(_AIX)
396 if( _ar.ar_size == 0L ) break;
397 fseek( f, (long) _ar.ar_size, 0 );
398#else
399 fseek( f, arhdroffset + sizeof(arhdr) + ((_ar.ar_size+1) & ~1L), 0 );
400#endif
401 }
402
403#if !defined(_AIX)
404 if( !feof(f) ) return( -1 );
405#endif
406 return 0;
407}
408
409
410
411static int
412ar_touch( f, now )/*
413====================
414 touch module header timestamp. */
415FILE *f;
416time_t now;
417{
418
419 fseek(f, arhdroffset + (unsigned long)(((struct ar_hdr *)0)->ar_date), 0);
420
421#if ASCARCH1
422 fprintf(f, "%lu", now);
423#else
424 fwrite((char *)now, sizeof(now), 1, f);
425#endif
426
427 return( ferror(f) ? 0 : 1 );
428}
429
430
431#if LC1
432typedef struct mem {
433 time_t m_time; /* modify time of member*/
434 struct mem *m_next; /* next member in lib */
435 char m_valid; /* valid cache entry */
436 char m_name[1]; /* lib member name */
437} MEM, *MEMPTR;
438
439typedef struct lib {
440 struct lib *lb_next; /* next library in list */
441 struct mem *lb_members; /* list of lib members */
442 char lb_valid; /* valid cache entry */
443 char *lb_name; /* library name */
444} LIB, *LIBPTR;
445
446static LIBPTR _cache = NIL(LIB)((LIB*)((void*)0));
447static MEMPTR _find_member ANSI(( LIBPTR, char * ))( LIBPTR, char * );
448
449static int
450_check_cache( name, lib, pmtime, touch )/*
451==========================================
452 Check to see if we have cached member in lib, if so return time in pmtime
453 and return TRUE, otherwise return FALSE, if touch is TRUE then touch
454 the archive member instead. */
455char *name;
456char *lib;
457time_t *pmtime;
458int touch;
459{
460 register MEMPTR mp;
461 register LIBPTR lp;
462
463 for( lp=_cache; lp != NIL(LIB)((LIB*)((void*)0)) && lp->lb_name != lib; lp=lp->lb_next );
464 if( lp == NIL(LIB)((LIB*)((void*)0)) ) return( FALSE0 );
465
466 mp = _find_member( lp, name );
467 if( mp == NIL(MEM)((MEM*)((void*)0)) || !mp->m_valid ) return( FALSE0 );
468
469 if( touch == TRUE1 )
470 {
471 mp->m_time = *pmtime;
472 mp->m_valid = 1;
473 }
474 else
475 *pmtime = mp->m_time;
476
477 lp->lb_valid = 1;
478 lp->lb_members = mp;
479
480 return( TRUE1 );
481}
482
483
484
485static int
486_cache_member( name, lib, mtime )/*
487===================================
488 Cache name in lib along with it's time */
489char *name;
490char *lib;
491time_t mtime;
492{
493 register MEMPTR mp;
494 register LIBPTR lp;
495
496 for( lp=_cache;
497 lp != NIL(LIB)((LIB*)((void*)0)) && lp->lb_name != NIL(char)((char*)((void*)0)) && lp->lb_name != lib;
1
Assuming 'lp' is equal to null
498 lp=lp->lb_next);
499
500 if( lp == NIL(LIB)((LIB*)((void*)0)) )
2
Taking true branch
501 {
502 lp = (LIBPTR) malloc(sizeof(LIB));
3
Value assigned to 'lp'
503 if( lp == NIL(LIB)((LIB*)((void*)0)) ) No_ram();
4
Assuming 'lp' is equal to null
5
Taking true branch
504
505 lp->lb_name = lib;
6
Access to field 'lb_name' results in a dereference of a null pointer (loaded from variable 'lp')
506 lp->lb_members = NIL(MEM)((MEM*)((void*)0));
507 lp->lb_next = _cache;
508 lp->lb_valid = 0;
509 _cache = lp;
510 }
511
512 /* On UNIX ar does not allow multiple copies of the same .o file to live
513 * in the same AR file. If this is not TRUE then use the commented out
514 * version to set the value of mp. */
515
516 /*mp = _find_member(lp, name);*/
517 mp = NIL(MEM)((MEM*)((void*)0));
518
519 if( mp == NIL(MEM)((MEM*)((void*)0)) )
520 {
521 mp = (MEMPTR) malloc(sizeof(char)*offsetof(MEM,m_name[strlen(name)+1])__builtin_offsetof(MEM, m_name[strlen(name)+1]));
522 if( mp == NIL(MEM)((MEM*)((void*)0)) ) No_ram();
523
524 strcpy( mp->m_name, name );
525 mp->m_time = mtime;
526
527 if( lp->lb_members == NIL(MEM)((MEM*)((void*)0)) ) {
528 mp->m_next = mp;
529 lp->lb_members = mp;
530 }
531 else {
532 mp->m_next = lp->lb_members->m_next;
533 lp->lb_members->m_next = mp;
534 lp->lb_members = mp;
535 }
536 }
537 else
538 mp->m_time = mtime;
539
540 mp->m_valid = 1;
541
542 return( lp->lb_valid );
543}
544
545
546static MEMPTR
547_find_member( lp, name )
548LIBPTR lp;
549char *name;
550{
551 register MEMPTR mp = lp->lb_members;
552
553 if( mp == NIL(MEM)((MEM*)((void*)0)) ) return(mp);
554
555 do {
556 if( !strcmp(mp->m_name, name ) ) return( mp );
557 mp = mp->m_next;
558 }
559 while( mp != lp->lb_members );
560
561 return( NIL(MEM)((MEM*)((void*)0)) );
562}
563#endif
564
565
566
567PUBLIC void
568void_lcache( lib, member )/*
569============================
570 Void the library cache for lib. If member is NIL(char) then nuke all
571 of the members, if member is NOT NIL(char) then invalidate only that
572 member. */
573char *lib;
574char *member;
575{
576#if LC1
577 register LIBPTR lp;
578 register MEMPTR mp;
579 register MEMPTR tmp;
580
581 for( lp=_cache; lp != NIL(LIB)((LIB*)((void*)0)) && lp->lb_name != lib; lp=lp->lb_next );
582 if( lp == NIL(LIB)((LIB*)((void*)0)) ) return;
583
584 if( member == NIL(char)((char*)((void*)0)) ) {
585 mp = lp->lb_members;
586 do {
587 tmp = mp->m_next;
588 (void) free( mp );
589 mp = tmp;
590 } while( mp != lp->lb_members );
591
592 lp->lb_valid = 0;
593 lp->lb_members = NIL(MEM)((MEM*)((void*)0));
594 lp->lb_name = NIL(char)((char*)((void*)0));
595 }
596 else {
597 mp=lp->lb_members;
598 do {
599 if( strcmp( member, mp->m_name) == 0 ) {
600 lp->lb_members = mp->m_next;
601 mp->m_valid = 0;
602 }
603
604 mp=mp->m_next;
605 } while( mp != lp->lb_members );
606 }
607#endif
608}