记录PG的一次内存泄漏
【摘要】 PG的cast函数在转换时间时可能会发生内存泄漏
问题
使用cast
函数误将时间字符串携带了多余字母,导致获取的最终时间结果的时间“抹掉了”。
时间“消失”了
进一步修改时间字符串
发现报错time zone xxx
。系统误将时间字符串当成了time zone
时区。通过分析源码可知pg的时区是缓存在上下文中Timezones
,且没有回收机制。
pg_tz *
pg_tzset(const char *tzname)
{
pg_tz_cache *tzp;
struct state tzstate;
char uppername[TZ_STRLEN_MAX + 1];
char canonname[TZ_STRLEN_MAX + 1];
char *p;
if (strlen(tzname) > TZ_STRLEN_MAX)
return NULL; /* not going to fit */
if (!timezone_cache)
if (!init_timezone_hashtable())
return NULL;
/*
* Upcase the given name to perform a case-insensitive hashtable search.
* (We could alternatively downcase it, but we prefer upcase so that we
* can get consistently upcased results from tzparse() in case the name is
* a POSIX-style timezone spec.)
*/
p = uppername;
while (*tzname)
*p++ = pg_toupper((unsigned char) *tzname++);
*p = '\0';
tzp = (pg_tz_cache *) hash_search(timezone_cache,
uppername,
HASH_FIND,
NULL);
if (tzp)
{
/* Timezone found in cache, nothing more to do */
return &tzp->tz;
}
/*
* "GMT" is always sent to tzparse(), as per discussion above.
*/
if (strcmp(uppername, "GMT") == 0)
{
if (!tzparse(uppername, &tzstate, true))
{
/* This really, really should not happen ... */
elog(ERROR, "could not initialize GMT time zone");
}
/* Use uppercase name as canonical */
strcpy(canonname, uppername);
}
else if (tzload(uppername, canonname, &tzstate, true) != 0)
{
if (uppername[0] == ':' || !tzparse(uppername, &tzstate, false))
{
/* Unknown timezone. Fail our call instead of loading GMT! */
return NULL;
}
/* For POSIX timezone specs, use uppercase name as canonical */
strcpy(canonname, uppername);
}
/* Save timezone in the cache */
tzp = (pg_tz_cache *) hash_search(timezone_cache,
uppername,
HASH_ENTER,
NULL);
/* hash_search already copied uppername into the hash key */
strcpy(tzp->tz.TZname, canonname);
memcpy(&tzp->tz.state, &tzstate, sizeof(tzstate));
return &tzp->tz;
}
static bool
init_timezone_hashtable(void)
{
HASHCTL hash_ctl;
hash_ctl.keysize = TZ_STRLEN_MAX + 1;
hash_ctl.entrysize = sizeof(pg_tz_cache);
timezone_cache = hash_create("Timezones",
4,
&hash_ctl,
HASH_ELEM | HASH_STRINGS);
if (!timezone_cache)
return false;
return true;
}
pg的所有时区存储在表pg_timezone_names
中。生成时区上下文时没有做校验,所以遇到新的时间点就会创建新的Timezone
上下文,造成内存的泄漏。
- 调用堆栈
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)