我有一些用 C 语言编写的软件,在我测试过的每个系统上都运行良好,直到现在。我们的一位系统管理员已将它安装在我们的集群上,并且出现了一些奇怪的行为。
在程序中,我正在使用京都内阁创建一个 DBM 数据库,尽管在此框中,该过程在创建数据库之前失败。该程序采用命令行参数来指定内存映射的大小和 KC 库使用的存储桶数。它根据kcdbopen
. 即,如果用户传递--mmap-size=1024 --num-buckets=256
了一个名为 的 db 文件,则构造foo.kch
一个字符串并将其传递给.foo.kch#msiz=1024#bnum=256
kcdbopen
正如我所说,这通常可以正常工作。但是,在这台特定的机器上,该进程将失败,并出现无法分配内存的错误。另外,一些调试文本显示它试图创建的文件以一些垃圾字符开头,并且 msiz 和 bnum 数字已经溢出,变得很大:
Failed to open database �!�u�foo.kch#msiz=249821240256#bnum=4199616: Cannot allocate memory
我argp_parse
用来解析命令行参数。该代码的相关部分是:
struct arguments
{
char *args[1];
unsigned long int mmap_size;
unsigned long int num_buckets;
};
static error_t
parse_opt (int key, char *arg, struct argp_state *state)
{
struct arguments *arguments = state->input;
switch (key)
{
case 'm':
arguments->mmap_size = arg ? atol (arg) : 1024;
break;
case 'b':
arguments->num_buckets = arg ? atol (arg) : 100;
break;
case ARGP_KEY_ARG:
if (state->arg_num >= 1)
argp_usage (state);
arguments->args[state->arg_num] = arg;
break;
...<snip>....
我试图在构建文件名字符串时格外(过度?)谨慎:
void *
zdb_create (char *dbfile, unsigned long int mmap_size, unsigned long int num_buckets,
bool verbose)
{
...<snip>...
char mmap_str[32];
char buckets_str[32];
char db_str[512];
if (strlen (dbfile) > sizeof (db_str) - sizeof (buckets_str) - sizeof (mmap_str))
error (EXIT_FAILURE, errno, "Filename too long");
strncat (db_str, dbfile, strlen (dbfile));
snprintf (mmap_str, sizeof(mmap_str), "#msiz=%lu", mmap_size);
if (strlen (dbfile) + strlen (mmap_str) < sizeof (db_str))
strncat (db_str, mmap_str, 32);
else
error (EXIT_FAILURE, errno, "Filename too long");
snprintf (buckets_str, sizeof(buckets_str), "#bnum=%lu", num_buckets);
if (strlen (dbfile) + strlen (mmap_str) < sizeof (db_str))
strncat (db_str, buckets_str, 32);
else
error (EXIT_FAILURE, errno, "Filename too long");
db = zdb_open (db_str, ZDB_CREATOR, false);
...<snip>...
所以,我刚刚了解到有一个strtoul
函数,这可能是问题的根源;atol
仅转换为标准long
而不是unsigned long
. 但是,我想 100% 确定我在去之前解决了问题并再次打扰系统管理员尝试重新安装(不幸的是,我不可能自己测试它,AFAICT)。这种溢出行为最可能的来源是什么?整数溢出和字符串开头的垃圾字符是否相关?为什么这适用于除此之外的大多数系统?
info
该系统使用的是 Linux 2.6.18、gcc 4.1.2,而且,根据它的页面很难判断 libc 的哪个版本...版本 2.3.x。我只在较新的系统上进行了测试,例如 Linux 2.6.32 / gcc 4.4.3 / libc 2.8 和 Linux 3.9.8 / gcc 4.8.1 / libc 2.17。
谢谢!