X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/94e1f16d6033683bdebaf5092f64c58bc044dd2d..e34f8ca2022e340d3c0e36260a0232fab306dfcc:/src/src/string.c diff --git a/src/src/string.c b/src/src/string.c index cfe801284..50442bced 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2016 */ +/* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ /* Miscellaneous string-handling functions. Some are not required for @@ -1050,12 +1050,40 @@ return list; +/************************************************/ +/* Create a growable-string with some preassigned space */ + +gstring * +string_get(unsigned size) +{ +gstring * g = store_get(sizeof(gstring) + size); +g->size = size; +g->ptr = 0; +g->s = US(g + 1); +return g; +} + +/* NUL-terminate the C string in the growable-string, and return it. */ + +uschar * +string_from_gstring(gstring * g) +{ +if (!g) return NULL; +g->s[g->ptr] = '\0'; +return g->s; +} + /************************************************* * Add chars to string * *************************************************/ -/* See inline functions in functions.h */ -void +/* Arguments: + g the grawable-string + p current end of data + count amount to grow by +*/ + +static void gstring_grow(gstring * g, int p, int count) { int oldsize = g->size; @@ -1080,13 +1108,62 @@ was the last item on the dynamic memory stack. This is the case if it matches store_last_get. */ if (!store_extend(g->s, oldsize, g->size)) + g->s = store_newblock(g->s, g->size, p); +} + + + +/* This function is used when building up strings of unknown length. Room is +always left for a terminating zero to be added to the string that is being +built. This function does not require the string that is being added to be NUL +terminated, because the number of characters to add is given explicitly. It is +sometimes called to extract parts of other strings. + +Arguments: + string points to the start of the string that is being built, or NULL + if this is a new string that has no contents yet + s points to characters to add + count count of characters to add; must not exceed the length of s, if s + is a C string. + +Returns: pointer to the start of the string, changed if copied for expansion. + Note that a NUL is not added, though space is left for one. This is + because string_cat() is often called multiple times to build up a + string - there's no point adding the NUL till the end. + +*/ +/* coverity[+alloc] */ + +gstring * +string_catn(gstring * g, const uschar *s, int count) +{ +int p; + +if (!g) { - BOOL release_ok = store_last_get[store_pool] == g->s; - uschar *newstring = store_get(g->size); - memcpy(newstring, g->s, p); - if (release_ok) store_release(g->s); - g->s = newstring; + unsigned inc = count < 4096 ? 127 : 1023; + unsigned size = ((count + inc) & ~inc) + 1; + g = string_get(size); } + +p = g->ptr; +if (p + count >= g->size) + gstring_grow(g, p, count); + +/* Because we always specify the exact number of characters to copy, we can +use memcpy(), which is likely to be more efficient than strncopy() because the +latter has to check for zero bytes. */ + +memcpy(g->s + p, s, count); +g->ptr = p + count; +return g; +} + + +gstring * +string_cat(gstring *string, const uschar *s) +{ +return string_catn(string, s, Ustrlen(s)); } @@ -1295,10 +1372,20 @@ while (*fp != 0) break; case 'p': - if (p >= last - 24) { yield = FALSE; goto END_FORMAT; } - strncpy(newformat, item_start, fp - item_start); - newformat[fp - item_start] = 0; - p += sprintf(CS p, newformat, va_arg(ap, void *)); + { + void * ptr; + if (p >= last - 24) { yield = FALSE; goto END_FORMAT; } + /* sprintf() saying "(nil)" for a null pointer seems unreliable. + Handle it explicitly. */ + if ((ptr = va_arg(ap, void *))) + { + strncpy(newformat, item_start, fp - item_start); + newformat[fp - item_start] = 0; + p += sprintf(CS p, newformat, ptr); + } + else + p += sprintf(CS p, "(nil)"); + } break; /* %f format is inherently insecure if the numbers that it may be