简体   繁体   English

gcc -O2 创建一个无限循环,可能是因为未定义的行为

[英]gcc -O2 creates an endless loop, probably because of undefined behaviour

I wrote this C code to solve Advent of Code 13 2020. I know, it's probably not viable trying to solve it via brute force, but the program gives the correct answer for the example input.我编写了这个 C 代码来解决代码 13 2020 的出现。我知道,尝试通过蛮力解决它可能不可行,但程序为示例输入提供了正确答案。

If I try to let gcc optimize the code, it gives the correct result with -O1, but creates an endless loop with -O2.如果我尝试让 gcc 优化代码,它会使用 -O1 给出正确的结果,但会使用 -O2 创建一个无限循环。 After all the research my conclusion is that there is undefined behavior in my code, I guess it has to do with the probability that "found" may never be higher than 0 and so "time" would overflow.经过所有研究,我的结论是我的代码中存在未定义的行为,我想这与“找到”可能永远不会高于 0 的概率有关,因此“时间”会溢出。

Here is the question: Does anybody know how to patch that undefined behavior?问题来了:有人知道如何修补这种未定义的行为吗?

"-Wall -Wextra -pedantic" don't even issue a warning or something. “-Wall -Wextra -pedantic”甚至不发出警告之类的。

I just can't find a solution.我只是找不到解决方案。 If I, for example, change the head of the while loop to (,found && time < 10000000000), so that no overflow can occur, it just breaks the loop right away with a time value of 10000000003 when compiled with -O2.例如,如果我将 while 循环的头部更改为 (,found && time < 10000000000),这样就不会发生溢出,当使用 -O2 编译时,它会立即以 10000000003 的时间值中断循环。 but still gives the right result with -O1.但仍然使用 -O1 给出正确的结果。

Here is the code, the correct result would be "1068781":这是代码,正确的结果是“1068781”:

#include <stdio.h>
int main()
{
    unsigned int busses[] = {7, 0, 13, 2, 59, 1, 31, 0, 19};
    unsigned int busses_used = 9;
    unsigned int i = 0;
    unsigned int found = 0;
    unsigned long long time = 0;
    unsigned int offset = 0;
    unsigned int increment = 7;
    while (!found) {
        time += increment;
        offset = 0;
        for (i = 0; i < busses_used; i++) {
            if ((time + offset) % busses[i] == 0) {
                found = 1;
                offset++;
            } else {
                found = 0;
                break;
            }
            offset += busses[++i];
        }
    }
    printf("Endtime: %lld\n", time);
    return 0;
}

Edit: Thanks to KamilCuk for pointing out that the code is accessing the array out of bounds and teaching how to find out that it is doing so.编辑:感谢 KamilCuk 指出代码正在越界访问数组并教如何找出它正在这样做。 The problem is solved by adding another 0 at the end of the "busses" array and therefore also setting "busses_used" to 10 instead of 9.该问题通过在“busses”数组的末尾添加另一个 0 来解决,因此也将“busses_used”设置为 10 而不是 9。

I do not understand the code and not indent to, but the loop is strange.我看不懂代码,也不缩进,但循环很奇怪。 Anyway:反正:

"-Wall -Wextra -pedantic" don't even issue a warning or something. “-Wall -Wextra -pedantic”甚至不发出警告之类的。

And there are also other ways to detect UB!而且还有其他检测UB的方法! Compiling your code with some more -fsanitize=* options results with:使用更多-fsanitize=*选项编译代码会导致:

+ gcc -Wall -Wextra -ggdb3 -fsanitize=address -fsanitize=undefined -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize-address-use-after-scope /tmp/1.c
/tmp/1.c:22:29: runtime error: index 9 out of bounds for type 'unsigned int [9]'
/tmp/1.c:22:29: runtime error: load of address 0x7ffc48c7a894 with insufficient space for an object of type 'unsigned int'
0x7ffc48c7a894: note: pointer points here
  13 00 00 00 60 60 00 00  00 00 00 00 00 00 00 00  01 00 00 00 00 00 00 00  08 aa c7 48 fc 7f 00 00
              ^ 
=================================================================
==73835==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffc48c7a894 at pc 0x55c28a5bf773 bp 0x7ffc48c7a800 sp 0x7ffc48c7a7f0
READ of size 4 at 0x7ffc48c7a894 thread T0
    #0 0x55c28a5bf772 in main /tmp/1.c:22
    #1 0x7f0060bd1151 in __libc_start_main (/usr/lib/libc.so.6+0x28151)
    #2 0x55c28a5bf12d in _start (/tmp/tmp.qv8ZsZofOJ.out+0x112d)

Address 0x7ffc48c7a894 is located in stack of thread T0 at offset 84 in frame
    #0 0x55c28a5bf208 in main /tmp/1.c:3

  This frame has 1 object(s):
    [48, 84) 'busses' (line 4) <== Memory access at offset 84 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow /tmp/1.c:22 in main
Shadow bytes around the buggy address:
  0x1000091874c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000091874d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000091874e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000091874f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100009187500: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 f1 f1 00 00
=>0x100009187510: 00 00[04]f3 f3 f3 f3 f3 00 00 00 00 00 00 00 00
  0x100009187520: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100009187530: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100009187540: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100009187550: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100009187560: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==73835==ABORTING

After quick inspection the out of bounds access to busses happens here:快速检查后,对busses的越界访问发生在这里:

offset += busses[++i];

Does anybody know how to patch that undefined behavior?有人知道如何修补这种未定义的行为吗?

No idea, but write an algorithm that doesn't access the array out of bounds.不知道,但是编写一个不会越界访问数组的算法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM