The branch, master has been updated via 2fff0a4 Merge latest samba version to get va_end() fixes, etc. from cb0db58 Fix unwritable directory issue due to misordered chmod call.
;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 2fff0a4f281523e3d62018f169585ad88aa5b12b Author: Wayne Davison <way...@samba.org> Date: Mon May 30 10:24:57 2011 -0700 Merge latest samba version to get va_end() fixes, etc. ----------------------------------------------------------------------- Summary of changes: lib/snprintf.c | 910 +++++++++++++++++++++++++++++++++++++++++++------------- 1 files changed, 699 insertions(+), 211 deletions(-) Changeset truncated at 500 lines: diff --git a/lib/snprintf.c b/lib/snprintf.c index d2072fb..f7ab908 100644 --- a/lib/snprintf.c +++ b/lib/snprintf.c @@ -89,13 +89,21 @@ * * Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even * if the C library has some snprintf functions already. + * + * Darren Tucker (dtuc...@zip.com.au) 2005 + * Fix bug allowing read overruns of the source string with "%.*s" + * Usually harmless unless the read runs outside the process' allocation + * (eg if your malloc does guard pages) in which case it will segfault. + * From OpenSSH. Also added test for same. + * + * Simo Sorce (i...@samba.org) Jan 2006 + * + * Add support for position independent parameters + * fix fmtstr now it conforms to sprintf wrt min.max + * **************************************************************/ -#ifndef NO_CONFIG_H -#include "config.h" -#else -#define NULL 0 -#endif +#include "../config.h" #ifdef TEST_SNPRINTF /* need math library headers for testing */ @@ -133,13 +141,19 @@ void dummy_snprintf(void) {} #endif /* HAVE_SNPRINTF, etc */ +/* yes this really must be a ||. Don't muck with this (tridge) */ +#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF) + #ifdef HAVE_LONG_DOUBLE #define LDOUBLE long double #else #define LDOUBLE double #endif -#if SIZEOF_LONG_LONG +#if !defined HAVE_LONG_LONG && SIZEOF_LONG_LONG +#define HAVE_LONG_LONG 1 +#endif +#ifdef HAVE_LONG_LONG #define LLONG long long #else #define LLONG long @@ -180,82 +194,145 @@ #define DP_F_UNSIGNED (1 << 6) /* Conversion Flags */ -#define DP_C_SHORT 1 -#define DP_C_LONG 2 -#define DP_C_LDOUBLE 3 -#define DP_C_LLONG 4 +#define DP_C_CHAR 1 +#define DP_C_SHORT 2 +#define DP_C_LONG 3 +#define DP_C_LDOUBLE 4 +#define DP_C_LLONG 5 +#define DP_C_SIZET 6 + +/* Chunk types */ +#define CNK_FMT_STR 0 +#define CNK_INT 1 +#define CNK_OCTAL 2 +#define CNK_UINT 3 +#define CNK_HEX 4 +#define CNK_FLOAT 5 +#define CNK_CHAR 6 +#define CNK_STRING 7 +#define CNK_PTR 8 +#define CNK_NUM 9 +#define CNK_PRCNT 10 #define char_to_int(p) ((p)- '0') #ifndef MAX #define MAX(p,q) (((p) >= (q)) ? (p) : (q)) #endif -/* yes this really must be a ||. Don't muck with this (tridge) */ -#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF) - -static size_t dopr(char *buffer, size_t maxlen, const char *format, +struct pr_chunk { + int type; /* chunk type */ + int num; /* parameter number */ + int min; + int max; + int flags; + int cflags; + int start; + int len; + LLONG value; + LDOUBLE fvalue; + char *strvalue; + void *pnum; + struct pr_chunk *min_star; + struct pr_chunk *max_star; + struct pr_chunk *next; +}; + +struct pr_chunk_x { + struct pr_chunk **chunks; + int num; +}; + +static int dopr(char *buffer, size_t maxlen, const char *format, va_list args_in); static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, int min, int max); static void fmtint(char *buffer, size_t *currlen, size_t maxlen, - long value, int base, int min, int max, int flags); + LLONG value, int base, int min, int max, int flags); static void fmtfp(char *buffer, size_t *currlen, size_t maxlen, LDOUBLE fvalue, int min, int max, int flags); static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c); +static struct pr_chunk *new_chunk(void); +static int add_cnk_list_entry(struct pr_chunk_x **list, + int max_num, struct pr_chunk *chunk); -static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args_in) +static int dopr(char *buffer, size_t maxlen, const char *format, va_list args_in) { char ch; - LLONG value; - LDOUBLE fvalue; - char *strvalue; - int min; - int max; int state; - int flags; - int cflags; + int pflag; + int pnum; + int pfirst; size_t currlen; va_list args; + const char *base; + struct pr_chunk *chunks = NULL; + struct pr_chunk *cnk = NULL; + struct pr_chunk_x *clist = NULL; + int max_pos; + int ret = -1; VA_COPY(args, args_in); - + state = DP_S_DEFAULT; - currlen = flags = cflags = min = 0; - max = -1; + pfirst = 1; + pflag = 0; + pnum = 0; + + max_pos = 0; + base = format; ch = *format++; + /* retrieve the string structure as chunks */ while (state != DP_S_DONE) { if (ch == '\0') state = DP_S_DONE; switch(state) { case DP_S_DEFAULT: - if (ch == '%') + + if (cnk) { + cnk->next = new_chunk(); + cnk = cnk->next; + } else { + cnk = new_chunk(); + } + if (!cnk) goto done; + if (!chunks) chunks = cnk; + + if (ch == '%') { state = DP_S_FLAGS; - else - dopr_outch (buffer, &currlen, maxlen, ch); - ch = *format++; + ch = *format++; + } else { + cnk->type = CNK_FMT_STR; + cnk->start = format - base -1; + while ((ch != '\0') && (ch != '%')) ch = *format++; + cnk->len = format - base - cnk->start -1; + } break; case DP_S_FLAGS: switch (ch) { case '-': - flags |= DP_F_MINUS; + cnk->flags |= DP_F_MINUS; ch = *format++; break; case '+': - flags |= DP_F_PLUS; + cnk->flags |= DP_F_PLUS; ch = *format++; break; case ' ': - flags |= DP_F_SPACE; + cnk->flags |= DP_F_SPACE; ch = *format++; break; case '#': - flags |= DP_F_NUM; + cnk->flags |= DP_F_NUM; ch = *format++; break; case '0': - flags |= DP_F_ZERO; + cnk->flags |= DP_F_ZERO; + ch = *format++; + break; + case 'I': + /* internationalization not supported yet */ ch = *format++; break; default: @@ -265,13 +342,51 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args break; case DP_S_MIN: if (isdigit((unsigned char)ch)) { - min = 10*min + char_to_int (ch); + cnk->min = 10 * cnk->min + char_to_int (ch); + ch = *format++; + } else if (ch == '$') { + if (!pfirst && !pflag) { + /* parameters must be all positioned or none */ + goto done; + } + if (pfirst) { + pfirst = 0; + pflag = 1; + } + if (cnk->min == 0) /* what ?? */ + goto done; + cnk->num = cnk->min; + cnk->min = 0; ch = *format++; } else if (ch == '*') { - min = va_arg (args, int); + if (pfirst) pfirst = 0; + cnk->min_star = new_chunk(); + if (!cnk->min_star) /* out of memory :-( */ + goto done; + cnk->min_star->type = CNK_INT; + if (pflag) { + int num; + ch = *format++; + if (!isdigit((unsigned char)ch)) { + /* parameters must be all positioned or none */ + goto done; + } + for (num = 0; isdigit((unsigned char)ch); ch = *format++) { + num = 10 * num + char_to_int(ch); + } + cnk->min_star->num = num; + if (ch != '$') /* what ?? */ + goto done; + } else { + cnk->min_star->num = ++pnum; + } + max_pos = add_cnk_list_entry(&clist, max_pos, cnk->min_star); + if (max_pos == 0) /* out of memory :-( */ + goto done; ch = *format++; state = DP_S_DOT; } else { + if (pfirst) pfirst = 0; state = DP_S_DOT; } break; @@ -285,12 +400,45 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args break; case DP_S_MAX: if (isdigit((unsigned char)ch)) { - if (max < 0) - max = 0; - max = 10*max + char_to_int (ch); + if (cnk->max < 0) + cnk->max = 0; + cnk->max = 10 * cnk->max + char_to_int (ch); + ch = *format++; + } else if (ch == '$') { + if (!pfirst && !pflag) { + /* parameters must be all positioned or none */ + goto done; + } + if (cnk->max <= 0) /* what ?? */ + goto done; + cnk->num = cnk->max; + cnk->max = -1; ch = *format++; } else if (ch == '*') { - max = va_arg (args, int); + cnk->max_star = new_chunk(); + if (!cnk->max_star) /* out of memory :-( */ + goto done; + cnk->max_star->type = CNK_INT; + if (pflag) { + int num; + ch = *format++; + if (!isdigit((unsigned char)ch)) { + /* parameters must be all positioned or none */ + goto done; + } + for (num = 0; isdigit((unsigned char)ch); ch = *format++) { + num = 10 * num + char_to_int(ch); + } + cnk->max_star->num = num; + if (ch != '$') /* what ?? */ + goto done; + } else { + cnk->max_star->num = ++pnum; + } + max_pos = add_cnk_list_entry(&clist, max_pos, cnk->max_star); + if (max_pos == 0) /* out of memory :-( */ + goto done; + ch = *format++; state = DP_S_MOD; } else { @@ -300,19 +448,27 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args case DP_S_MOD: switch (ch) { case 'h': - cflags = DP_C_SHORT; + cnk->cflags = DP_C_SHORT; ch = *format++; + if (ch == 'h') { + cnk->cflags = DP_C_CHAR; + ch = *format++; + } break; case 'l': - cflags = DP_C_LONG; + cnk->cflags = DP_C_LONG; ch = *format++; if (ch == 'l') { /* It's a long long */ - cflags = DP_C_LLONG; + cnk->cflags = DP_C_LLONG; ch = *format++; } break; case 'L': - cflags = DP_C_LDOUBLE; + cnk->cflags = DP_C_LDOUBLE; + ch = *format++; + break; + case 'z': + cnk->cflags = DP_C_SIZET; ch = *format++; break; default: @@ -321,133 +477,65 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args state = DP_S_CONV; break; case DP_S_CONV: + if (cnk->num == 0) cnk->num = ++pnum; + max_pos = add_cnk_list_entry(&clist, max_pos, cnk); + if (max_pos == 0) /* out of memory :-( */ + goto done; + switch (ch) { case 'd': case 'i': - if (cflags == DP_C_SHORT) - value = va_arg (args, int); - else if (cflags == DP_C_LONG) - value = va_arg (args, long int); - else if (cflags == DP_C_LLONG) - value = va_arg (args, LLONG); - else - value = va_arg (args, int); - fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); + cnk->type = CNK_INT; break; case 'o': - flags |= DP_F_UNSIGNED; - if (cflags == DP_C_SHORT) - value = va_arg (args, unsigned int); - else if (cflags == DP_C_LONG) - value = (long)va_arg (args, unsigned long int); - else if (cflags == DP_C_LLONG) - value = (long)va_arg (args, unsigned LLONG); - else - value = (long)va_arg (args, unsigned int); - fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags); + cnk->type = CNK_OCTAL; + cnk->flags |= DP_F_UNSIGNED; break; case 'u': - flags |= DP_F_UNSIGNED; - if (cflags == DP_C_SHORT) - value = va_arg (args, unsigned int); - else if (cflags == DP_C_LONG) - value = (long)va_arg (args, unsigned long int); - else if (cflags == DP_C_LLONG) - value = (LLONG)va_arg (args, unsigned LLONG); - else - value = (long)va_arg (args, unsigned int); - fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); + cnk->type = CNK_UINT; + cnk->flags |= DP_F_UNSIGNED; break; case 'X': - flags |= DP_F_UP; + cnk->flags |= DP_F_UP; case 'x': - flags |= DP_F_UNSIGNED; - if (cflags == DP_C_SHORT) - value = va_arg (args, unsigned int); - else if (cflags == DP_C_LONG) - value = (long)va_arg (args, unsigned long int); - else if (cflags == DP_C_LLONG) - value = (LLONG)va_arg (args, unsigned LLONG); - else - value = (long)va_arg (args, unsigned int); - fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags); - break; - case 'f': - if (cflags == DP_C_LDOUBLE) - fvalue = va_arg (args, LDOUBLE); - else - fvalue = va_arg (args, double); - /* um, floating point? */ - fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); + cnk->type = CNK_HEX; + cnk->flags |= DP_F_UNSIGNED; break; + case 'A': + /* hex float not supported yet */ case 'E': - flags |= DP_F_UP; - case 'e': - if (cflags == DP_C_LDOUBLE) - fvalue = va_arg (args, LDOUBLE); - else - fvalue = va_arg (args, double); - fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); - break; case 'G': - flags |= DP_F_UP; + case 'F': + cnk->flags |= DP_F_UP; + case 'a': + /* hex float not supported yet */ + case 'e': + case 'f': case 'g': - if (cflags == DP_C_LDOUBLE) - fvalue = va_arg (args, LDOUBLE); - else - fvalue = va_arg (args, double); - fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); + cnk->type = CNK_FLOAT; break; case 'c': - dopr_outch (buffer, &currlen, maxlen, va_arg (args, int)); + cnk->type = CNK_CHAR; break; case 's': - strvalue = va_arg (args, char *); - if (!strvalue) strvalue = "(NULL)"; - if (max == -1) { - max = strlen(strvalue); - } - if (min > 0 && max >= 0 && min > max) max = min; - fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max); + cnk->type = CNK_STRING; break; case 'p': - strvalue = va_arg (args, void *); - fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags); + cnk->type = CNK_PTR; + cnk->flags |= DP_F_UNSIGNED; break; case 'n': - if (cflags == DP_C_SHORT) { - short int *num; - num = va_arg (args, short int *); - *num = currlen; - } else if (cflags == DP_C_LONG) { - long int *num; - num = va_arg (args, long int *); - *num = (long int)currlen; - } else if (cflags == DP_C_LLONG) { - LLONG *num; - num = va_arg (args, LLONG *); - *num = (LLONG)currlen; - } else { -- The rsync repository. _______________________________________________ rsync-cvs mailing list rsync-cvs@lists.samba.org https://lists.samba.org/mailman/listinfo/rsync-cvs