Bug 101666 - Objective-C frontend crashes with `-fobjc-nilcheck`
Summary: Objective-C frontend crashes with `-fobjc-nilcheck`
Status: REOPENED
Alias: None
Product: gcc
Classification: Unclassified
Component: objc (show other bugs)
Version: 10.2.0
: P3 normal
Target Milestone: ---
Assignee: Iain Sandoe
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2021-07-28 23:15 UTC by Matt Jacobson
Modified: 2022-06-14 22:38 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work: 12.1.0
Known to fail: 10.3.0, 11.3.0, 9.5.0
Last reconfirmed: 2021-08-22 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Matt Jacobson 2021-07-28 23:15:01 UTC
Details, including minimal reproducer, below.  The Objective-C frontend crashes when I try to use -fobjc-nilcheck under the NeXT v2 ABI.  If I send a message whose return type would require using objc_msgSend_stret (and a nil check), crash.  Message sends not requiring stret (and thus no nil check) work fine.

===

macOS 10.15.7 "Catalina" / x86_64

$ gcc --version
gcc (GCC) 10.2.0

$ gcc -Os -fobjc-nilcheck -xobjective-c -
struct point { double x, y, z; };

@interface Foo
- (struct point)bar;
@end

Foo *f;

int main(void) {
	struct point p = [f bar];
}
<stdin>: In function ‘main’:
<stdin>:10:9: internal compiler error: Segmentation fault: 11

Here's the backtrace:

(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
  * frame #0: 0x00000001012ce428 cc1obj`recompute_constructor_flags(c=0x0000000144513f90) at tree.c:2018:12
    frame #1: 0x00000001012cd45f cc1obj`build_constructor(type=0x0000000144505930, vals=0x000000014450a678) at tree.c:2059:3
    frame #2: 0x000000010000c2bd cc1obj`objc_build_constructor(type=0x0000000144505930, elts=0x000000014450a678) at objc-act.c:3235:22
    frame #3: 0x0000000100031b37 cc1obj`build_v2_build_objc_method_call(super_flag=0, method_prototype=0x0000000144504a18, lookup_object=0x00000001444f3720, selector=0x00000001444f36a0, method_params=0x000000014452b140, check_for_nil=true) at objc-next-runtime-abi-02.c:1637:12
    frame #4: 0x000000010002d8da cc1obj`next_runtime_abi_02_build_objc_method_call(loc=62820, method_prototype=0x0000000144504a18, receiver=0x0000000142c5d240, rtype=0x0000000144527000, sel_name=0x000000014451bf00, method_params=0x0000000000000000, super=0) at objc-next-runtime-abi-02.c:1720:10
    frame #5: 0x000000010000902d cc1obj`objc_finish_message_expr(receiver=0x0000000142c5d240, sel_name=0x000000014451bf00, method_params=0x0000000000000000, deprecated_method_prototype=0x0000000000000000) at objc-act.c:5679:12
    frame #6: 0x000000010000ec8f cc1obj`objc_build_message_expr(receiver=0x0000000142c5d240, message_args=0x000000014451bf00) at objc-act.c:5308:10
    frame #7: 0x00000001000be312 cc1obj`c_parser_postfix_expression(parser=0x0000000142c5d1b0) at c-parser.c:10163:17
    frame #8: 0x00000001000b5f21 cc1obj`c_parser_unary_expression(parser=0x0000000142c5d1b0) at c-parser.c:8276:14
    frame #9: 0x00000001000b3ce5 cc1obj`c_parser_cast_expression(parser=0x0000000142c5d1b0, after=0x0000000000000000) at c-parser.c:8115:12
    frame #10: 0x00000001000b209b cc1obj`c_parser_binary_expression(parser=0x0000000142c5d1b0, after=0x0000000000000000, omp_atomic_lhs=0x0000000000000000) at c-parser.c:7918:19
    frame #11: 0x00000001000b1800 cc1obj`c_parser_conditional_expression(parser=0x0000000142c5d1b0, after=0x0000000000000000, omp_atomic_lhs=0x0000000000000000) at c-parser.c:7652:10
    frame #12: 0x00000001000b13ed cc1obj`c_parser_expr_no_commas(parser=0x0000000142c5d1b0, after=0x0000000000000000, omp_atomic_lhs=0x0000000000000000) at c-parser.c:7569:9
    frame #13: 0x00000001000c6921 cc1obj`c_parser_initializer(parser=0x0000000142c5d1b0) at c-parser.c:5227:13
    frame #14: 0x00000001000c34a0 cc1obj`c_parser_declaration_or_fndef(parser=0x0000000142c5d1b0, fndef_ok=false, static_assert_ok=true, empty_ok=true, nested=true, start_attr_ok=true, objc_foreach_object_declaration=0x0000000000000000, omp_declare_simd_clauses=vec<c_token, va_heap, vl_ptr> @ 0x00007ffeefbfede8, have_attrs=false, attrs=0x0000000000000000, oacc_routine_data=0x0000000000000000, fallthru_attr_p=0x00007ffeefbfeebf) at c-parser.c:2248:12
    frame #15: 0x00000001000c00d4 cc1obj`c_parser_compound_statement_nostart(parser=0x0000000142c5d1b0) at c-parser.c:5718:4
    frame #16: 0x00000001000c6c3d cc1obj`c_parser_compound_statement(parser=0x0000000142c5d1b0, endlocp=0x00007ffeefbff070) at c-parser.c:5617:24
    frame #17: 0x00000001000c3e66 cc1obj`c_parser_declaration_or_fndef(parser=0x0000000142c5d1b0, fndef_ok=true, static_assert_ok=true, empty_ok=true, nested=false, start_attr_ok=true, objc_foreach_object_declaration=0x0000000000000000, omp_declare_simd_clauses=vec<c_token, va_heap, vl_ptr> @ 0x00007ffeefbff478, have_attrs=false, attrs=0x0000000000000000, oacc_routine_data=0x0000000000000000, fallthru_attr_p=0x0000000000000000) at c-parser.c:2505:11
    frame #18: 0x00000001000ee11e cc1obj`c_parser_external_declaration(parser=0x0000000142c5d1b0) at c-parser.c:1745:7
    frame #19: 0x00000001000b095d cc1obj`c_parser_translation_unit(parser=0x0000000142c5d1b0) at c-parser.c:1618:4
    frame #20: 0x00000001000b066b cc1obj`c_parse_file() at c-parser.c:21745:3
    frame #21: 0x0000000100178750 cc1obj`c_common_parse_file() at c-opts.c:1190:7
    frame #22: 0x0000000100eaeb34 cc1obj`compile_file() at toplev.c:458:3
    frame #23: 0x0000000100eaaee5 cc1obj`do_compile() at toplev.c:2278:11
    frame #24: 0x0000000100eaa5b4 cc1obj`toplev::main(this=0x00007ffeefbff7f8, argc=24, argv=0x00007ffeefbff838) at toplev.c:2417:7
    frame #25: 0x0000000101427c0b cc1obj`main(argc=24, argv=0x00007ffeefbff838) at main.c:39:17
    frame #26: 0x00007fff6c08ecc9 libdyld.dylib`start + 1
Comment 1 Matt Jacobson 2021-07-28 23:33:51 UTC
I'm not an expert on GCC ASTs, but would this change be correct here?  I'm trying to simulate something like `struct whatever ftree[8 * 3] = {0};`.

diff --git a/gcc/objc/objc-next-runtime-abi-02.c b/gcc/objc/objc-next-runtime-abi-02.c
index e401906ed..0cc19a079 100644
--- a/gcc/objc/objc-next-runtime-abi-02.c
+++ b/gcc/objc/objc-next-runtime-abi-02.c
@@ -1631,9 +1631,8 @@ build_v2_build_objc_method_call (int super_flag, tree method_prototype,
          || TREE_CODE (ret_type) == UNION_TYPE)
        {
          vec<constructor_elt, va_gc> *rtt = NULL;
-         /* ??? CHECKME. hmmm..... think we need something more
-            here.  */
-         CONSTRUCTOR_APPEND_ELT (rtt, NULL_TREE, NULL_TREE);
+         CONSTRUCTOR_APPEND_ELT (rtt, NULL_TREE, build_int_cst (integer_type_node,
+                                                           0));
          ftree = objc_build_constructor (ret_type, rtt);
        }
       else
Comment 2 Matt Jacobson 2021-07-28 23:34:34 UTC
(Oops, ignore the `[8*3]` part in the explanation.)
Comment 4 CVS Commits 2021-08-18 18:42:30 UTC
The master branch has been updated by Iain D Sandoe <iains@gcc.gnu.org>:

https://gcc.gnu.org/g:d2aa4e0b3b5053df8f5853d9ed29022ff0d3ecf6

commit r12-3006-gd2aa4e0b3b5053df8f5853d9ed29022ff0d3ecf6
Author: Iain Sandoe <iain@sandoe.co.uk>
Date:   Sat Aug 14 12:27:55 2021 +0100

    Objective-C: fix crash with -fobjc-nilcheck
    
    When -fobjc-nilcheck is enabled, messages that result in a struct type should
    yield a zero-initialized struct when sent to nil.  Currently, the frontend
    crashes when it encounters this situation.  This patch fixes the crash by
    generating the tree for the `{}` initializer.
    
    Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>
    Co-authored-by: Matt Jacobson  <mhjacobson@me.com>
    
            PR objc/101666
    
    gcc/objc/ChangeLog:
    
            * objc-act.c (objc_build_constructor): Handle empty constructor
            lists.
            * objc-next-runtime-abi-02.c (build_v2_objc_method_fixup_call):
            Handle nil receivers.
            (build_v2_build_objc_method_call): Likewise.
    
    gcc/testsuite/ChangeLog:
    
            * obj-c++.dg/pr101666-0.mm: New test.
            * obj-c++.dg/pr101666-1.mm: New test.
            * obj-c++.dg/pr101666.inc: New.
            * objc.dg/pr101666-0.m: New test.
            * objc.dg/pr101666-1.m: New test.
            * objc.dg/pr101666.inc: New.
Comment 5 Iain Sandoe 2021-08-22 10:48:40 UTC
fixed on master, should be backported to open branches.
Comment 6 CVS Commits 2022-05-29 19:13:36 UTC
The releases/gcc-10 branch has been updated by Iain D Sandoe <iains@gcc.gnu.org>:

https://gcc.gnu.org/g:acd300cfdc434f03f1b08e46bca98b963d43ebc3

commit r10-10798-gacd300cfdc434f03f1b08e46bca98b963d43ebc3
Author: Iain Sandoe <iain@sandoe.co.uk>
Date:   Sat Aug 14 12:27:55 2021 +0100

    Objective-C: fix crash with -fobjc-nilcheck
    
    When -fobjc-nilcheck is enabled, messages that result in a struct type should
    yield a zero-initialized struct when sent to nil.  Currently, the frontend
    crashes when it encounters this situation.  This patch fixes the crash by
    generating the tree for the `{}` initializer.
    
    Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>
    Co-authored-by: Matt Jacobson  <mhjacobson@me.com>
    
            PR objc/101666
    
    gcc/objc/ChangeLog:
    
            * objc-act.c (objc_build_constructor): Handle empty constructor
            lists.
            * objc-next-runtime-abi-02.c (build_v2_objc_method_fixup_call):
            Handle nil receivers.
            (build_v2_build_objc_method_call): Likewise.
    
    gcc/testsuite/ChangeLog:
    
            * obj-c++.dg/pr101666-0.mm: New test.
            * obj-c++.dg/pr101666-1.mm: New test.
            * obj-c++.dg/pr101666.inc: New.
            * objc.dg/pr101666-0.m: New test.
            * objc.dg/pr101666-1.m: New test.
            * objc.dg/pr101666.inc: New.
    
    (cherry picked from commit d2aa4e0b3b5053df8f5853d9ed29022ff0d3ecf6)
Comment 7 Iain Sandoe 2022-05-29 19:26:13 UTC
fixed on open branches, needed on at least 9.x for vendor branches.
Comment 8 Iain Sandoe 2022-06-14 22:38:14 UTC
needed on 11.x too.