saltwater
saltwater copied to clipboard
[ICE] infinite recursion on union containing itself
Expected behavior RCC gives an error.
Actual Behavior RCC segfaults.
Code
union u { int _; };
union u{
union u{
struct u _;
} i: i
}
Segmentation fault
Backtrace
From GDB:#46064 0x0000555555816405 in rcc::arch::<impl rcc::data::types::struct_ref::StructType>::union_size (self=0x555555f4d648) at src/arch/mod.rs:70
#46065 0x000055555570a186 in rcc::arch::<impl rcc::data::types::Type>::sizeof (self=0x555555f4d640) at src/arch/mod.rs:119
#46066 0x00005555557dacf3 in rcc::arch::<impl rcc::data::types::struct_ref::StructType>::union_size::{{closure}} (symbol=0x555555f4d640) at src/arch/mod.rs:72
#46067 0x00005555557e27f1 in core::iter::adapters::map_try_fold::{{closure}} (acc=1, elt=0x555555f4d640) at /rustc/73528e339aae0f17a15ffa49a8ac608f50c6cf14/src/libcore/iter/adapters/mod.rs:701
#46068 0x000055555572668a in core::iter::traits::iterator::Iterator::try_fold (self=0x7fffffff6330, init=1, f=...) at /rustc/73528e339aae0f17a15ffa49a8ac608f50c6cf14/src/libcore/iter/traits/iterator.rs:1709
#46069 0x00005555557e6074 in <core::iter::adapters::Map<I,F> as core::iter::traits::iterator::Iterator>::try_fold (self=0x7fffffff6330, init=1, g=...) at /rustc/73528e339aae0f17a15ffa49a8ac608f50c6cf14/src/libcore/iter/adapters/mod.rs:721
#46070 0x0000555555816405 in rcc::arch::<impl rcc::data::types::struct_ref::StructType>::union_size (self=0x7fffffff6f98) at src/arch/mod.rs:70
#46071 0x000055555570a186 in rcc::arch::<impl rcc::data::types::Type>::sizeof (self=0x7fffffff6f90) at src/arch/mod.rs:119
#46072 0x00005555556b382c in rcc::parse::decl::<impl rcc::parse::Parser<I>>::struct_declarator_list (self=0x7fffffffbf90, members=0x7fffffff7858) at src/parse/decl.rs:797
#46073 0x00005555556ae740 in rcc::parse::decl::<impl rcc::parse::Parser<I>>::struct_declaration (self=0x7fffffffbf90, ident=..., c_struct=false, location=0x7fffffff8c30) at src/parse/decl.rs:705
#46074 0x00005555556a9a83 in rcc::parse::decl::<impl rcc::parse::Parser<I>>::compound_specifier (self=0x7fffffffbf90, kind=rcc::data::lex::Keyword::Union, location=...) at src/parse/decl.rs:555
#46075 0x00005555556a6b65 in rcc::parse::decl::<impl rcc::parse::Parser<I>>::declaration_specifiers (self=0x7fffffffbf90) at src/parse/decl.rs:376
#46076 0x000055555569f949 in rcc::parse::decl::<impl rcc::parse::Parser<I>>::declaration (self=0x7fffffffbf90) at src/parse/decl.rs:68
#46077 0x00005555556ffb49 in <rcc::parse::Parser<I> as core::iter::traits::iterator::Iterator>::next::{{closure}} () at src/parse/mod.rs:147
#46078 0x000055555571ef76 in core::option::Option<T>::or_else (self=..., f=...) at /rustc/73528e339aae0f17a15ffa49a8ac608f50c6cf14/src/libcore/option.rs:751
#46079 0x00005555556ff7d3 in <rcc::parse::Parser<I> as core::iter::traits::iterator::Iterator>::next (self=0x7fffffffbf90) at src/parse/mod.rs:125
#46080 0x00005555556ffe0f in <rcc::parse::Parser<I> as core::iter::traits::iterator::Iterator>::next::{{closure}} () at src/parse/mod.rs:158
#46081 0x000055555571ef76 in core::option::Option<T>::or_else (self=..., f=...) at /rustc/73528e339aae0f17a15ffa49a8ac608f50c6cf14/src/libcore/option.rs:751
#46082 0x00005555556ff7d3 in <rcc::parse::Parser<I> as core::iter::traits::iterator::Iterator>::next (self=0x7fffffffbf90) at src/parse/mod.rs:125
#46083 0x000055555569e0af in <&mut I as core::iter::traits::iterator::Iterator>::next (self=0x7fffffffc128) at /rustc/73528e339aae0f17a15ffa49a8ac608f50c6cf14/src/libcore/iter/traits/iterator.rs:2990
#46084 0x0000555555663a48 in rcc::compile (buf=..., opt=0x7fffffffe340) at src/lib.rs:137
#46085 0x00005555555f8b4b in rcc::real_main (file_db=0x7fffffffe650, file_id=..., opt=0x7fffffffe340, output=0x7ffff7ffefe0) at src/main.rs:73
#46086 0x00005555555fa011 in rcc::main () at src/main.rs:135
sizeof
is trying to calculate it indefinitely, but the real issue is that the parser shouldn't allow types to contain themselves.
Thanks to @Byter09 for the help fuzzing.
Related to C11 standard 6.7.2.1p3
A structure or union shall not contain a member with incomplete or function type (hence, a structure shall not contain an instance of itself, but may contain a pointer to an instance of itself), except that the last member of a structure with more than one named member may have incomplete array type; such a structure (and any union containing, possibly recursively, a member that is such a structure) shall not be a member of a structure or an element of an array.
Standard 6.7.2.3p4
All declarations of structure, union, or enumerated types that have the same scope and use the same tag declare the same type. Irrespective of whether there is a tag or what other declarations of the type are in the same translation unit, the type is incomplete [129]) until immediately after the closing brace of the list defining the content, and complete thereafter.
Is there already a notion of complete vs incomplete types in rcc or no?
There is. Now that you say that, I think I see the bug: https://github.com/jyn514/rcc/blob/96f70a672b0e4dc03ec9ac1abfc4da1e2b9292c9/src/parse/expr.rs#L1600
Hmm, but this seems like it should have already been caught: https://github.com/jyn514/rcc/blob/96f70a672b0e4dc03ec9ac1abfc4da1e2b9292c9/src/parse/decl.rs#L831
Aha! We calculate the size of the struct for the bitfield before we catch that error: https://github.com/jyn514/rcc/blob/96f70a672b0e4dc03ec9ac1abfc4da1e2b9292c9/src/parse/decl.rs#L803.
This will probably be fixed by #151. In the meantime, though, it should be a quick fix to move that bitfield block below the check for a forward declaration.
I'm getting a borrow of moved memory error if I rearrange the two blocks because symbol
is being used in the match
block. It seems the members.push(symbol)
should be separate from the constraint checking. Is it worth pursuing this or not since it's very clearly an issue of parsing and semantic analysis being too tightly coupled anyway (as in #151)?
error[E0382]: borrow of moved value: `symbol.ctype`
--> src/parse/decl.rs:839:46
|
801 | let mut symbol = Symbol {
| ---------- move occurs because `symbol` has type `data::Symbol`, which does not implement the `Copy` trait
...
823 | members.push(symbol);
| ------ value moved here
824 | }
825 | _ => members.push(symbol),
| ------ value moved here
...
839 | symbol.id, bit_size, symbol.ctype
| ^^^^^^^^^^^^ value borrowed here after move
You could fix this by taking members.push(symbol)
out of the match and moving it after the (newly reordered) bitfield check.
Reordering doesn't work because incomplete types are not yet implemented for struct/union. As much as I'd like to pursue this further, I think this will require modifying TYPES
to have a "complete" flag and I am not confident enough to do this.
The original is fixed (mostly because of the split in #370). With fixed syntax, it also gives the proper errors:
union u { int _; };
union u{
union u{
struct u _;
} i: i
;
};
<stdin>:2:6 warning: bitfields are not implemented and will be ignored
<stdin>:2:6 error: invalid program: use of 'u' with type tag 'struct' that does not match previous struct declaration
<stdin>:2:6 error: invalid program: redefinition of union 'u'
<stdin>:5:9 error: invalid program: use of undeclared identifier 'i'
} i: i
<stdin>:2:6 error: invalid program: C does not have zero-sized types. hint: omit the declarator i
<stdin>:2:6 error: invalid program: redefinition of union 'u'
// compile-fail
// https://gdthub.com/jyn514/rcc/issues/261
union u {
struct u {
union u { _; };
union u _;
} i: i;
};
Is still crashing.
Found inputs attached: union-crash.tar.gz