Bug Summary

File:dmake/macparse.c
Location:line 154, column 9
Description:Access to field 'st_string' results in a dereference of a null pointer (loaded from variable 'sp')

Annotated Source Code

1/* RCS $Id: macparse.c,v 1.3 2007-10-15 15:40:02 ihi Exp $
2--
3-- SYNOPSIS
4-- Parse a macro definition
5--
6-- DESCRIPTION
7-- This file contains the code that parses a macro definition
8-- stored in a buffer. If the string in buffer is not a valid
9-- macro definition the routie Parse_macro returns 0, otherwise it
10-- returns 1 to indicate success.
11--
12-- AUTHOR
13-- Dennis Vadura, dvadura@dmake.wticorp.com
14--
15-- WWW
16-- http://dmake.wticorp.com/
17--
18-- COPYRIGHT
19-- Copyright (c) 1996,1997 by WTI Corp. All rights reserved.
20--
21-- This program is NOT free software; you can redistribute it and/or
22-- modify it under the terms of the Software License Agreement Provided
23-- in the file <distribution-root>/readme/license.txt.
24--
25-- LOG
26-- Use cvs log to obtain detailed change logs.
27*/
28
29#include "extern.h"
30
31PUBLIC int
32Parse_macro( buffer, flag )/*
33=============================
34 Parse the string in buffer and define it as a macro if it is a valid macro.
35 Note especially the string .SETDIR= since it is an attribute, but looks a
36 lot like a macro definition. This would not be a problem if make used
37 white space as token separators, since this is not the case we must do
38 something about it. */
39char *buffer;
40int flag;
41{
42 char *result; /* temporary pointer for strings */
43 TKSTR input; /* place to scan the buffer from */
44 HASHPTR hv; /* pointer to hash table value */
45 int operator; /* what macro operator do we have */
46 char *tok1; /* temporary place to keep a token */
47 char *tok2; /* temporary place to keep a token */
48 int toklen; /* length of a token */
49
50 DB_ENTER( "Parse_macro" );
51
52 SET_TOKEN( &input, buffer )(&input)->tk_str = (buffer); (&input)->tk_cchar
= *(buffer); (&input)->tk_quote = 1;
;
53 tok1 = Get_token( &input, "=+:*!?", 0 );
54
55 operator=Macro_op(tok1);
56 if( operator ) {
1
Taking false branch
57 CLEAR_TOKEN( &input )*(&input)->tk_str = (&input)->tk_cchar;
58 Error( "Assignment without macro name: [%s].", buffer );
59 DB_RETURN( 1 )return (1);
60 }
61
62 tok1 = DmStrDup(tok1);
63 tok2 = Get_token( &input, "=+:*!?", 2 );
64 if( !(operator = Macro_op(tok2)) || !strcmp(tok1,".SETDIR") ) {
2
Taking false branch
65 CLEAR_TOKEN( &input )*(&input)->tk_str = (&input)->tk_cchar;
66 FREE(tok1)free((char*)(tok1));
67 DB_RETURN(0)return (0);
68 }
69
70 tok2 = Expand(tok1); FREE(tok1)free((char*)(tok1)); tok1 = tok2;
71 if ( !(toklen = strlen(tok1)) ) {
3
Taking false branch
72 Warning( "Empty macro name after expansion: [%s].", buffer );
73 }
74
75 /* Catch illegal single character macro names. */
76 if ( toklen == 1 && strchr("{()}", tok1[0]) ) {
77 CLEAR_TOKEN( &input )*(&input)->tk_str = (&input)->tk_cchar;
78 Fatal( "Syntax error in macro assignment [%s]. The following characters cannot be used as single letter macro names: '{()}'.", buffer );
79 }
80
81 /* Catch ':' in macro names. */
82 if ( strchr(tok1, ':') ) {
4
Taking false branch
83 CLEAR_TOKEN( &input )*(&input)->tk_str = (&input)->tk_cchar;
84 Fatal( "Syntax error in macro assignment [%s]. The character ':' is not allowed in macro names.", buffer );
85 }
86
87 tok2 = Get_token(&input, NIL( char )((char*)((void*)0)), FALSE0);
88
89 /* Make sure we can force the assignment. */
90 if ( operator & M_OP_SI32 ) {
5
Taking false branch
91 flag |= M_FORCE0x0080|M_MULTI0x0004;
92 operator &= ~M_OP_SI32;
93 }
94
95 switch( operator ) {
6
Control jumps to 'case 17:' at line 138
96 case M_OP_PLCL7:
97 tok2 = Expand( tok2 );
98 /* Fall thru */
99
100 case M_OP_PL5:
101 /* Add to an existing macro, if it is not defined, though, then
102 * just define a new macro */
103
104 if( (hv = GET_MACRO(tok1)Get_name(tok1, Macs, 0)) == NIL(HASH)((HASH*)((void*)0)) || hv->ht_value == NIL(char)((char*)((void*)0)) )
105 Def_macro( tok1, tok2, flag );
106 else {
107 result = DmStrAdd( hv->ht_value, tok2, FALSE0 );
108 Def_macro( tok1, result, flag );
109 FREE( result )free((char*)(result));
110 }
111 if( operator == M_OP_PLCL7 ) FREE(tok2)free((char*)(tok2));
112 break;
113
114 case M_OP_DF9:
115 /* *= */
116 /* internal default macros or initialized empty macros set M_INIT. */
117 if( (hv = GET_MACRO(tok1)Get_name(tok1, Macs, 0)) != NIL(HASH)((HASH*)((void*)0)) && !(hv->ht_flag & M_INIT0x0200) )
118 break;
119 /* else FALLTHRU */
120
121 case M_OP_EQ1:
122 Def_macro( tok1, tok2, flag );
123 break;
124
125 case M_OP_DFCL11:
126 /* *:= */
127 /* internal default macros or initialized empty macros set M_INIT. */
128 if( (hv = GET_MACRO(tok1)Get_name(tok1, Macs, 0)) != NIL(HASH)((HASH*)((void*)0)) && !(hv->ht_flag & M_INIT0x0200) )
129 break;
130 /* else FALLTHRU */
131
132 case M_OP_CL3:
133 tok2 = Expand( tok2 );
134 Def_macro( tok1, tok2, M_EXPANDED0x0008 | flag );
135 FREE( tok2 )free((char*)(tok2));
136 break;
137
138 case M_OP_CM17:{
139 CELLPTR cp;
140 STRINGPTR sp;
141
142 if (flag & M_PUSH0x0100) {
7
Taking false branch
143 Error("Nested conditional definition [%s ?= %s] ignored",
144 tok1, tok2);
145 }
146 else {
147 cp = Def_cell(tok1);
148 if (cp->ce_flag & F_MULTI0x0002) {
8
Taking false branch
149 LINKPTR lp;
150 for(lp=cp->ce_prq; lp->cl_next; lp=lp->cl_next);
151 cp = lp->cl_prq;
152 }
153 TALLOC(sp,1,STRING)if ((sp = (STRING*) calloc((unsigned int)(1), (size_t)sizeof(
STRING))) == (STRING*)0) {No_ram();}
;
9
Within the expansion of the macro 'TALLOC':
a
Value assigned to 'sp'
b
Assuming pointer value is null
154 sp->st_string = DmStrDup(tok2);
10
Access to field 'st_string' results in a dereference of a null pointer (loaded from variable 'sp')
155 sp->st_next = cp->ce_cond;
156 cp->ce_cond = sp;
157
158 tok1 = NIL(char)((char*)((void*)0));
159 }
160 }
161 break;
162 }
163
164 if (tok1) {
165 if ( LastMacName != NIL(char)((char*)((void*)0)) )
166 FREE( LastMacName )free((char*)(LastMacName));
167
168 LastMacName = tok1;
169 }
170
171 DB_RETURN( 1 )return (1);
172}
173
174
175
176PUBLIC int
177Macro_op( op )/*
178================
179 Check the passed in op string and map it to one of the macro operators */
180char *op;
181{
182 int ret = 0;
183 DB_ENTER( "macro_op" );
184
185 if ( *op == '!' ) {
186 ret = M_OP_SI32;
187 op++;
188 }
189
190 switch( *op ) {
191 case '=': ret |= M_OP_EQ1; break;
192 case ':': ret |= M_OP_CL3; op++; break;
193
194 case '+':
195 op++;
196 if( *op == ':' ) {
197 ret |= M_OP_PLCL7;
198 op++;
199 }
200 else {
201 ret |= M_OP_PL5;
202 }
203 break;
204
205 case '*':
206 op++;
207 if( *op == ':' ) {
208 ret |= M_OP_DFCL11;
209 op++;
210 }
211 else {
212 ret |= M_OP_DF9;
213 }
214 break;
215
216 case '?':
217 ret |= M_OP_CM17;
218 op++;
219 break;
220 }
221
222 if( *op != '=' )
223 ret = 0;
224 else {
225 op++;
226
227 if( *op != '\0' )
228 ret = 0;
229 }
230
231 DB_RETURN( ret )return (ret);
232}