Open DCNick3 opened 1 year ago
This appears to be because canonical_macro_replacement()
is calling resolve_expr_type_id()
, which then discards the intermediate types:
#define TEST_CAST ((short)0x8000)
int test_cast() { return TEST_CAST; }
trace: Expanding macro CDeclId(337): Located { loc: Some(SrcSpan { fileid: 1, begin_line: 84, begin_column: 9, end_line: 84, end_column: 33 }), kind: MacroObject { name: "TEST_CAST" } }
trace: resolve_expr_type: Some(CTypeId(15)) // ImplicitCast(CQualTypeId { qualifiers: Qualifiers { is_const: false, is_restrict: false, is_volatile: false }, ctype: CTypeId(15) }, CExprId(338), IntegralCast, None, RValue)
trace: resolve_expr_type: Some(CTypeId(66)) // ExplicitCast(CQualTypeId { qualifiers: Qualifiers { is_const: false, is_restrict: false, is_volatile: false }, ctype: CTypeId(66) }, CExprId(340), IntegralCast, None, RValue)
trace: resolve_expr_type: Some(CTypeId(15)) // Literal(CQualTypeId { qualifiers: Qualifiers { is_const: false, is_restrict: false, is_volatile: false }, ctype: CTypeId(15) }, Integer(32768, Hex))
A bug I found when working on unsafe-libopus
Apparently, when const macro translation is enabled, some casts are dropped, which leads to a change in semantics.
Reproducible case
Without
--translate-const-macros
:Outputs
-32768
With
--translate-const-macros
:Outputs
32768
The bug
When no constants are generated the value is correctly cast to
c_short
before being widened back:0x8000 as libc::c_int as libc::c_short as libc::c_int
When constant translation is enabled, however, the
0x8000
constant is not cast to theshort
type and stored directly as an int, which is incorrect