llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
29.41k stars 12.15k forks source link

continue in __finally fails assert (!BreakContinueStack.empty() && "continue stmt not in a loop) #116926

Open jaykrell opened 1 week ago

jaykrell commented 1 week ago
int main()
{
    int a = 10;
    while (1)
    {
        __try {
            a = 20;
            *(volatile char*)0;
            a = 30;
        }
        __finally
        {
            // Next line is not needed.
            //a = _abnormal_termination() ? 40 : 50;

            //goto A;

            continue;
        }
    }

A:
    return a;
}

/* 1.c(18,13): warning: jump out of __finally block has undefined behavior [-Wjump-seh-finally] break;; ^ Assertion failed: !BreakContinueStack.empty() && "continue stmt not in a loop!", file C:\Users\swift-ci\jenkins\workspace\oss-swift-windows-toolchain\llvm-project\clang\lib\CodeGen\CGStmt.cpp, line 1402 PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script. Stack dump:

  1. parser at end of file
  2. 1.c:1:5: LLVM IR generation of declaration 'main'
  3. 1.c:1:5: Generating code for declaration 'main'
  4. 1.c:5:5: LLVM IR generation of compound statement ('{}')
  5. 1.c:12:9: LLVM IR generation of compound statement ('{}') */
jaykrell commented 1 week ago

More information. The Visual C++ warning has meaning, in that, you can continue once from the exception, but not after that. I wonder if it has locally unwound, vs. duplicated the loop in the finally block. We can find out, step, disassemble, print RIP, etc.

So the first example does return 0xC0000005. I wrote the second example to explore a more states, while avoiding that.

C:\s>type continue-in-finally.c
int main()
{
    int a = 10;
    while (a < 100)
    {
        __try {
            a += 10;
printf("1\n");
            *(volatile char*)0;
printf("2\n");
            a += 10;
        }
        __finally
        {
printf("3\n");
            continue;
        }
    }
printf("4\n");
    return a;
}
C:\s>cl continue-in-finally.c && continue-in-finally.exe
Microsoft (R) C/C++ Optimizing Compiler Version 19.41.34123 for x64
continue-in-finally.c(16): warning C4532: 'continue': jump out of __finally block has undefined behavior 
1
3
1

C:\s>echo %errorlevel%
-1073741819
C:\s>type continue-in-finally-once.c
#include "excpt.h"
int main()
{
    int alternate = 0;
    int once = 0;
    int a = 10;
    while (a < 50) {
        __try {
            a += 10;
printf("1 %d\n", a);
            if (a == 20)
                *(volatile char*)0;
printf("2 %d\n", a);
            a += 10;
        }
        __finally
        {
printf("3 %d\n", a);
            ++alternate;
            if (++once == 1 || (AbnormalTermination() || (alternate & 1))) {
                printf("=> continue\n");
                continue;
            } else {
                printf("=> no continue\n");
            }
printf("4 %d\n", a);
        }
    }
printf("5 %d\n", a);
    return a;
}
C:\s>cl continue-in-finally-once.c && continue-in-finally-once.exe
Microsoft (R) C/C++ Optimizing Compiler Version 19.41.34123 for x64
continue-in-finally-once.c(22): warning C4532: 'continue': jump out of __finally block has undefined behavior during termination handling

1 20
3 20
=> continue
1 30
2 30
3 40
=> no continue
4 40
1 50
2 50
3 60
=> continue
5 60