1 /*
2 * Environment handling routines
3 *
4 * Copyright 2020 by Gray Watson
5 *
6 * This file is part of the dmalloc package.
7 *
8 * Permission to use, copy, modify, and distribute this software for
9 * any purpose and without fee is hereby granted, provided that the
10 * above copyright notice and this permission notice appear in all
11 * copies, and that the name of Gray Watson not be used in advertising
12 * or publicity pertaining to distribution of the document or software
13 * without specific, written prior permission.
14 *
15 * Gray Watson makes no representations about the suitability of the
16 * software described herein for any purpose. It is provided "as is"
17 * without express or implied warranty.
18 *
19 * The author may be contacted via http://dmalloc.com/
20 */
21
22 /*
23 * This file contains short routine(s) to process the environment
24 * variable(s) used by the library to get the runtime option(s).
25 */
26
27 #define DMALLOC_DISABLE
28
29 #if HAVE_STDLIB_H
30 # include <stdlib.h>
31 #endif
32 #if HAVE_STRING_H
33 # include <string.h>
34 #endif
35 #if HAVE_UNISTD_H
36 # include <unistd.h> /* for getpid */
37 #endif
38
39 #include "conf.h"
40 #include "dmalloc.h"
41
42 #include "append.h"
43 #include "compat.h"
44 #include "dmalloc_loc.h"
45 #include "debug_tok.h"
46 #include "env.h"
47 #include "error.h"
48
49 /*
50 * Environmental labels.
51 *
52 * NOTE: the decision has been made _not_ to do the sizeof() hack for
53 * portability reasons.
54 */
55 #define ADDRESS_LABEL "addr"
56 #define DEBUG_LABEL "debug"
57 #define INTERVAL_LABEL "inter"
58 #define LOCK_ON_LABEL "lockon"
59 #define LOGFILE_LABEL "log"
60 #define START_LABEL "start"
61 #define LIMIT_LABEL "limit"
62
63 #define ASSIGNMENT_CHAR '='
64
65 /* local variables */
66 static char log_path[512] = { '\0' }; /* storage for env path */
67 static char start_file[512] = { '\0' }; /* file to start at */
68
69 /****************************** local utilities ******************************/
70
71 /*
72 * Hexadecimal STR to long translation
73 */
hex_to_uint(const char * str)74 static unsigned int hex_to_uint(const char *str)
75 {
76 unsigned int ret;
77
78 /* strip off spaces */
79 for (; *str == ' ' || *str == '\t'; str++) {
80 }
81
82 /* skip a leading 0[xX] */
83 if (*str == '0' && (*(str + 1) == 'x' || *(str + 1) == 'X')) {
84 str += 2;
85 }
86
87 for (ret = 0;; str++) {
88 if (*str >= '0' && *str <= '9') {
89 ret = ret * 16 + (*str - '0');
90 }
91 else if (*str >= 'a' && *str <= 'f') {
92 ret = ret * 16 + (*str - 'a' + 10);
93 }
94 else if (*str >= 'A' && *str <= 'F') {
95 ret = ret * 16 + (*str - 'A' + 10);
96 }
97 else {
98 break;
99 }
100 }
101
102 return ret;
103 }
104
105 /*
106 * Hexadecimal STR to address translation
107 */
hex_to_address(const char * str)108 static DMALLOC_PNT hex_to_address(const char *str)
109 {
110 PNT_ARITH_TYPE ret;
111
112 /* strip off spaces */
113 for (; *str == ' ' || *str == '\t'; str++) {
114 }
115
116 /* skip a leading 0[xX] */
117 if (*str == '0' && (*(str + 1) == 'x' || *(str + 1) == 'X')) {
118 str += 2;
119 }
120
121 for (ret = 0;; str++) {
122 if (*str >= '0' && *str <= '9') {
123 ret = ret * 16 + (*str - '0');
124 }
125 else if (*str >= 'a' && *str <= 'f') {
126 ret = ret * 16 + (*str - 'a' + 10);
127 }
128 else if (*str >= 'A' && *str <= 'F') {
129 ret = ret * 16 + (*str - 'A' + 10);
130 }
131 else {
132 break;
133 }
134 }
135
136 return (DMALLOC_PNT)ret;
137 }
138
139 /***************************** exported routines *****************************/
140
141 /*
142 * Break up ADDR_ALL into ADDR_P and ADDR_COUNT_P
143 */
_dmalloc_address_break(const char * addr_all,DMALLOC_PNT * addr_p,unsigned long * addr_count_p)144 void _dmalloc_address_break(const char *addr_all, DMALLOC_PNT *addr_p,
145 unsigned long *addr_count_p)
146 {
147 char *colon_p;
148
149 SET_POINTER(addr_p, hex_to_address(addr_all));
150 if (addr_count_p != NULL) {
151 colon_p = strchr(addr_all, ':');
152 if (colon_p != NULL) {
153 *addr_count_p = loc_atoul(colon_p + 1);
154 }
155 }
156 }
157
158 /*
159 * Break up START_ALL into SFILE_P, SLINE_P, and SCOUNT_P
160 */
_dmalloc_start_break(char * start_all,char ** start_file_p,int * start_line_p,unsigned long * start_iter_p,unsigned long * start_size_p)161 void _dmalloc_start_break(char *start_all, char **start_file_p,
162 int *start_line_p, unsigned long *start_iter_p,
163 unsigned long *start_size_p)
164 {
165 char *start_p;
166
167 start_p = strchr(start_all, ':');
168 if (start_p != NULL) {
169 (void)strncpy(start_file, start_all, sizeof(start_file));
170 start_file[sizeof(start_file) - 1] = '\0';
171 SET_POINTER(start_file_p, start_file);
172 start_p = start_file + (start_p - start_all);
173 *start_p = '\0';
174 SET_POINTER(start_line_p, atoi(start_p + 1));
175 SET_POINTER(start_iter_p, 0);
176 SET_POINTER(start_size_p, 0);
177 }
178 else if (start_all[0] == 's') {
179 SET_POINTER(start_file_p, NULL);
180 SET_POINTER(start_line_p, 0);
181 SET_POINTER(start_iter_p, 0);
182 SET_POINTER(start_size_p, loc_atoul(start_all + 1));
183 }
184 else {
185 SET_POINTER(start_file_p, NULL);
186 SET_POINTER(start_line_p, 0);
187 if (start_all[0] == 'c') {
188 SET_POINTER(start_iter_p, loc_atoul(start_all + 1));
189 }
190 else {
191 SET_POINTER(start_iter_p, loc_atoul(start_all));
192 }
193 SET_POINTER(start_size_p, 0);
194 }
195 }
196
197 /*
198 * Process the values of dmalloc environ variable(s) from ENVIRON
199 * string.
200 */
_dmalloc_environ_process(const char * env_str,DMALLOC_PNT * addr_p,unsigned long * addr_count_p,unsigned int * debug_p,unsigned long * interval_p,int * lock_on_p,char ** logpath_p,char ** start_file_p,int * start_line_p,unsigned long * start_iter_p,unsigned long * start_size_p,unsigned long * limit_p)201 void _dmalloc_environ_process(const char *env_str, DMALLOC_PNT *addr_p,
202 unsigned long *addr_count_p,
203 unsigned int *debug_p,
204 unsigned long *interval_p, int *lock_on_p,
205 char **logpath_p, char **start_file_p,
206 int *start_line_p,
207 unsigned long *start_iter_p,
208 unsigned long *start_size_p,
209 unsigned long *limit_p)
210 {
211 char *env_p, *this_p;
212 char buf[1024];
213 int len, done_b = 0;
214 unsigned int flags = 0;
215 attr_t *attr_p;
216
217 SET_POINTER(addr_p, NULL);
218 SET_POINTER(addr_count_p, 0);
219 SET_POINTER(debug_p, 0);
220 SET_POINTER(interval_p, 0);
221 SET_POINTER(lock_on_p, 0);
222 SET_POINTER(logpath_p, NULL);
223 SET_POINTER(start_file_p, NULL);
224 SET_POINTER(start_line_p, 0);
225 SET_POINTER(start_iter_p, 0);
226 SET_POINTER(start_size_p, 0);
227 SET_POINTER(limit_p, 0);
228
229 /* make a copy */
230 (void)strncpy(buf, env_str, sizeof(buf));
231 buf[sizeof(buf) - 1] = '\0';
232
233 /* handle each of tokens, in turn */
234 for (env_p = buf, this_p = buf; ! done_b; env_p++, this_p = env_p) {
235
236 /* find the comma of end */
237 for (;; env_p++) {
238 if (*env_p == '\0') {
239 done_b = 1;
240 break;
241 }
242 if (*env_p == ',' && (env_p == buf || *(env_p - 1) != '\\')) {
243 break;
244 }
245 }
246
247 /* should we strip ' ' or '\t' here? */
248
249 if (this_p == env_p) {
250 continue;
251 }
252
253 *env_p = '\0';
254
255 len = strlen(ADDRESS_LABEL);
256 if (strncmp(this_p, ADDRESS_LABEL, len) == 0
257 && *(this_p + len) == ASSIGNMENT_CHAR) {
258 this_p += len + 1;
259 _dmalloc_address_break(this_p, addr_p, addr_count_p);
260 continue;
261 }
262
263 len = strlen(DEBUG_LABEL);
264 if (strncmp(this_p, DEBUG_LABEL, len) == 0
265 && *(this_p + len) == ASSIGNMENT_CHAR) {
266 this_p += len + 1;
267 SET_POINTER(debug_p, hex_to_uint(this_p));
268 continue;
269 }
270
271 len = strlen(INTERVAL_LABEL);
272 if (strncmp(this_p, INTERVAL_LABEL, len) == 0
273 && *(this_p + len) == ASSIGNMENT_CHAR) {
274 this_p += len + 1;
275 SET_POINTER(interval_p, loc_atoul(this_p));
276 continue;
277 }
278
279 len = strlen(LOCK_ON_LABEL);
280 if (strncmp(this_p, LOCK_ON_LABEL, len) == 0
281 && *(this_p + len) == ASSIGNMENT_CHAR) {
282 this_p += len + 1;
283 SET_POINTER(lock_on_p, atoi(this_p));
284 continue;
285 }
286
287 /* get the dmalloc logfile name into a holding variable */
288 len = strlen(LOGFILE_LABEL);
289 if (strncmp(this_p, LOGFILE_LABEL, len) == 0
290 && *(this_p + len) == ASSIGNMENT_CHAR) {
291 this_p += len + 1;
292 (void)strncpy(log_path, this_p, sizeof(log_path));
293 log_path[sizeof(log_path) - 1] = '\0';
294 SET_POINTER(logpath_p, log_path);
295 continue;
296 }
297
298 /*
299 * start checking the heap after X iterations OR
300 * start at a file:line combination
301 */
302 len = strlen(START_LABEL);
303 if (strncmp(this_p, START_LABEL, len) == 0
304 && *(this_p + len) == ASSIGNMENT_CHAR) {
305 this_p += len + 1;
306 _dmalloc_start_break(this_p, start_file_p, start_line_p, start_iter_p,
307 start_size_p);
308 continue;
309 }
310
311 /* set the memory limit to the library */
312 len = strlen(LIMIT_LABEL);
313 if (strncmp(this_p, LIMIT_LABEL, len) == 0
314 && *(this_p + len) == ASSIGNMENT_CHAR) {
315 this_p += len + 1;
316 SET_POINTER(limit_p, loc_atoul(this_p));
317 continue;
318 }
319
320 /* need to check the short/long debug options */
321 for (attr_p = attributes; attr_p->at_string != NULL; attr_p++) {
322 if (strcmp(this_p, attr_p->at_string) == 0) {
323 flags |= attr_p->at_value;
324 break;
325 }
326 }
327 if (attr_p->at_string != NULL) {
328 continue;
329 }
330 }
331
332 /* append the token settings to the debug setting */
333 if (debug_p != NULL) {
334 if (*debug_p == 0) {
335 *debug_p = flags;
336 }
337 else {
338 *debug_p |= flags;
339 }
340 }
341 }
342
343 /*
344 * Set dmalloc environ variable(s) with the values (maybe SHORT debug
345 * info) into BUF.
346 */
_dmalloc_environ_set(char * buf,const int buf_size,const int long_tokens_b,const DMALLOC_PNT address,const unsigned long addr_count,const unsigned int debug,const unsigned long interval,const int lock_on,const char * logpath,const char * start_file_p,const int start_line,const unsigned long start_iter,const unsigned long start_size,const unsigned long limit_val)347 void _dmalloc_environ_set(char *buf, const int buf_size,
348 const int long_tokens_b,
349 const DMALLOC_PNT address,
350 const unsigned long addr_count,
351 const unsigned int debug,
352 const unsigned long interval, const int lock_on,
353 const char *logpath, const char *start_file_p,
354 const int start_line,
355 const unsigned long start_iter,
356 const unsigned long start_size,
357 const unsigned long limit_val)
358 {
359 char *buf_p = buf, *bounds_p = buf + buf_size;
360
361 if (debug > 0) {
362 if (long_tokens_b) {
363 attr_t *attr_p;
364
365 for (attr_p = attributes; attr_p->at_string != NULL; attr_p++) {
366 if (debug & attr_p->at_value) {
367 buf_p += loc_snprintf(buf_p, bounds_p - buf_p, "%s,",
368 attr_p->at_string);
369 }
370 }
371 }
372 else {
373 buf_p += loc_snprintf(buf_p, bounds_p - buf_p, "%s%c%#x,",
374 DEBUG_LABEL, ASSIGNMENT_CHAR, debug);
375 }
376 }
377 if (address != NULL) {
378 if (addr_count > 0) {
379 buf_p += loc_snprintf(buf_p, bounds_p - buf_p, "%s%c%p:%lu,",
380 ADDRESS_LABEL, ASSIGNMENT_CHAR, address, addr_count);
381 }
382 else {
383 buf_p += loc_snprintf(buf_p, bounds_p - buf_p, "%s%c%p,",
384 ADDRESS_LABEL, ASSIGNMENT_CHAR, address);
385 }
386 }
387 if (interval > 0) {
388 buf_p += loc_snprintf(buf_p, bounds_p - buf_p, "%s%c%lu,",
389 INTERVAL_LABEL, ASSIGNMENT_CHAR, interval);
390 }
391 if (lock_on > 0) {
392 buf_p += loc_snprintf(buf_p, bounds_p - buf_p, "%s%c%d,",
393 LOCK_ON_LABEL, ASSIGNMENT_CHAR, lock_on);
394 }
395 if (logpath != NULL) {
396 buf_p += loc_snprintf(buf_p, bounds_p - buf_p, "%s%c%s,",
397 LOGFILE_LABEL, ASSIGNMENT_CHAR, logpath);
398 }
399 if (start_file_p != NULL) {
400 if (start_line > 0) {
401 buf_p += loc_snprintf(buf_p, bounds_p - buf_p, "%s%c%s:%d,",
402 START_LABEL, ASSIGNMENT_CHAR, start_file_p,
403 start_line);
404 }
405 else {
406 buf_p += loc_snprintf(buf_p, bounds_p - buf_p, "%s%c%s,",
407 START_LABEL, ASSIGNMENT_CHAR, start_file_p);
408 }
409 }
410 else if (start_iter > 0) {
411 /* NOTE: there is an 'c' (for count) before the iter variable here */
412 buf_p += loc_snprintf(buf_p, bounds_p - buf_p, "%s%cc%lu,",
413 START_LABEL, ASSIGNMENT_CHAR, start_iter);
414 }
415 else if (start_size > 0) {
416 /* NOTE: there is an 's' before the size variable here */
417 buf_p += loc_snprintf(buf_p, bounds_p - buf_p, "%s%cs%lu,",
418 START_LABEL, ASSIGNMENT_CHAR, start_size);
419 }
420 if (limit_val > 0) {
421 buf_p += loc_snprintf(buf_p, bounds_p - buf_p, "%s%c%lu,",
422 LIMIT_LABEL, ASSIGNMENT_CHAR, limit_val);
423 }
424
425 /* cut off the last comma */
426 if (buf_p > buf) {
427 buf_p--;
428 }
429
430 *buf_p = '\0';
431 }
432