Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 2cdec8b

Browse files
committed
Fix core dump due to null-pointer dereference in to_char() when datetime
format codes are misapplied to a numeric argument. (The code still produces a pretty bogus error message in such cases, but I'll settle for stopping the crash for now.) Per bug #4700 from Sergey Burladyan. Problem exists in all supported branches, so patch all the way back. In HEAD, also clean up some ugly coding in the nearby cache management code.
1 parent e04810e commit 2cdec8b

File tree

1 file changed

+24
-35
lines changed

1 file changed

+24
-35
lines changed

src/backend/utils/adt/formatting.c

+24-35
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* -----------------------------------------------------------------------
22
* formatting.c
33
*
4-
* $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.154 2009/02/07 14:16:45 momjian Exp $
4+
* $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.155 2009/03/12 00:53:25 tgl Exp $
55
*
66
*
77
* Portions Copyright (c) 1999-2009, PostgreSQL Global Development Group
@@ -392,12 +392,10 @@ static int DCHCounter = 0;
392392

393393
/* global cache for --- number part */
394394
static NUMCacheEntry NUMCache[NUM_CACHE_FIELDS + 1];
395-
static NUMCacheEntry *last_NUMCacheEntry;
396395

397396
static int n_NUMCache = 0; /* number of entries */
398397
static int NUMCounter = 0;
399-
400-
#define MAX_INT32 (2147483600)
398+
static NUMCacheEntry *last_NUMCacheEntry = NUMCache + 0;
401399

402400
/* ----------
403401
* For char->date/time conversion
@@ -2765,10 +2763,10 @@ DCH_from_char(FormatNode *node, char *in, TmFromChar *out)
27652763
static DCHCacheEntry *
27662764
DCH_cache_getnew(char *str)
27672765
{
2768-
DCHCacheEntry *ent = NULL;
2766+
DCHCacheEntry *ent;
27692767

2770-
/* counter overload check - paranoia? */
2771-
if (DCHCounter + DCH_CACHE_FIELDS >= MAX_INT32)
2768+
/* counter overflow check - paranoia? */
2769+
if (DCHCounter >= (INT_MAX - DCH_CACHE_FIELDS - 1))
27722770
{
27732771
DCHCounter = 0;
27742772

@@ -2777,7 +2775,7 @@ DCH_cache_getnew(char *str)
27772775
}
27782776

27792777
/*
2780-
* Cache is full - needs remove any older entry
2778+
* If cache is full, remove oldest entry
27812779
*/
27822780
if (n_DCHCache > DCH_CACHE_FIELDS)
27832781
{
@@ -2786,7 +2784,7 @@ DCH_cache_getnew(char *str)
27862784
#ifdef DEBUG_TO_FROM_CHAR
27872785
elog(DEBUG_elog_output, "cache is full (%d)", n_DCHCache);
27882786
#endif
2789-
for (ent = DCHCache; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++)
2787+
for (ent = DCHCache + 1; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++)
27902788
{
27912789
if (ent->age < old->age)
27922790
old = ent;
@@ -2811,35 +2809,30 @@ DCH_cache_getnew(char *str)
28112809
++n_DCHCache;
28122810
return ent;
28132811
}
2814-
2815-
return NULL; /* never */
28162812
}
28172813

28182814
static DCHCacheEntry *
28192815
DCH_cache_search(char *str)
28202816
{
2821-
int i = 0;
2817+
int i;
28222818
DCHCacheEntry *ent;
28232819

2824-
/* counter overload check - paranoia? */
2825-
if (DCHCounter + DCH_CACHE_FIELDS >= MAX_INT32)
2820+
/* counter overflow check - paranoia? */
2821+
if (DCHCounter >= (INT_MAX - DCH_CACHE_FIELDS - 1))
28262822
{
28272823
DCHCounter = 0;
28282824

28292825
for (ent = DCHCache; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++)
28302826
ent->age = (++DCHCounter);
28312827
}
28322828

2833-
for (ent = DCHCache; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++)
2829+
for (i = 0, ent = DCHCache; i < n_DCHCache; i++, ent++)
28342830
{
2835-
if (i == n_DCHCache)
2836-
break;
28372831
if (strcmp(ent->str, str) == 0)
28382832
{
28392833
ent->age = (++DCHCounter);
28402834
return ent;
28412835
}
2842-
i++;
28432836
}
28442837

28452838
return NULL;
@@ -3371,10 +3364,10 @@ do { \
33713364
static NUMCacheEntry *
33723365
NUM_cache_getnew(char *str)
33733366
{
3374-
NUMCacheEntry *ent = NULL;
3367+
NUMCacheEntry *ent;
33753368

3376-
/* counter overload check - paranoia? */
3377-
if (NUMCounter + NUM_CACHE_FIELDS >= MAX_INT32)
3369+
/* counter overflow check - paranoia? */
3370+
if (NUMCounter >= (INT_MAX - NUM_CACHE_FIELDS - 1))
33783371
{
33793372
NUMCounter = 0;
33803373

@@ -3383,7 +3376,7 @@ NUM_cache_getnew(char *str)
33833376
}
33843377

33853378
/*
3386-
* Cache is full - needs remove any older entry
3379+
* If cache is full, remove oldest entry
33873380
*/
33883381
if (n_NUMCache > NUM_CACHE_FIELDS)
33893382
{
@@ -3392,13 +3385,13 @@ NUM_cache_getnew(char *str)
33923385
#ifdef DEBUG_TO_FROM_CHAR
33933386
elog(DEBUG_elog_output, "Cache is full (%d)", n_NUMCache);
33943387
#endif
3395-
33963388
for (ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++)
33973389
{
33983390
/*
3399-
* entry removed via NUM_cache_remove() can be used here
3391+
* entry removed via NUM_cache_remove() can be used here,
3392+
* which is why it's worth scanning first entry again
34003393
*/
3401-
if (*ent->str == '\0')
3394+
if (ent->str[0] == '\0')
34023395
{
34033396
old = ent;
34043397
break;
@@ -3412,7 +3405,6 @@ NUM_cache_getnew(char *str)
34123405
StrNCpy(old->str, str, NUM_CACHE_SIZE + 1);
34133406
/* old->format fill parser */
34143407
old->age = (++NUMCounter);
3415-
34163408
ent = old;
34173409
}
34183410
else
@@ -3430,35 +3422,32 @@ NUM_cache_getnew(char *str)
34303422
zeroize_NUM(&ent->Num);
34313423

34323424
last_NUMCacheEntry = ent;
3433-
return ent; /* never */
3425+
return ent;
34343426
}
34353427

34363428
static NUMCacheEntry *
34373429
NUM_cache_search(char *str)
34383430
{
3439-
int i = 0;
3431+
int i;
34403432
NUMCacheEntry *ent;
34413433

3442-
/* counter overload check - paranoia? */
3443-
if (NUMCounter + NUM_CACHE_FIELDS >= MAX_INT32)
3434+
/* counter overflow check - paranoia? */
3435+
if (NUMCounter >= (INT_MAX - NUM_CACHE_FIELDS - 1))
34443436
{
34453437
NUMCounter = 0;
34463438

34473439
for (ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++)
34483440
ent->age = (++NUMCounter);
34493441
}
34503442

3451-
for (ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++)
3443+
for (i = 0, ent = NUMCache; i < n_NUMCache; i++, ent++)
34523444
{
3453-
if (i == n_NUMCache)
3454-
break;
34553445
if (strcmp(ent->str, str) == 0)
34563446
{
34573447
ent->age = (++NUMCounter);
34583448
last_NUMCacheEntry = ent;
34593449
return ent;
34603450
}
3461-
i++;
34623451
}
34633452

34643453
return NULL;
@@ -3470,7 +3459,7 @@ NUM_cache_remove(NUMCacheEntry *ent)
34703459
#ifdef DEBUG_TO_FROM_CHAR
34713460
elog(DEBUG_elog_output, "REMOVING ENTRY (%s)", ent->str);
34723461
#endif
3473-
*ent->str = '\0';
3462+
ent->str[0] = '\0';
34743463
ent->age = 0;
34753464
}
34763465

0 commit comments

Comments
 (0)