BUG #1044: snprintf() shipped with PostgreSQL is not thread safe - Mailing list pgsql-bugs
From | PostgreSQL Bugs List |
---|---|
Subject | BUG #1044: snprintf() shipped with PostgreSQL is not thread safe |
Date | |
Msg-id | 20040108075001.2C12ACF522F@www.postgresql.com Whole thread Raw |
Responses |
Re: BUG #1044: snprintf() shipped with PostgreSQL is not thread safe
|
List | pgsql-bugs |
The following bug has been logged online: Bug reference: 1044 Logged by: Denis Stepanov Email address: D.N.Stepanov@inp.nsk.su PostgreSQL version: 7.4 Operating system: Any OS lacking proper snprintf() Description: snprintf() shipped with PostgreSQL is not thread safe Details: Some OSes lack proper snprintf()/vsnprintf() fuctions so PostgreSQL includes its own version (src/port/snprintf.c) during building. Unfortunately, this version of snprintf() is not reentrant (it uses global vars to keep internal state), so for example running libpq-based concurrent applications (threads) causes libpq fuctions to fail sometimes. The suggestion is to remove globals usage in src/port/snprintf.c. I am attaching here a sample patch for your review. Thanks. --- postgresql-7.4.1/src/port/snprintf.c Thu Jul 18 11:13:59 2002 +++ postgresql-7.4.1.fixed/src/port/snprintf.c Thu Jan 8 13:23:47 2004 @@ -67,6 +67,9 @@ * Sigh. This sort of thing is always nasty do deal with. Note that * the version here does not include floating point. (now it does ... tgl) * + * Denis Stepanov Thu Jan 8 13:01:01 NOVT 2004 + * Made functions reentrant (thread safe). + * * snprintf() is used instead of sprintf() as it does limit checks * for string length. This covers a nasty loophole. * @@ -75,12 +78,18 @@ **************************************************************/ /*static char _id[] = "$Id: snprintf.c,v 1.1 2002/07/18 04:13:59 momjian Exp $";*/ -static char *end; -static int SnprfOverflow; + +typedef struct _vsnprintf_data +{ + int SnprfOverflow; + char *end; + char *output; + +} vsnprintf_data; int snprintf(char *str, size_t count, const char *fmt,...); int vsnprintf(char *str, size_t count, const char *fmt, va_list args); -static void dopr(char *buffer, const char *format, va_list args); +static void dopr(char *buffer, const char *format, va_list args, vsnprintf_data *vsnpd); int snprintf(char *str, size_t count, const char *fmt,...) @@ -98,12 +107,14 @@ int vsnprintf(char *str, size_t count, const char *fmt, va_list args) { + vsnprintf_data vsnpd; + str[0] = '\0'; - end = str + count - 1; - SnprfOverflow = 0; - dopr(str, fmt, args); + vsnpd.end = str + count - 1; + vsnpd.SnprfOverflow = 0; + dopr(str, fmt, args, &vsnpd); if (count > 0) - end[0] = '\0'; + vsnpd.end[0] = '\0'; return strlen(str); } @@ -111,17 +122,16 @@ * dopr(): poor man's version of doprintf */ -static void fmtstr(char *value, int ljust, int len, int zpad, int maxwidth); -static void fmtnum(long_long value, int base, int dosign, int ljust, int len, int zpad); -static void fmtfloat(double value, char type, int ljust, int len, int precision, int pointflag); -static void dostr(char *str, int cut); -static void dopr_outch(int c); +static void fmtstr(char *value, int ljust, int len, int zpad, int maxwidth, vsnprintf_data *vsnpd); +static void fmtnum(long_long value, int base, int dosign, int ljust, int len, int zpad, vsnprintf_data *vsnpd); +static void fmtfloat(double value, char type, int ljust, int len, int precision, int pointflag, vsnprintf_data *vsnpd); +static void dostr(char *str, int cut, vsnprintf_data *vsnpd); +static void dopr_outch(int c, vsnprintf_data *vsnpd); -static char *output; static void -dopr(char *buffer, const char *format, va_list args) +dopr(char *buffer, const char *format, va_list args, vsnprintf_data *vsnpd) { int ch; long_long value; @@ -135,7 +145,7 @@ int len; int zpad; - output = buffer; + vsnpd->output = buffer; while ((ch = *format++)) { switch (ch) @@ -148,8 +158,8 @@ switch (ch) { case 0: - dostr("**end of format**", 0); - *output = '\0'; + dostr("**end of format**", 0, vsnpd); + *vsnpd->output = '\0'; return; case '-': ljust = 1; @@ -188,7 +198,7 @@ goto nextch; case 'u': case 'U': - /* fmtnum(value,base,dosign,ljust,len,zpad) */ + /* fmtnum(value,base,dosign,ljust,len,zpad,vsnpd) */ if (longflag) { if (longlongflag) @@ -198,11 +208,11 @@ } else value = va_arg(args, unsigned int); - fmtnum(value, 10, 0, ljust, len, zpad); + fmtnum(value, 10, 0, ljust, len, zpad, vsnpd); break; case 'o': case 'O': - /* fmtnum(value,base,dosign,ljust,len,zpad) */ + /* fmtnum(value,base,dosign,ljust,len,zpad,vsnpd) */ if (longflag) { if (longlongflag) @@ -212,7 +222,7 @@ } else value = va_arg(args, unsigned int); - fmtnum(value, 8, 0, ljust, len, zpad); + fmtnum(value, 8, 0, ljust, len, zpad, vsnpd); break; case 'd': case 'D': @@ -225,7 +235,7 @@ } else value = va_arg(args, int); - fmtnum(value, 10, 1, ljust, len, zpad); + fmtnum(value, 10, 1, ljust, len, zpad, vsnpd); break; case 'x': if (longflag) @@ -237,7 +247,7 @@ } else value = va_arg(args, unsigned int); - fmtnum(value, 16, 0, ljust, len, zpad); + fmtnum(value, 16, 0, ljust, len, zpad, vsnpd); break; case 'X': if (longflag) @@ -249,7 +259,7 @@ } else value = va_arg(args, unsigned int); - fmtnum(value, -16, 0, ljust, len, zpad); + fmtnum(value, -16, 0, ljust, len, zpad, vsnpd); break; case 's': strvalue = va_arg(args, char *); @@ -257,12 +267,12 @@ { if (pointflag && len > maxwidth) len = maxwidth; /* Adjust padding */ - fmtstr(strvalue, ljust, len, zpad, maxwidth); + fmtstr(strvalue, ljust, len, zpad, maxwidth, vsnpd); } break; case 'c': ch = va_arg(args, int); - dopr_outch(ch); + dopr_outch(ch, vsnpd); break; case 'e': case 'E': @@ -270,25 +280,25 @@ case 'g': case 'G': fvalue = va_arg(args, double); - fmtfloat(fvalue, ch, ljust, len, maxwidth, pointflag); + fmtfloat(fvalue, ch, ljust, len, maxwidth, pointflag, vsnpd); break; case '%': - dopr_outch(ch); + dopr_outch(ch, vsnpd); continue; default: - dostr("???????", 0); + dostr("???????", 0, vsnpd); } break; default: - dopr_outch(ch); + dopr_outch(ch, vsnpd); break; } } - *output = '\0'; + *vsnpd->output = '\0'; } static void -fmtstr(char *value, int ljust, int len, int zpad, int maxwidth) +fmtstr(char *value, int ljust, int len, int zpad, int maxwidth, vsnprintf_data *vsnpd) { int padlen, strlen; /* amount to pad */ @@ -305,19 +315,19 @@ padlen = -padlen; while (padlen > 0) { - dopr_outch(' '); + dopr_outch(' ', vsnpd); --padlen; } - dostr(value, maxwidth); + dostr(value, maxwidth, vsnpd); while (padlen < 0) { - dopr_outch(' '); + dopr_outch(' ', vsnpd); ++padlen; } } static void -fmtnum(long_long value, int base, int dosign, int ljust, int len, int zpad) +fmtnum(long_long value, int base, int dosign, int ljust, int len, int zpad, vsnprintf_data *vsnpd) { int signvalue = 0; ulong_long uvalue; @@ -372,34 +382,34 @@ { if (signvalue) { - dopr_outch(signvalue); + dopr_outch(signvalue, vsnpd); --padlen; signvalue = 0; } while (padlen > 0) { - dopr_outch(zpad); + dopr_outch(zpad, vsnpd); --padlen; } } while (padlen > 0) { - dopr_outch(' '); + dopr_outch(' ', vsnpd); --padlen; } if (signvalue) - dopr_outch(signvalue); + dopr_outch(signvalue, vsnpd); while (place > 0) - dopr_outch(convert[--place]); + dopr_outch(convert[--place], vsnpd); while (padlen < 0) { - dopr_outch(' '); + dopr_outch(' ', vsnpd); ++padlen; } } static void -fmtfloat(double value, char type, int ljust, int len, int precision, int pointflag) +fmtfloat(double value, char type, int ljust, int len, int precision, int pointflag, vsnprintf_data *vsnpd) { char fmt[32]; char convert[512]; @@ -426,45 +436,45 @@ while (padlen > 0) { - dopr_outch(' '); + dopr_outch(' ', vsnpd); --padlen; } - dostr(convert, 0); + dostr(convert, 0, vsnpd); while (padlen < 0) { - dopr_outch(' '); + dopr_outch(' ', vsnpd); ++padlen; } } static void -dostr(char *str, int cut) +dostr(char *str, int cut, vsnprintf_data *vsnpd) { if (cut) { while (*str && cut-- > 0) - dopr_outch(*str++); + dopr_outch(*str++, vsnpd); } else { while (*str) - dopr_outch(*str++); + dopr_outch(*str++, vsnpd); } } static void -dopr_outch(int c) +dopr_outch(int c, vsnprintf_data *vsnpd) { #ifdef NOT_USED if (iscntrl((unsigned char) c) && c != '\n' && c != '\t') { c = '@' + (c & 0x1F); - if (end == 0 || output < end) - *output++ = '^'; + if (vsnpd->end == 0 || vsnpd->output < vsnpd->end) + *vsnpd->output++ = '^'; } #endif - if (end == 0 || output < end) - *output++ = c; + if (vsnpd->end == 0 || vsnpd->output < vsnpd->end) + *vsnpd->output++ = c; else - SnprfOverflow++; + vsnpd->SnprfOverflow++; }
pgsql-bugs by date: