From 8cd9dfad1e2f24e52e022bdad52f23286af8c571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Thu, 17 Feb 2022 00:00:00 +0000 Subject: [PATCH] Fix ScalarInt to char conversion to avoid panic for invalid Unicode scalar values --- compiler/rustc_middle/src/ty/consts/int.rs | 18 +++++-- .../invalid_constant.main.ConstProp.diff | 48 ++++++++++++------- .../mir-opt/const_prop/invalid_constant.rs | 8 +++- 3 files changed, 52 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index de45e1bb851ac..ca1db2fd55141 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -294,12 +294,22 @@ impl From for ScalarInt { } } +/// Error returned when a conversion from ScalarInt to char fails. +#[derive(Debug)] +pub struct CharTryFromScalarInt; + impl TryFrom for char { - type Error = Size; + type Error = CharTryFromScalarInt; + #[inline] - fn try_from(int: ScalarInt) -> Result { - int.to_bits(Size::from_bytes(std::mem::size_of::())) - .map(|u| char::from_u32(u.try_into().unwrap()).unwrap()) + fn try_from(int: ScalarInt) -> Result { + let Ok(bits) = int.to_bits(Size::from_bytes(std::mem::size_of::())) else { + return Err(CharTryFromScalarInt); + }; + match char::from_u32(bits.try_into().unwrap()) { + Some(c) => Ok(c), + None => Err(CharTryFromScalarInt), + } } } diff --git a/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff b/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff index ee6c3b5f36fd4..1b53318806f4d 100644 --- a/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff @@ -5,39 +5,53 @@ let mut _0: (); // return place in scope 0 at $DIR/invalid_constant.rs:15:11: 15:11 let _1: std::option::Option<()>; // in scope 0 at $DIR/invalid_constant.rs:16:5: 16:12 let mut _2: std::option::Option>; // in scope 0 at $DIR/invalid_constant.rs:16:7: 16:11 - scope 1 (inlined f) { // at $DIR/invalid_constant.rs:16:5: 16:12 - debug x => _2; // in scope 1 at $DIR/invalid_constant.rs:16:5: 16:12 - let mut _3: isize; // in scope 1 at $DIR/invalid_constant.rs:16:5: 16:12 - let _4: std::option::Option<()>; // in scope 1 at $DIR/invalid_constant.rs:16:5: 16:12 - scope 2 { - debug y => _4; // in scope 2 at $DIR/invalid_constant.rs:16:5: 16:12 + let _3: main::Union; // in scope 0 at $DIR/invalid_constant.rs:22:9: 22:22 + scope 1 { + debug _invalid_char => _3; // in scope 1 at $DIR/invalid_constant.rs:22:9: 22:22 + } + scope 2 (inlined f) { // at $DIR/invalid_constant.rs:16:5: 16:12 + debug x => _2; // in scope 2 at $DIR/invalid_constant.rs:16:5: 16:12 + let mut _4: isize; // in scope 2 at $DIR/invalid_constant.rs:16:5: 16:12 + let _5: std::option::Option<()>; // in scope 2 at $DIR/invalid_constant.rs:16:5: 16:12 + scope 3 { + debug y => _5; // in scope 3 at $DIR/invalid_constant.rs:16:5: 16:12 } } bb0: { discriminant(_2) = 0; // scope 0 at $DIR/invalid_constant.rs:16:7: 16:11 -- _3 = discriminant(_2); // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12 -- switchInt(move _3) -> [0_isize: bb3, otherwise: bb2]; // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12 -+ _3 = const 0_isize; // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12 -+ switchInt(const 0_isize) -> [0_isize: bb3, otherwise: bb2]; // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12 +- _4 = discriminant(_2); // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12 +- switchInt(move _4) -> [0_isize: bb3, otherwise: bb2]; // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12 ++ _4 = const 0_isize; // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12 ++ switchInt(const 0_isize) -> [0_isize: bb3, otherwise: bb2]; // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12 } bb1: { - nop; // scope 0 at $DIR/invalid_constant.rs:15:11: 17:2 - return; // scope 0 at $DIR/invalid_constant.rs:17:2: 17:2 +- _3 = const { Union { int: 0x110001 } }; // scope 0 at $DIR/invalid_constant.rs:22:25: 22:58 ++ _3 = const main::Union { int: 1114113_u32, chr: {transmute(0x00110001): char} }; // scope 0 at $DIR/invalid_constant.rs:22:25: 22:58 + // ty::Const + // + ty: main::Union +- // + val: Unevaluated(main::{constant#0}, [main::Union], None) ++ // + val: Value(Scalar(0x00110001)) + // mir::Constant + // + span: $DIR/invalid_constant.rs:22:25: 22:58 +- // + literal: Const { ty: main::Union, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:8 ~ invalid_constant[726d]::main::{constant#0}), const_param_did: None }, substs: [main::Union], promoted: None }) } ++ // + literal: Const { ty: main::Union, val: Value(Scalar(0x00110001)) } + nop; // scope 0 at $DIR/invalid_constant.rs:15:11: 23:2 + return; // scope 0 at $DIR/invalid_constant.rs:23:2: 23:2 } bb2: { -- _4 = ((_2 as Some).0: std::option::Option<()>); // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12 -- _1 = _4; // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12 -+ _4 = const Scalar(0x02): Option::<()>; // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12 +- _5 = ((_2 as Some).0: std::option::Option<()>); // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12 +- _1 = _5; // scope 3 at $DIR/invalid_constant.rs:16:5: 16:12 ++ _5 = const Scalar(0x02): Option::<()>; // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12 + // ty::Const + // + ty: std::option::Option<()> + // + val: Value(Scalar(0x02)) + // mir::Constant + // + span: $DIR/invalid_constant.rs:16:5: 16:12 + // + literal: Const { ty: std::option::Option<()>, val: Value(Scalar(0x02)) } -+ _1 = const Scalar(0x02): Option::<()>; // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12 ++ _1 = const Scalar(0x02): Option::<()>; // scope 3 at $DIR/invalid_constant.rs:16:5: 16:12 + // ty::Const + // + ty: std::option::Option<()> + // + val: Value(Scalar(0x02)) @@ -48,7 +62,7 @@ } bb3: { - discriminant(_1) = 0; // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12 + discriminant(_1) = 0; // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12 goto -> bb1; // scope 0 at $DIR/invalid_constant.rs:9:17: 9:21 } } diff --git a/src/test/mir-opt/const_prop/invalid_constant.rs b/src/test/mir-opt/const_prop/invalid_constant.rs index 1eb6f37df5968..4aca90900199e 100644 --- a/src/test/mir-opt/const_prop/invalid_constant.rs +++ b/src/test/mir-opt/const_prop/invalid_constant.rs @@ -2,7 +2,7 @@ // by constant propagation. Regression test for issue #93688. // // compile-flags: -Copt-level=0 -Zinline-mir - +#![feature(inline_const)] #[inline(always)] pub fn f(x: Option>) -> Option<()> { match x { @@ -14,4 +14,10 @@ pub fn f(x: Option>) -> Option<()> { // EMIT_MIR invalid_constant.main.ConstProp.diff fn main() { f(None); + + union Union { + int: u32, + chr: char, + } + let _invalid_char = const { Union { int: 0x110001 } }; }