对于相同的输入,两次连续调用 strcmp 将返回不同的值

问题描述 投票:0回答:1

我使用 strcmp 来比较多个字符串,通常每个程序运行大约数百或数千次比较。

我注意到,当我知道字符串完全相同时,strcmp 有时会返回非零。这种情况每隔几次运行就会发生一次,而且是不可预测的。很困惑,我使用 GDB 在 strcmp 的返回值非零时设置了一个断点,这样我就可以在调用 strcmp 后立即手动比较字符串。果然,它到达了断点,我在 GDB 中手动打印出了这两个字符串。它们完全相同,包括空终止字符。

更困惑的是,我将代码修改为以下内容,尝试通过在完全相同的字符串上运行两次 strcmp 来查明问题。在这种情况下,我知道

name
参数应始终匹配
R.ecos[0].name
:

Eco *get_eco(const char *name)
{
    int r1 = strcmp(R.ecos[0].name, name);
    int r2 = strcmp(R.ecos[0].name, name);
    if (r1) {
        //break here with GDB
    } else {
        return &R.ecos[0];
    }
    return 0;
}

我再次运行该程序几次以尝试产生错误。当断点命中时,我打印 r1 和 r2 并看到 r1 = 1 和 r2 = 0。

我的经验使我不相信编译器错误或 strcmp 本身存在错误的可能性。这段代码是游戏引擎的一部分,因此其他线程正在运行 FMOD(音频)和 GLFW3(输入),但这些都没有触及这里的内存,所以我没有理由认为多线程/存在一些可疑的情况竞争条件。还有什么会导致如此奇怪的错误?

我在Windows上使用mingw32,用gcc编译,并且我尝试了两个不同版本的gcc和gdb,都产生相同的结果。这在我的 Linux 版本上没有发生,尽管由于该错误的偶发性,我无法确定它不存在于 Linux 上,但是在该操作系统上运行数十次后我无法重现它。

编译器标志:

-static -ggdb -g -O0 -std=c11 -Wall -Wextra -pedantic -Wshadow -Wpointer-arith \
                    -Wcast-align -Wwrite-strings -Wmissing-prototypes \
                    -Wmissing-declarations -Wredundant-decls -Wnested-externs \
                    -Winline -Wno-long-long -Wuninitialized \
                    -Wstrict-prototypes

编辑:我也在 Linux 上使用 ASAN 运行该程序,但没有遇到错误

编辑2:在两个字符串的地址上设置硬件观察点后,例如

watch -l R.ecos[0].name[32]
我仍然在代码中命中断点,根本没有触发硬件观察点。

c windows gdb mingw mingw32
1个回答
0
投票

我的经验使我不相信编译器错误或 strcmp 本身存在错误的可能性。

GLIBC strstr很久以前曾经有一个

bug
,这样的bug有时确实存在。但你是对的,这不太可能。

我建议在 strcmp 之前制作字符串的

local
副本。这应该可以提供关于
strcmp
中是否存在数据争用或错误的明确答案。

如果有合理的长度限制,这相当容易做到:

Eco *get_eco(const char *name)
{
    char s1[MAXLEN], s2[MAXLEN];
    strcpy(s1, R.ecos[0].name);
    strcpy(s2, name);
    int r = strcmp(s1, s2);
    if (r) {
       // break here, examine s1, s2, name and R.ecos[0].name
    } else ...
© www.soinside.com 2019 - 2024. All rights reserved.