public inbox for gcc-bugs@sourceware.org help / color / mirror / Atom feed
* [Bug c++/37722] New: destructors not called on computed goto @ 2008-10-02 20:46 cburger at sunysb dot edu 2008-10-02 21:23 ` [Bug middle-end/37722] " pinskia at gcc dot gnu dot org 2009-05-09 8:17 ` scovich at gmail dot com 0 siblings, 2 replies; 10+ messages in thread From: cburger at sunysb dot edu @ 2008-10-02 20:46 UTC (permalink / raw) To: gcc-bugs #include <iostream> struct foo { foo() { std::cout << "foo constructed\n"; } ~foo() { std::cout << "foo destructed\n"; } }; enum opcode { NOP, FOO, DONE }; void exec0(const opcode* o) { loop: switch (*o) { case NOP: ++o; goto loop; case FOO: { foo f; ++o; goto loop; } // f destructed case DONE: return; } } void exec1(const opcode* o) { static void* label[] = { &&NOP, &&FOO, &&DONE }; goto *label[*o]; NOP: ++o; goto *label[*o]; FOO: { foo f; ++o; goto *label[*o]; } // f not destructed // FOO: { foo f; ++o; } goto *label[*o]; // work-around DONE: return; } int main() { const opcode program[] = { NOP, FOO, NOP, NOP, DONE }; exec0(program); exec1(program); return 0; } Output: foo constructed foo destructed foo constructed Tested with: 4.3.2, 4.2.4, 4.1.3, 3.4.6 Optimization level makes no difference. Intel icpc 10.1, 9.1 show the same problem. -- Summary: destructors not called on computed goto Product: gcc Version: 4.3.2 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: cburger at sunysb dot edu GCC build triplet: x86_64-linux-gnu GCC host triplet: x86_64-linux-gnu GCC target triplet: x86_64-linux-gnu http://gcc.gnu.org/bugzilla/show_bug.cgi?id=37722 ^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug middle-end/37722] destructors not called on computed goto 2008-10-02 20:46 [Bug c++/37722] New: destructors not called on computed goto cburger at sunysb dot edu @ 2008-10-02 21:23 ` pinskia at gcc dot gnu dot org 2009-05-09 8:17 ` scovich at gmail dot com 1 sibling, 0 replies; 10+ messages in thread From: pinskia at gcc dot gnu dot org @ 2008-10-02 21:23 UTC (permalink / raw) To: gcc-bugs ------- Comment #1 from pinskia at gcc dot gnu dot org 2008-10-02 21:22 ------- EH lowering for some reason does not copy the finally part of the try before the goto. This also happens with 3.3. -- pinskia at gcc dot gnu dot org changed: What |Removed |Added ---------------------------------------------------------------------------- Component|c++ |middle-end Keywords| |wrong-code Known to fail| |3.3 4.4.0 4.0.1 http://gcc.gnu.org/bugzilla/show_bug.cgi?id=37722 ^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug middle-end/37722] destructors not called on computed goto 2008-10-02 20:46 [Bug c++/37722] New: destructors not called on computed goto cburger at sunysb dot edu 2008-10-02 21:23 ` [Bug middle-end/37722] " pinskia at gcc dot gnu dot org @ 2009-05-09 8:17 ` scovich at gmail dot com 1 sibling, 0 replies; 10+ messages in thread From: scovich at gmail dot com @ 2009-05-09 8:17 UTC (permalink / raw) To: gcc-bugs ------- Comment #2 from scovich at gmail dot com 2009-05-09 08:16 ------- Computed gotos can easily make it impossible for the compiler to call constructors and destructors consistently. This is a major gotcha of computed gotos for people who have used normal gotos in C++ and expect destructors to be handled properly. Consider this program, for instance: #include <stdio.h> template<int i> struct foo { foo() { printf("%s<%d>\n", __FUNCTION__, i); } ~foo() { printf("%s<%d>\n", __FUNCTION__, i); } }; enum {RETRY, INSIDE, OUTSIDE, EVIL}; int bar(int idx) { static void* const gotos[] = {&&RETRY, &&INSIDE, &&OUTSIDE, &&EVIL}; bool first = true; { RETRY: foo<1> f1; if(first) { first = false; goto *gotos[idx]; } INSIDE: return 1; } if(0) { foo<2> f2; EVIL: return 2; } OUTSIDE: return 0; } int main() { for(int i=RETRY; i <= EVIL; i++) printf("%d\n", bar(i)); return 0; } Not only does it let you jump out of a block without calling destructors, it lets you jump into one without calling constructors: $ g++-4.4.0 -Wall -O3 scratch.cpp && ./a.out foo<1> foo<1> ~foo<1> 1 foo<1> ~foo<1> 1 foo<1> 0 foo<1> ~foo<2> 2 Ideally, the compiler could analyze possible destinations of the goto (best-effort, of course) and emit suitable diagnostics: scratch.cpp:16: warning: computed goto bypasses destructor of 'foo<1> f1' scratch.cpp:13: warning: declared here scratch.cpp:23: warning: possible jump to label 'EVIL' scratch.cpp:16: warning: from here scratch.cpp:22: warning: crosses initialization of 'foo<2> f2' In this particular example the compiler should be able to figure out that no labels reach a live f1 and call its destructor properly. If it's not feasible to analyze the possible destinations of the computed goto, regular control flow analysis should at least be able to identify potentially dangerous labels and gotos, e.g.: scratch.cpp:16: warning: computed goto may bypass destructor of 'foo<1> f1' scratch.cpp:13: warning: declared here scratch.cpp:23: warning: jump to label 'EVIL' scratch.cpp:8: warning: using a computed goto scratch.cpp:22: warning: may cross initialization of 'foo<2> f2' -- scovich at gmail dot com changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |scovich at gmail dot com http://gcc.gnu.org/bugzilla/show_bug.cgi?id=37722 ^ permalink raw reply [flat|nested] 10+ messages in thread
[parent not found: <bug-37722-4@http.gcc.gnu.org/bugzilla/>]
* [Bug middle-end/37722] destructors not called on computed goto [not found] <bug-37722-4@http.gcc.gnu.org/bugzilla/> @ 2013-01-11 14:52 ` timo.kreuzer at reactos dot org 2022-01-03 12:00 ` pinskia at gcc dot gnu.org ` (5 subsequent siblings) 6 siblings, 0 replies; 10+ messages in thread From: timo.kreuzer at reactos dot org @ 2013-01-11 14:52 UTC (permalink / raw) To: gcc-bugs http://gcc.gnu.org/bugzilla/show_bug.cgi?id=37722 Timo Kreuzer <timo.kreuzer at reactos dot org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |timo.kreuzer at reactos dot | |org --- Comment #3 from Timo Kreuzer <timo.kreuzer at reactos dot org> 2013-01-11 14:52:03 UTC --- (In reply to comment #2) > int bar(int idx) { > static void* const gotos[] = {&&RETRY, &&INSIDE, &&OUTSIDE, &&EVIL}; > bool first = true; > { > RETRY: > foo<1> f1; > if(first) { > first = false; Well usually you cannot declare a variable after a label. That's a gcc extension. So you should either add curly braces between RETRY and INSIDE, or move RETRY above the preceeding brace. But that is just syntax, since it would be desired that it behaved like it would with a normal goto, even if that was placed like that. (I assume normal gotos will handle this properly) To theoretically solve the proplem, you could replace every indirect goto with code like this: { static void* const local_gotos[] = {&&label1, &&label2, &&label3, &&label4}; goto *local_gotos[idx]; label1: goto RETRY; label2: goto INSIDE; label3: goto OUTSIDE; label4: goto EVIL; } And now have the compiler optimize the pathes. This way, there are no more crazy jumps, just a very simple indirect jump and a number of normal jumps that the compiler should be able to handle anyway. The problem is now, that there might be multiple indirect jumps that use the same static data, which is just a bunch of void pointers. So depending on the origin of the jump different pathes would need to be generated for each target. This is incompatible with an indirect jump instruction though, which only utilizes some arbitrary address. One possible solution for this is to always invoke all destructors and constructors, even for local indirect gotos. So you would need to consider an indirect jump to always leave all scope blocks, up to the top level of the function and reenter from there. This would allow to generate labels/codepathes that are consistent for multiple indirect gotos. Another solution, is to use multiple jump tables. One table for each indirect goto containing one entry for each possibly referenced label in the function. The trick is that the original label addresses, that are produced with the && operator will all point to an "array" of direct jmp instructions. all of the same size. Now the first indirect goto would emit an indirect jump instruction to the address itself. The second one would substract the address of the first label, divide by the size of the jmp stub code and use the result as an index into it's own private jump table. Alternatively a static offset could be added to the actual address and multiple direct jump stubs would be generated in a row. table: .long label1, label2, label3, label4; table2: .long label1_from_2, label2_from_2, label3_from_2, label4_from_2; // first indirect goto mov eax, table[ecx * 4] // get the address from the table jmp eax // jump there // Second indirect goto mov ecx, table[ecx * 4] // get the address from the table sub ecx, label1 // substract the address of the first label shr ecx, 3 // divide by 8 (assuming each stub is 8 bytes) mov eax, table[ecx * 4] // get the address from the 2nd table jmp eax // jump there // Alternative: using multiple stub arrays mov eax, table[ecx * 4] // get the address from the table add eax, label5 - label1 // add the offset to the second "jmp array" jmp eax // jump there label1: jmp label1_from_1 label2: jmp label2_from_1 label3: jmp label3_from_1 label4: jmp label4_from_1 label5: jmp label1_from_2 label6: jmp label2_from_2 label7: jmp label3_from_2 label8: jmp label4_from_2 This mechanism would only be needed as soon as multiple indirect jumps could reference the same labels and different code pathes would need to be constructed for the targets depending on the origin of the goto. As an optimization it should be considered that labels, of which the address has been put in a table, which is now out of scope are not actually available anymore. Other optimizations might be using 2 different tables directly, if they are only used for 2 indirect jumps (someone might (mis)use it for different things like non-local gotos, exception handling, saving the address of code that is being executed for debugging purposes, etc) ^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug middle-end/37722] destructors not called on computed goto [not found] <bug-37722-4@http.gcc.gnu.org/bugzilla/> 2013-01-11 14:52 ` timo.kreuzer at reactos dot org @ 2022-01-03 12:00 ` pinskia at gcc dot gnu.org 2022-01-03 17:33 ` jakub at gcc dot gnu.org ` (4 subsequent siblings) 6 siblings, 0 replies; 10+ messages in thread From: pinskia at gcc dot gnu.org @ 2022-01-03 12:00 UTC (permalink / raw) To: gcc-bugs https://gcc.gnu.org/bugzilla/show_bug.cgi?id=37722 Andrew Pinski <pinskia at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |fchelnokov at gmail dot com --- Comment #4 from Andrew Pinski <pinskia at gcc dot gnu.org> --- *** Bug 103896 has been marked as a duplicate of this bug. *** ^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug middle-end/37722] destructors not called on computed goto [not found] <bug-37722-4@http.gcc.gnu.org/bugzilla/> 2013-01-11 14:52 ` timo.kreuzer at reactos dot org 2022-01-03 12:00 ` pinskia at gcc dot gnu.org @ 2022-01-03 17:33 ` jakub at gcc dot gnu.org 2023-07-19 16:46 ` ndesaulniers at google dot com ` (3 subsequent siblings) 6 siblings, 0 replies; 10+ messages in thread From: jakub at gcc dot gnu.org @ 2022-01-03 17:33 UTC (permalink / raw) To: gcc-bugs https://gcc.gnu.org/bugzilla/show_bug.cgi?id=37722 Jakub Jelinek <jakub at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |jakub at gcc dot gnu.org --- Comment #5 from Jakub Jelinek <jakub at gcc dot gnu.org> --- I think computed gotos are similar to longjmp here, the compiler doesn't know where exactly the jump will go to and so which variables should be destructed on a particular computed goto at runtime. For normal gotos, the compiler knows which scopes will be left and can arrange for those destructors to be run, and similarly which scopes will be entered and can complain if construction of some vars is jumped over. For longjmp, C++ documents it as undefined behavior: https://eel.is/c++draft/csetjmp.syn#2 I'm afraid for computed gotos all we can do is just document something similar for leaving the C++ scopes (and C with cleanup attribute) with computed gotos and similarly document that any crossed initializations of variables are undefined behavior (normal gotos crossing initialization are errors in C++ but not in C). ^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug middle-end/37722] destructors not called on computed goto [not found] <bug-37722-4@http.gcc.gnu.org/bugzilla/> ` (2 preceding siblings ...) 2022-01-03 17:33 ` jakub at gcc dot gnu.org @ 2023-07-19 16:46 ` ndesaulniers at google dot com 2023-12-21 2:07 ` cvs-commit at gcc dot gnu.org ` (2 subsequent siblings) 6 siblings, 0 replies; 10+ messages in thread From: ndesaulniers at google dot com @ 2023-07-19 16:46 UTC (permalink / raw) To: gcc-bugs https://gcc.gnu.org/bugzilla/show_bug.cgi?id=37722 Nick Desaulniers <ndesaulniers at google dot com> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |ndesaulniers at google dot com --- Comment #6 from Nick Desaulniers <ndesaulniers at google dot com> --- (In reply to Jakub Jelinek from comment #5) > I'm afraid for computed gotos all we can do is just document something > similar Right, clang behaves this way, too. And I don't see how we'd change that, for all of the reasons above. If the documentation doesn't mention this edge case with the computed goto extension, it should be revised to do so. Then this bug can be closed as "Working as intended" IMO. ^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug middle-end/37722] destructors not called on computed goto [not found] <bug-37722-4@http.gcc.gnu.org/bugzilla/> ` (3 preceding siblings ...) 2023-07-19 16:46 ` ndesaulniers at google dot com @ 2023-12-21 2:07 ` cvs-commit at gcc dot gnu.org 2023-12-21 2:08 ` jason at gcc dot gnu.org 2024-01-03 4:23 ` egallager at gcc dot gnu.org 6 siblings, 0 replies; 10+ messages in thread From: cvs-commit at gcc dot gnu.org @ 2023-12-21 2:07 UTC (permalink / raw) To: gcc-bugs https://gcc.gnu.org/bugzilla/show_bug.cgi?id=37722 --- Comment #7 from GCC Commits <cvs-commit at gcc dot gnu.org> --- The trunk branch has been updated by Jason Merrill <jason@gcc.gnu.org>: https://gcc.gnu.org/g:4d9e0f3f211c8c459f285b5cddabc9958ad170f8 commit r14-6765-g4d9e0f3f211c8c459f285b5cddabc9958ad170f8 Author: Jason Merrill <jason@redhat.com> Date: Wed Dec 20 13:58:16 2023 -0500 c++: computed goto warning [PR37722] PR37722 complains that a computed goto doesn't destroy objects that go out of scope. In the PR we agreed that it never will, but we can warn about it. PR c++/37722 gcc/ChangeLog: * doc/extend.texi: Document that computed goto does not call destructors. gcc/cp/ChangeLog: * decl.cc (identify_goto): Adjust for computed goto. (struct named_label_use_entry): Add computed_goto field. (poplevel_named_label_1): Add to computed_goto vec. (check_previous_goto_1): Dump computed_goto vec. (check_goto_1): Split out from check_goto. (check_goto): Check all addressable labels for computed goto. (struct named_label_entry): Add addressed field. (mark_label_addressed): New. * parser.cc (cp_parser_unary_expression): Call it. * cp-tree.h (mark_label_addressed): Declare it. gcc/testsuite/ChangeLog: * g++.dg/ext/label15.C: New test. * g++.dg/torture/pr42739.C: Expect warning. ^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug middle-end/37722] destructors not called on computed goto [not found] <bug-37722-4@http.gcc.gnu.org/bugzilla/> ` (4 preceding siblings ...) 2023-12-21 2:07 ` cvs-commit at gcc dot gnu.org @ 2023-12-21 2:08 ` jason at gcc dot gnu.org 2024-01-03 4:23 ` egallager at gcc dot gnu.org 6 siblings, 0 replies; 10+ messages in thread From: jason at gcc dot gnu.org @ 2023-12-21 2:08 UTC (permalink / raw) To: gcc-bugs https://gcc.gnu.org/bugzilla/show_bug.cgi?id=37722 Jason Merrill <jason at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |jason at gcc dot gnu.org Status|UNCONFIRMED |RESOLVED Assignee|unassigned at gcc dot gnu.org |jason at gcc dot gnu.org Target Milestone|--- |14.0 Resolution|--- |FIXED --- Comment #8 from Jason Merrill <jason at gcc dot gnu.org> --- Warning and documentation added for GCC 14. ^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug middle-end/37722] destructors not called on computed goto [not found] <bug-37722-4@http.gcc.gnu.org/bugzilla/> ` (5 preceding siblings ...) 2023-12-21 2:08 ` jason at gcc dot gnu.org @ 2024-01-03 4:23 ` egallager at gcc dot gnu.org 6 siblings, 0 replies; 10+ messages in thread From: egallager at gcc dot gnu.org @ 2024-01-03 4:23 UTC (permalink / raw) To: gcc-bugs https://gcc.gnu.org/bugzilla/show_bug.cgi?id=37722 Eric Gallager <egallager at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- See Also| |https://gcc.gnu.org/bugzill | |a/show_bug.cgi?id=105401 Keywords| |diagnostic --- Comment #9 from Eric Gallager <egallager at gcc dot gnu.org> --- see also bug 105401 for another issue about diagnostics and documentation related to computed gotos ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2024-01-03 4:23 UTC | newest] Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2008-10-02 20:46 [Bug c++/37722] New: destructors not called on computed goto cburger at sunysb dot edu 2008-10-02 21:23 ` [Bug middle-end/37722] " pinskia at gcc dot gnu dot org 2009-05-09 8:17 ` scovich at gmail dot com [not found] <bug-37722-4@http.gcc.gnu.org/bugzilla/> 2013-01-11 14:52 ` timo.kreuzer at reactos dot org 2022-01-03 12:00 ` pinskia at gcc dot gnu.org 2022-01-03 17:33 ` jakub at gcc dot gnu.org 2023-07-19 16:46 ` ndesaulniers at google dot com 2023-12-21 2:07 ` cvs-commit at gcc dot gnu.org 2023-12-21 2:08 ` jason at gcc dot gnu.org 2024-01-03 4:23 ` egallager 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).