1

我有一个声明

strncpy(&data->m_bin->data,versionStr,data->m_bin->sizeData);

在我的应用程序中,它本身很好并且运行良好。这里 data->m_bin->data 是一个字符,调用应用程序确保它后面跟着一个数据块,该数据块大到足以保存 strncpy() 传递的所有数据。

但是当我使用 GCC/Linux 将其构建为发行版时,此函数在 __strncpy_chk() 中崩溃。因此,似乎我的 strncpy() 被 __strncpy_chk() 替换,参数 s1 使用了错误的长度。

那么如何确保 __strncpy_chk() 以正确的 s1 长度调用?

谢谢!

4

2 回答 2

2

这里 data->m_bin->data 是一个字符,调用应用程序确保它后面跟着一个数据块,该数据块大到足以保存 strncpy() 传递的所有数据。

这导致生成有效的 C 程序是不寻常的。指针出处规则通常意味着这会导致未定义的行为。

如果 位于char结构的末尾,则可以使用灵活的数组成员,以使编译器更清楚其意图是什么。

如果您不想更改源代码,可以使用-U_FORTIFY_SOURCE或进行编译-D_FORTIFY_SOURCE=0。这将禁用strncpy强化版本的替换。

于 2019-03-12T07:45:14.150 回答
1

strncpy(&data->m_bin->data,versionStr,data->m_bin->sizeData);

接线员在address of我看来很可疑。我希望是这样的:

strncpy(data->m_bin->data,versionStr,data->m_bin->sizeData);

或许:

strncpy(&data->m_bin->data[0],versionStr,data->m_bin->sizeData);

如何确保__strncpy_chk()以正确的 s1 长度调用?

好吧,你本身不能。这是FORTIFY_SOURCE对象大小检查的一部分,当编译器可以推断时使用目标缓冲区大小。

data假设是一个 size 数组,您可能会执行以下操作sizeData

/* avoid undefined behavior */
ASSERT(data->m_bin->data != NULL);
ASSERT(versionStr != NULL);
ASSERT(data->m_bin->sizeData > 0);

size_t l1 = data->m_bin->sizeData;
size_t l2 = strlen(versionStr);

/* min function */
size_t len = l1 < l2 ? l1 : l2;

/* if versionStr is shorter than len, then data will be backfilled */
strncpy(data->m_bin->data, versionStr, len);

/* NULL terminate, even if it truncates */
data->m_bin->data[data->m_bin->sizeData-1] = '\0';

您可能应该使用-Wall. 我怀疑你应该得到一个使用address of操作员。

于 2019-03-12T07:33:19.740 回答