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

Lines changed: 24 additions & 35 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy