<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/66063>66063</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            lld-link bug when using control flow guard /guard:cf with setjmp/longjmp
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          timabroad
      </td>
    </tr>
</table>

<pre>
    The bug seems to occur when linking multiple objects/libraries where some were compiled with `/guard:cf`, and some without, and then the final executable is linked using `/guard:cf` - in particular when the setjmp/longjmp code is not compiled with `/guard:cf`. MSVC `link` handles this without issue. Also regular indirect function calls seem to be handled correctly 

Reproduction code:

```
// util.h
typedef void (*test_fn)( void );
void indirect( void );
void ret( void );
void call( test_fn f );
```
```
// util.c
#include <setjmp.h>
#include "util.h"

static jmp_buf jmp;

void indirect( void )
{
}

void ret( void )
{
 longjmp( jmp, 1 );
}

void call( test_fn f )
{
    if ( 0 == setjmp( jmp ) )
    {
        f();
    }
}
```
```
// src.c
#include <stdio.h>
#include "util.h"

void bar( void )
{
    ret();
}

int main(void)
{
    // Regular indirect call into non-CFG file handled correctly.
    printf( "Testing indirect call: " );
    fflush( stdout );
    test_fn f = indirect;
    f();
    printf( "Success!\n" );
    fflush( stdout );

    // But setjmp/longjmp triggers a CFG violation.
    // Flow is call -> setjmp -> bar -> ret -> longjmp
    printf( "Testing longjmp: " );
    fflush( stdout );
    call( bar );
    printf( "Success!\n" );
    fflush( stdout );

    return 0;
}
```

```
# This works correctly
$ cl -guard:cf -c src.c && cl -c util.c && link -guard:cf src.obj util.obj && ./src.exe
Testing indirect call: Success!
Testing longjmp: Success!

# This aborts with a CFG violation
$ clang-cl -guard:cf -c src.c && clang-cl -c util.c && lld-link -guard:cf src.obj util.obj && ./src.exe
Testing indirect call: Success!
Testing longjmp:
```

Looks like this is an issue in `lld-link`, since using MSVC `cl` with `lld-link` also fails, but `clang-cl` with `link` works. I think you might also be able to reduce this down to a single source file without `/guard:cf` as long as you pass `/guard:cf` to the linker, but this example follows how I ended up running into the issue - I have a large cmake project that uses `cunit` for testing, and we have a single unit test target that turns on CFG, but it's not turned on for any other targets (in particular it's not turned on when compiling `cunit`). Cunit implements a method to skip tests that uses setjmp/longjmp, and so a skipped test causes the test binary to abort.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzEV01v2zwS_jX0ZWBDphLHPviQxvWiwO6lLfZaUORIYkyRAknFzb9fDCnVH3HS7Xt436KIZM0Hn3k4HD0SIejGIm7Z_Sd2v5uJIbbOb6PuROWdULPKqdft9xahGhoIiF2A6MBJOXg4tmjBaHvQtoFuMFH3BsFVzyhjYHxvdOWF1xjI0yME1yEc6U66rtcGFRx1bIGtCsb3zSC8YuWjrNPvJxBWjSE6tm6I07NIy8YWodZWGMCfKIcoKoOgQ4KDCoZAmG4khjloC73wUcvBiLEIyhYwPnc9wXa2ee56kE6llNbF3wNewH--_feJLISAFmqFVQYDxFaHqQTQIQy4gEcTHHhsEgJtlfYoI9SDlVE7C1IYExLbRHaFYy4F0nnyNK_Aih0rHvPfr9h7p4Yx1ilk5eO5neDm__kn3zO-hyFqs2jzo_jao8IaXpxWwPia8ceIIf6oLeMbxteTYcPKTzkiPZiQv-_h8QMjlUnWcSmoL1yuUb9fhJweldpKMygEVj7l7Vy0rPz81sz5WD3n50SFKKKW8Nz1P6qhpusJzW-qzk4Pk_fD7k3YNRWXETB2HbmkyxMsL-m4kfI2gVeJAUCTYQ0FsHLHyt2vVk9LUcwpjtwvYulfnVrihCU77a6B_T8bFrx8Z7-i0u7PtitxUAn_Ea0AI_EfcKlthE5oy_ia0tzOMuL_en1oaQ9A2-jAOjt_2v8Lam1unNjFKVXvtY3EKVX2HUOkWXWRkJWPZINr0uvaDKGlyBAVzZNrh7NOKHenTr3IcWMzLxB9G6TEEBhfsvsn-8cw3lD2aYhvh2v0umnQBxBAnL1oZwTNr8Wb8L1xRxrDieg5Kz-PyfJ9JXy-8RjzzXSQPqZ78vqrRE9Hj9b_e9j0GAdvobjRxVcn7fbxK-F7ehM5fwintpysdyANzE-vNJjLfFaB8RXjq2SW47ydntGr7iKIIlz1nN3oZnRcML4nG_7EvOC7XX9G14Xj2X5du1wVKCrnY37jXjfXebHCNvPfljw5vSncqPk_UvwHG_5v5w6kfw6YJQdRYbPgIMlDymREPeqroK3EUSlN4kUaki6TyDkLAEGSpRbaBIqtqE3JPTN0ETQGpEZbwBdCYw_w6gbodNPGnKlCSJItkg5SgxxBK3e09EwQusaQZhy8xDxTJxF1S9aJkFiiK63UixBu-kWXxF6SiX6qJC2NP0VH-rV2xrhjgNYd4QugVSQne_CDtXnTxhSZ2Tl8gVa8IAgwwjcIshMHhN47UsEQWxFhCJjAyMHqSCBq59Ok1raZRO0RpzRj4eSbnCBS3jEVjYAAzlJfT-h1ZPwhy1QyoyI7LSHsK7jYoh9TBFIBl-r3ZmySxFnxjip6Qs74ZgFPCZomsjq0kUZ4h7F1isgNB90n2OGs9uvpf1L3VO9B9z2qXKsUKYD4Tb8rbYV_TR1Bx3oxU9tSbcqNmOF2udrc3S_Lu3Uxa7frzVopWWO9rtabZflwv1wXS5RScCXvxHIz01te8LLYLPmyWC55sZCKK_Ug11VdrARXD-yuwE5oszDmpVs438zSDm9Xq2JVzoyo0IT0mcS5xWPefhIk97uZ31LMvBqawO4Ko0MMpyxRR4PbXxODvqMSwfngSWejdwZqesulVoWLns3H6prA2eDNto2xDzQT0nuy0bEdqoV0HbmZl-kyH1uR8X2CTB9mqaT_BQAA__8xKDn0">