public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c/112870] New: incorrect jmp when using goto on a function, causing infinite loop
@ 2023-12-05 18:41 grantrwittmann at gmail dot com
  2023-12-05 18:44 ` [Bug c/112870] " pinskia at gcc dot gnu.org
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: grantrwittmann at gmail dot com @ 2023-12-05 18:41 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112870

            Bug ID: 112870
           Summary: incorrect jmp when using goto on a function, causing
                    infinite loop
           Product: gcc
           Version: 13.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: grantrwittmann at gmail dot com
  Target Milestone: ---

When first setting a variable to a label, then jumping after that label to a
function (not calling the function), GCC generates incorrect assembly causing
the goto statement to jump to the previous label and not the function.

The code:

void function() {
    return;
}

int main() {
    void* label_var = &&label;
    label:
        goto *&function;
}

compiles to this assembly:

function:
        push    rbp
        mov     rbp, rsp
        nop
        pop     rbp
        ret
main:
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], OFFSET FLAT:.L4
.L4:
        nop
        jmp     .L4

The last jmp goes back to .L4 (label) even though it should be going to
function. The assembly is compiled correctly when the `label_var` declaration
is removed.

This same code compiles correctly on other compilers like clang (17.0.1):

function:                               # @function
        push    rbp
        mov     rbp, rsp
        pop     rbp
        ret
main:                                   # @main
        push    rbp
        mov     rbp, rsp
        mov     dword ptr [rbp - 4], 0
        lea     rax, [rip + .Ltmp2]
        mov     qword ptr [rbp - 16], rax
.Ltmp2:                                 # Block address taken
.LBB1_1:                                # =>This Inner Loop Header: Depth=1
        lea     rax, [rip + function]
        mov     qword ptr [rbp - 24], rax       # 8-byte Spill
        jmp     .LBB1_2
.LBB1_2:                                #   in Loop: Header=BB1_1 Depth=1
        mov     rax, qword ptr [rbp - 24]       # 8-byte Reload
        jmp     rax


All examples from this issue were compiled and ran through the godbolt.org
online compiler explorer.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Bug c/112870] incorrect jmp when using goto on a function, causing infinite loop
  2023-12-05 18:41 [Bug c/112870] New: incorrect jmp when using goto on a function, causing infinite loop grantrwittmann at gmail dot com
@ 2023-12-05 18:44 ` pinskia at gcc dot gnu.org
  2023-12-05 19:01 ` grantrwittmann at gmail dot com
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: pinskia at gcc dot gnu.org @ 2023-12-05 18:44 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112870

Andrew Pinski <pinskia at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
         Resolution|---                         |INVALID
             Status|UNCONFIRMED                 |RESOLVED

--- Comment #1 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
This is all undefined behavior.


Please read https://gcc.gnu.org/onlinedocs/gcc-13.2.0/gcc/Labels-as-Values.html
.

Specifically:
You may not use this mechanism to jump to code in a different function.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Bug c/112870] incorrect jmp when using goto on a function, causing infinite loop
  2023-12-05 18:41 [Bug c/112870] New: incorrect jmp when using goto on a function, causing infinite loop grantrwittmann at gmail dot com
  2023-12-05 18:44 ` [Bug c/112870] " pinskia at gcc dot gnu.org
@ 2023-12-05 19:01 ` grantrwittmann at gmail dot com
  2023-12-05 19:04 ` pinskia at gcc dot gnu.org
  2024-03-16 17:58 ` pinskia at gcc dot gnu.org
  3 siblings, 0 replies; 5+ messages in thread
From: grantrwittmann at gmail dot com @ 2023-12-05 19:01 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112870

--- Comment #2 from Grant Wittman <grantrwittmann at gmail dot com> ---
(In reply to Andrew Pinski from comment #1)
> This is all undefined behavior.
> 
> 
> Please read
> https://gcc.gnu.org/onlinedocs/gcc-13.2.0/gcc/Labels-as-Values.html .
> 
> Specifically:
> You may not use this mechanism to jump to code in a different function.

I think I might get what you mean by 'undefined behavior', but this result is
predictable. I know that specific code snippet does not work, but it was the
shortest example I could make that would recreate the error.

Additionally, that doesn't explain why the last instruction is compiled
completely differently when the line `void* label_var = &&label;`, is removed.
I understand that the `label` is also removed from compilation but I can still
just use this code and it compiles correctly:

void function() {
    return;
}

int main() {
    goto *&function;
}

Again this code does not run without a segfault, but it compiles correctly.

If I force the compiler to add the labels into the assembly, it will still
compile correctly:

void function() {
    return;
}

int one = 1;

int main() {
    if(one) goto end;
label:
    goto *&function;
end:
    if(!one) goto label;
    return 0;
}

which compiles to

function:
        push    rbp
        mov     rbp, rsp
        nop
        pop     rbp
        ret
one:
        .long   1
main:
        push    rbp
        mov     rbp, rsp
        mov     eax, DWORD PTR one[rip]
        test    eax, eax
        jne     .L9
        nop
        jmp     .L4
.L10:
        nop
.L4:
        mov     eax, OFFSET FLAT:function
        jmp     rax
.L9:
        nop
        mov     eax, DWORD PTR one[rip]
        test    eax, eax
        je      .L10
        mov     eax, 0
        pop     rbp
        ret

But by adding that declaration of `label_var` back, it breaks again

void function() {
    return;
}

int one = 1;

int main() {
    void* label_var = &&label; // <-- ADDED STATEMENT
    if(one) goto end;
label:
    goto *&function;
end:
    if(!one) goto label;
    return 0;
}

which compiles to 

function:
        push    rbp
        mov     rbp, rsp
        nop
        pop     rbp
        ret
one:
        .long   1
main:
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], OFFSET FLAT:.L4
        mov     eax, DWORD PTR one[rip]
        test    eax, eax
        jne     .L9
.L4:
        nop
        jmp     .L4 ; <-- GOTO STATEMENT INFINITE LOOP AGAIN
.L9:
        nop
        mov     eax, DWORD PTR one[rip]
        test    eax, eax
        jne     .L6
        jmp     .L4
.L6:
        mov     eax, 0
        pop     rbp
        ret

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Bug c/112870] incorrect jmp when using goto on a function, causing infinite loop
  2023-12-05 18:41 [Bug c/112870] New: incorrect jmp when using goto on a function, causing infinite loop grantrwittmann at gmail dot com
  2023-12-05 18:44 ` [Bug c/112870] " pinskia at gcc dot gnu.org
  2023-12-05 19:01 ` grantrwittmann at gmail dot com
@ 2023-12-05 19:04 ` pinskia at gcc dot gnu.org
  2024-03-16 17:58 ` pinskia at gcc dot gnu.org
  3 siblings, 0 replies; 5+ messages in thread
From: pinskia at gcc dot gnu.org @ 2023-12-05 19:04 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112870

--- Comment #3 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
What you are doing is all not allowed with this extension.

Yes the documentation should be a little clearier on this but at least the part
where it says:
`You may not use this mechanism to jump to code in a different function.`

Is very clear on that part.

Basically computed gotos can only go to labels in the same function whos
address has been taken. That is the effect you are seeing here and why the
difference comes from.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Bug c/112870] incorrect jmp when using goto on a function, causing infinite loop
  2023-12-05 18:41 [Bug c/112870] New: incorrect jmp when using goto on a function, causing infinite loop grantrwittmann at gmail dot com
                   ` (2 preceding siblings ...)
  2023-12-05 19:04 ` pinskia at gcc dot gnu.org
@ 2024-03-16 17:58 ` pinskia at gcc dot gnu.org
  3 siblings, 0 replies; 5+ messages in thread
From: pinskia at gcc dot gnu.org @ 2024-03-16 17:58 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112870

Andrew Pinski <pinskia at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
         Resolution|INVALID                     |DUPLICATE

--- Comment #4 from Andrew Pinski <pinskia at gcc dot gnu.org> ---


*** This bug has been marked as a duplicate of bug 44298 ***

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2024-03-16 17:58 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-12-05 18:41 [Bug c/112870] New: incorrect jmp when using goto on a function, causing infinite loop grantrwittmann at gmail dot com
2023-12-05 18:44 ` [Bug c/112870] " pinskia at gcc dot gnu.org
2023-12-05 19:01 ` grantrwittmann at gmail dot com
2023-12-05 19:04 ` pinskia at gcc dot gnu.org
2024-03-16 17:58 ` pinskia at gcc dot gnu.org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).