非空结尾值导致StrCmp返回0?

3

I have the following code:

_Bool grantAccess(char *password){
    char goodPassWord[]= "goodpass";
    return (0 == strcmp(password, goodPassWord));

}

_Bool grantAccessExercise(void){
    char password[9];
    int allow = 0;

    printf("Please enter password: ");

    gets(password); 

    if (grantAccess(password)) {
         allow = 1;
    }

    return (allow != 0);
    }

当我输入任何10个字符的密码组合时,它会溢出并覆盖空终止符。有人能解释一下为什么非空终止值会导致StrCmp返回0吗?


2
这是未定义行为,因此 0 没有保证的结果。它可能会完全执行其他操作。 - Blaze
5
请注意,危险的函数gets并不是“覆盖空终止符”,而是在数组越界写入空终止符。 - Some programmer dude
3
仅仅因为某个东西似乎有效,并不意味着它的行为已经被定义,只是你恰好“幸运”(有些人会认为这是幸的)。你不知道它何时会出问题,或者在出现问题后你做了什么导致它出了问题。 - Some programmer dude
我明白了。我在想StrCmp可能存在某种弱点,导致当传递NNT值时它总是返回正结果。我猜我的讲师无法反驳“未定义的行为”。谢谢大家。 - qz_99
1
@Hughes_J 请注意,您需要区分“实现定义行为”的概念,这意味着该行为没有被标准定义,而是交给编译器供应商(随后他们需要记录其相应实现的行为),以及“未定义行为”,这意味着不存在正确的行为,无论您怎么做,结果都不可能正确(例如从负实数值计算实数平方根)。 - Aconcagua
显示剩余4条评论
2个回答

4
有人能解释一下为什么非空终止值会导致 StrCmp 返回 0 吗?
事实并非如此。
以下是发生的情况:
- 缓冲区溢出覆盖了位于堆栈中的变量 allow 的字节。 - 因此,allow 不再包含值零,而是包含其他值。 - grantAccess() 调用返回 false,并且不修改 allow。 - 最后,由于溢出,allow 包含非零值。
为了验证这一点,我进行了以下测试:
- 我输入密码“0123456789”。 - 我观察到 allow == 57,这是字符 '9' 的 ASCII 码。

1
换句话说,TL;DR,strcmp不会返回0。 - hyde
1
请注意,这仍然是UB。不能保证堆栈中值(变量)的顺序。但是因为发现了在此示例中strcmp看似奇怪行为的原因而加1分。 - GermanNerd

0
进一步说明:您在这里观察到的是堆栈破坏。如果您输入一个足够长的字符串作为密码,您甚至会得到堆栈溢出(stack smashing)。您可以尝试将您的密码数组分配不同的大小,这可能会导致堆栈上的一些东西重新排列。有关堆栈溢出或堆栈缓冲区溢出的良好解释,请参见 此处
您还可以更改代码,并使用 malloc 在堆上分配 password 数组。您可能会得到似乎工作正常的代码,因为大多数内存位置在递增时很可能会包含 0,这被解释为 NULL 终止符。这将是一种更加阴险的行为,因为您的 grantAccess 函数可能会表现得看似正常。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接