]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - misc.c
When asked to malloc zero bytes, malloc one byte instead. This ensures
[PuTTY.git] / misc.c
1 /*
2  * Platform-independent routines shared between all PuTTY programs.
3  */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <stdarg.h>
8 #include <limits.h>
9 #include <ctype.h>
10 #include <assert.h>
11 #include "putty.h"
12
13 /*
14  * Parse a string block size specification. This is approximately a
15  * subset of the block size specs supported by GNU fileutils:
16  *  "nk" = n kilobytes
17  *  "nM" = n megabytes
18  *  "nG" = n gigabytes
19  * All numbers are decimal, and suffixes refer to powers of two.
20  * Case-insensitive.
21  */
22 unsigned long parse_blocksize(const char *bs)
23 {
24     char *suf;
25     unsigned long r = strtoul(bs, &suf, 10);
26     if (*suf != '\0') {
27         while (*suf && isspace((unsigned char)*suf)) suf++;
28         switch (*suf) {
29           case 'k': case 'K':
30             r *= 1024ul;
31             break;
32           case 'm': case 'M':
33             r *= 1024ul * 1024ul;
34             break;
35           case 'g': case 'G':
36             r *= 1024ul * 1024ul * 1024ul;
37             break;
38           case '\0':
39           default:
40             break;
41         }
42     }
43     return r;
44 }
45
46 /*
47  * Parse a ^C style character specification.
48  * Returns NULL in `next' if we didn't recognise it as a control character,
49  * in which case `c' should be ignored.
50  * The precise current parsing is an oddity inherited from the terminal
51  * answerback-string parsing code. All sequences start with ^; all except
52  * ^<123> are two characters. The ones that are worth keeping are probably:
53  *   ^?             127
54  *   ^@A-Z[\]^_     0-31
55  *   a-z            1-26
56  *   <num>          specified by number (decimal, 0octal, 0xHEX)
57  *   ~              ^ escape
58  */
59 char ctrlparse(char *s, char **next)
60 {
61     char c = 0;
62     if (*s != '^') {
63         *next = NULL;
64     } else {
65         s++;
66         if (*s == '\0') {
67             *next = NULL;
68         } else if (*s == '<') {
69             s++;
70             c = (char)strtol(s, next, 0);
71             if ((*next == s) || (**next != '>')) {
72                 c = 0;
73                 *next = NULL;
74             } else
75                 (*next)++;
76         } else if (*s >= 'a' && *s <= 'z') {
77             c = (*s - ('a' - 1));
78             *next = s+1;
79         } else if ((*s >= '@' && *s <= '_') || *s == '?' || (*s & 0x80)) {
80             c = ('@' ^ *s);
81             *next = s+1;
82         } else if (*s == '~') {
83             c = '^';
84             *next = s+1;
85         }
86     }
87     return c;
88 }
89
90 /* ----------------------------------------------------------------------
91  * String handling routines.
92  */
93
94 char *dupstr(const char *s)
95 {
96     char *p = NULL;
97     if (s) {
98         int len = strlen(s);
99         p = snewn(len + 1, char);
100         strcpy(p, s);
101     }
102     return p;
103 }
104
105 /* Allocate the concatenation of N strings. Terminate arg list with NULL. */
106 char *dupcat(const char *s1, ...)
107 {
108     int len;
109     char *p, *q, *sn;
110     va_list ap;
111
112     len = strlen(s1);
113     va_start(ap, s1);
114     while (1) {
115         sn = va_arg(ap, char *);
116         if (!sn)
117             break;
118         len += strlen(sn);
119     }
120     va_end(ap);
121
122     p = snewn(len + 1, char);
123     strcpy(p, s1);
124     q = p + strlen(p);
125
126     va_start(ap, s1);
127     while (1) {
128         sn = va_arg(ap, char *);
129         if (!sn)
130             break;
131         strcpy(q, sn);
132         q += strlen(q);
133     }
134     va_end(ap);
135
136     return p;
137 }
138
139 /*
140  * Do an sprintf(), but into a custom-allocated buffer.
141  * 
142  * Currently I'm doing this via vsnprintf. This has worked so far,
143  * but it's not good, because:
144  * 
145  *  - vsnprintf is not available on all platforms. There's an ifdef
146  *    to use `_vsnprintf', which seems to be the local name for it
147  *    on Windows. Other platforms may lack it completely, in which
148  *    case it'll be time to rewrite this function in a totally
149  *    different way.
150  * 
151  *  - technically you can't reuse a va_list like this: it is left
152  *    unspecified whether advancing a va_list pointer modifies its
153  *    value or something it points to, so on some platforms calling
154  *    vsnprintf twice on the same va_list might fail hideously. It
155  *    would be better to use the `va_copy' macro mandated by C99,
156  *    but that too is not yet ubiquitous.
157  * 
158  * The only `properly' portable solution I can think of is to
159  * implement my own format string scanner, which figures out an
160  * upper bound for the length of each formatting directive,
161  * allocates the buffer as it goes along, and calls sprintf() to
162  * actually process each directive. If I ever need to actually do
163  * this, some caveats:
164  * 
165  *  - It's very hard to find a reliable upper bound for
166  *    floating-point values. %f, in particular, when supplied with
167  *    a number near to the upper or lower limit of representable
168  *    numbers, could easily take several hundred characters. It's
169  *    probably feasible to predict this statically using the
170  *    constants in <float.h>, or even to predict it dynamically by
171  *    looking at the exponent of the specific float provided, but
172  *    it won't be fun.
173  * 
174  *  - Don't forget to _check_, after calling sprintf, that it's
175  *    used at most the amount of space we had available.
176  * 
177  *  - Fault any formatting directive we don't fully understand. The
178  *    aim here is to _guarantee_ that we never overflow the buffer,
179  *    because this is a security-critical function. If we see a
180  *    directive we don't know about, we should panic and die rather
181  *    than run any risk.
182  */
183 char *dupprintf(const char *fmt, ...)
184 {
185     char *ret;
186     va_list ap;
187     va_start(ap, fmt);
188     ret = dupvprintf(fmt, ap);
189     va_end(ap);
190     return ret;
191 }
192 char *dupvprintf(const char *fmt, va_list ap)
193 {
194     char *buf;
195     int len, size;
196
197     buf = snewn(512, char);
198     size = 512;
199
200     while (1) {
201 #ifdef _WINDOWS
202 #define vsnprintf _vsnprintf
203 #endif
204         len = vsnprintf(buf, size, fmt, ap);
205         if (len >= 0 && len < size) {
206             /* This is the C99-specified criterion for snprintf to have
207              * been completely successful. */
208             return buf;
209         } else if (len > 0) {
210             /* This is the C99 error condition: the returned length is
211              * the required buffer size not counting the NUL. */
212             size = len + 1;
213         } else {
214             /* This is the pre-C99 glibc error condition: <0 means the
215              * buffer wasn't big enough, so we enlarge it a bit and hope. */
216             size += 512;
217         }
218         buf = sresize(buf, size, char);
219     }
220 }
221
222 /*
223  * Read an entire line of text from a file. Return a buffer
224  * malloced to be as big as necessary (caller must free).
225  */
226 char *fgetline(FILE *fp)
227 {
228     char *ret = snewn(512, char);
229     int size = 512, len = 0;
230     while (fgets(ret + len, size - len, fp)) {
231         len += strlen(ret + len);
232         if (ret[len-1] == '\n')
233             break;                     /* got a newline, we're done */
234         size = len + 512;
235         ret = sresize(ret, size, char);
236     }
237     if (len == 0) {                    /* first fgets returned NULL */
238         sfree(ret);
239         return NULL;
240     }
241     ret[len] = '\0';
242     return ret;
243 }
244
245 /* ----------------------------------------------------------------------
246  * Base64 encoding routine. This is required in public-key writing
247  * but also in HTTP proxy handling, so it's centralised here.
248  */
249
250 void base64_encode_atom(unsigned char *data, int n, char *out)
251 {
252     static const char base64_chars[] =
253         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
254
255     unsigned word;
256
257     word = data[0] << 16;
258     if (n > 1)
259         word |= data[1] << 8;
260     if (n > 2)
261         word |= data[2];
262     out[0] = base64_chars[(word >> 18) & 0x3F];
263     out[1] = base64_chars[(word >> 12) & 0x3F];
264     if (n > 1)
265         out[2] = base64_chars[(word >> 6) & 0x3F];
266     else
267         out[2] = '=';
268     if (n > 2)
269         out[3] = base64_chars[word & 0x3F];
270     else
271         out[3] = '=';
272 }
273
274 /* ----------------------------------------------------------------------
275  * Generic routines to deal with send buffers: a linked list of
276  * smallish blocks, with the operations
277  * 
278  *  - add an arbitrary amount of data to the end of the list
279  *  - remove the first N bytes from the list
280  *  - return a (pointer,length) pair giving some initial data in
281  *    the list, suitable for passing to a send or write system
282  *    call
283  *  - retrieve a larger amount of initial data from the list
284  *  - return the current size of the buffer chain in bytes
285  */
286
287 #define BUFFER_GRANULE  512
288
289 struct bufchain_granule {
290     struct bufchain_granule *next;
291     int buflen, bufpos;
292     char buf[BUFFER_GRANULE];
293 };
294
295 void bufchain_init(bufchain *ch)
296 {
297     ch->head = ch->tail = NULL;
298     ch->buffersize = 0;
299 }
300
301 void bufchain_clear(bufchain *ch)
302 {
303     struct bufchain_granule *b;
304     while (ch->head) {
305         b = ch->head;
306         ch->head = ch->head->next;
307         sfree(b);
308     }
309     ch->tail = NULL;
310     ch->buffersize = 0;
311 }
312
313 int bufchain_size(bufchain *ch)
314 {
315     return ch->buffersize;
316 }
317
318 void bufchain_add(bufchain *ch, const void *data, int len)
319 {
320     const char *buf = (const char *)data;
321
322     if (len == 0) return;
323
324     ch->buffersize += len;
325
326     if (ch->tail && ch->tail->buflen < BUFFER_GRANULE) {
327         int copylen = min(len, BUFFER_GRANULE - ch->tail->buflen);
328         memcpy(ch->tail->buf + ch->tail->buflen, buf, copylen);
329         buf += copylen;
330         len -= copylen;
331         ch->tail->buflen += copylen;
332     }
333     while (len > 0) {
334         int grainlen = min(len, BUFFER_GRANULE);
335         struct bufchain_granule *newbuf;
336         newbuf = snew(struct bufchain_granule);
337         newbuf->bufpos = 0;
338         newbuf->buflen = grainlen;
339         memcpy(newbuf->buf, buf, grainlen);
340         buf += grainlen;
341         len -= grainlen;
342         if (ch->tail)
343             ch->tail->next = newbuf;
344         else
345             ch->head = ch->tail = newbuf;
346         newbuf->next = NULL;
347         ch->tail = newbuf;
348     }
349 }
350
351 void bufchain_consume(bufchain *ch, int len)
352 {
353     struct bufchain_granule *tmp;
354
355     assert(ch->buffersize >= len);
356     while (len > 0) {
357         int remlen = len;
358         assert(ch->head != NULL);
359         if (remlen >= ch->head->buflen - ch->head->bufpos) {
360             remlen = ch->head->buflen - ch->head->bufpos;
361             tmp = ch->head;
362             ch->head = tmp->next;
363             sfree(tmp);
364             if (!ch->head)
365                 ch->tail = NULL;
366         } else
367             ch->head->bufpos += remlen;
368         ch->buffersize -= remlen;
369         len -= remlen;
370     }
371 }
372
373 void bufchain_prefix(bufchain *ch, void **data, int *len)
374 {
375     *len = ch->head->buflen - ch->head->bufpos;
376     *data = ch->head->buf + ch->head->bufpos;
377 }
378
379 void bufchain_fetch(bufchain *ch, void *data, int len)
380 {
381     struct bufchain_granule *tmp;
382     char *data_c = (char *)data;
383
384     tmp = ch->head;
385
386     assert(ch->buffersize >= len);
387     while (len > 0) {
388         int remlen = len;
389
390         assert(tmp != NULL);
391         if (remlen >= tmp->buflen - tmp->bufpos)
392             remlen = tmp->buflen - tmp->bufpos;
393         memcpy(data_c, tmp->buf + tmp->bufpos, remlen);
394
395         tmp = tmp->next;
396         len -= remlen;
397         data_c += remlen;
398     }
399 }
400
401 /* ----------------------------------------------------------------------
402  * My own versions of malloc, realloc and free. Because I want
403  * malloc and realloc to bomb out and exit the program if they run
404  * out of memory, realloc to reliably call malloc if passed a NULL
405  * pointer, and free to reliably do nothing if passed a NULL
406  * pointer. We can also put trace printouts in, if we need to; and
407  * we can also replace the allocator with an ElectricFence-like
408  * one.
409  */
410
411 #ifdef MINEFIELD
412 void *minefield_c_malloc(size_t size);
413 void minefield_c_free(void *p);
414 void *minefield_c_realloc(void *p, size_t size);
415 #endif
416
417 #ifdef MALLOC_LOG
418 static FILE *fp = NULL;
419
420 static char *mlog_file = NULL;
421 static int mlog_line = 0;
422
423 void mlog(char *file, int line)
424 {
425     mlog_file = file;
426     mlog_line = line;
427     if (!fp) {
428         fp = fopen("putty_mem.log", "w");
429         setvbuf(fp, NULL, _IONBF, BUFSIZ);
430     }
431     if (fp)
432         fprintf(fp, "%s:%d: ", file, line);
433 }
434 #endif
435
436 void *safemalloc(size_t n, size_t size)
437 {
438     void *p;
439
440     if (n > INT_MAX / size) {
441         p = NULL;
442     } else {
443         size *= n;
444         if (size == 0) size = 1;
445 #ifdef MINEFIELD
446         p = minefield_c_malloc(size);
447 #else
448         p = malloc(size);
449 #endif
450     }
451
452     if (!p) {
453         char str[200];
454 #ifdef MALLOC_LOG
455         sprintf(str, "Out of memory! (%s:%d, size=%d)",
456                 mlog_file, mlog_line, size);
457         fprintf(fp, "*** %s\n", str);
458         fclose(fp);
459 #else
460         strcpy(str, "Out of memory!");
461 #endif
462         modalfatalbox(str);
463     }
464 #ifdef MALLOC_LOG
465     if (fp)
466         fprintf(fp, "malloc(%d) returns %p\n", size, p);
467 #endif
468     return p;
469 }
470
471 void *saferealloc(void *ptr, size_t n, size_t size)
472 {
473     void *p;
474
475     if (n > INT_MAX / size) {
476         p = NULL;
477     } else {
478         size *= n;
479         if (!ptr) {
480 #ifdef MINEFIELD
481             p = minefield_c_malloc(size);
482 #else
483             p = malloc(size);
484 #endif
485         } else {
486 #ifdef MINEFIELD
487             p = minefield_c_realloc(ptr, size);
488 #else
489             p = realloc(ptr, size);
490 #endif
491         }
492     }
493
494     if (!p) {
495         char str[200];
496 #ifdef MALLOC_LOG
497         sprintf(str, "Out of memory! (%s:%d, size=%d)",
498                 mlog_file, mlog_line, size);
499         fprintf(fp, "*** %s\n", str);
500         fclose(fp);
501 #else
502         strcpy(str, "Out of memory!");
503 #endif
504         modalfatalbox(str);
505     }
506 #ifdef MALLOC_LOG
507     if (fp)
508         fprintf(fp, "realloc(%p,%d) returns %p\n", ptr, size, p);
509 #endif
510     return p;
511 }
512
513 void safefree(void *ptr)
514 {
515     if (ptr) {
516 #ifdef MALLOC_LOG
517         if (fp)
518             fprintf(fp, "free(%p)\n", ptr);
519 #endif
520 #ifdef MINEFIELD
521         minefield_c_free(ptr);
522 #else
523         free(ptr);
524 #endif
525     }
526 #ifdef MALLOC_LOG
527     else if (fp)
528         fprintf(fp, "freeing null pointer - no action taken\n");
529 #endif
530 }
531
532 /* ----------------------------------------------------------------------
533  * Debugging routines.
534  */
535
536 #ifdef DEBUG
537 extern void dputs(char *);             /* defined in per-platform *misc.c */
538
539 void debug_printf(char *fmt, ...)
540 {
541     char *buf;
542     va_list ap;
543
544     va_start(ap, fmt);
545     buf = dupvprintf(fmt, ap);
546     dputs(buf);
547     sfree(buf);
548     va_end(ap);
549 }
550
551
552 void debug_memdump(void *buf, int len, int L)
553 {
554     int i;
555     unsigned char *p = buf;
556     char foo[17];
557     if (L) {
558         int delta;
559         debug_printf("\t%d (0x%x) bytes:\n", len, len);
560         delta = 15 & (int) p;
561         p -= delta;
562         len += delta;
563     }
564     for (; 0 < len; p += 16, len -= 16) {
565         dputs("  ");
566         if (L)
567             debug_printf("%p: ", p);
568         strcpy(foo, "................");        /* sixteen dots */
569         for (i = 0; i < 16 && i < len; ++i) {
570             if (&p[i] < (unsigned char *) buf) {
571                 dputs("   ");          /* 3 spaces */
572                 foo[i] = ' ';
573             } else {
574                 debug_printf("%c%02.2x",
575                         &p[i] != (unsigned char *) buf
576                         && i % 4 ? '.' : ' ', p[i]
577                     );
578                 if (p[i] >= ' ' && p[i] <= '~')
579                     foo[i] = (char) p[i];
580             }
581         }
582         foo[i] = '\0';
583         debug_printf("%*s%s\n", (16 - i) * 3 + 2, "", foo);
584     }
585 }
586
587 #endif                          /* def DEBUG */