diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 6217f6c9fdd33d9a7ebb06bbbd1b02e1cc1a8624..ed2127cc755fc5f47dbddac5184357e97feda701 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -32,7 +32,7 @@ }); impl_stable_hash_for!(struct mir::UpvarDecl { debug_name, var_hir_id, by_ref, mutability }); impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator, is_cleanup }); -impl_stable_hash_for!(struct mir::UnsafetyViolation { source_info, description, kind }); +impl_stable_hash_for!(struct mir::UnsafetyViolation { source_info, description, details, kind }); impl_stable_hash_for!(struct mir::UnsafetyCheckResult { violations, unsafe_blocks }); impl<'a> HashStable> diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index cd4b32735e57a220f0f395da909f91f9e364803c..6d63f0c81cd5e6ebc5798fe3b6edcfdc0cc64243 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2377,6 +2377,7 @@ pub enum UnsafetyViolationKind { pub struct UnsafetyViolation { pub source_info: SourceInfo, pub description: InternedString, + pub details: InternedString, pub kind: UnsafetyViolationKind, } diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 00e064fbb4717ce541a61a629ab05e021bfd8367..737f30f7d87595574e22df174186ac387bd28f67 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -85,7 +85,9 @@ fn visit_terminator(&mut self, let func_ty = func.ty(self.mir, self.tcx); let sig = func_ty.fn_sig(self.tcx); if let hir::Unsafety::Unsafe = sig.unsafety() { - self.require_unsafe("call to unsafe function") + self.require_unsafe("call to unsafe function", + "consult the function's documentation for information on how to avoid \ + undefined behavior") } } } @@ -112,7 +114,8 @@ fn visit_statement(&mut self, } StatementKind::InlineAsm { .. } => { - self.require_unsafe("use of inline assembly") + self.require_unsafe("use of inline assembly", + "inline assembly is entirely unchecked and can cause undefined behavior") }, } self.super_statement(block, statement, location); @@ -151,6 +154,11 @@ fn visit_place(&mut self, self.register_violations(&[UnsafetyViolation { source_info, description: Symbol::intern("borrow of packed field").as_interned_str(), + details: + Symbol::intern("fields of packed structs might be misaligned: \ + dereferencing a misaligned pointer or even just creating a \ + misaligned reference is undefined behavior") + .as_interned_str(), kind: UnsafetyViolationKind::BorrowPacked(lint_root) }], &[]); } @@ -172,7 +180,10 @@ fn visit_place(&mut self, let base_ty = base.ty(self.mir, self.tcx).to_ty(self.tcx); match base_ty.sty { ty::TyRawPtr(..) => { - self.require_unsafe("dereference of raw pointer") + self.require_unsafe("dereference of raw pointer", + "raw pointers may be NULL, dangling or unaligned; they can violate \ + aliasing rules and cause data races: all of these are undefined \ + behavior") } ty::TyAdt(adt, _) => { if adt.is_union() { @@ -190,12 +201,17 @@ fn visit_place(&mut self, if elem_ty.moves_by_default(self.tcx, self.param_env, self.source_info.span) { self.require_unsafe( - "assignment to non-`Copy` union field") + "assignment to non-`Copy` union field", + "the previous content of the field may be dropped, which \ + cause undefined behavior if the field was not properly \ + initialized") } else { // write to non-move union, safe } } else { - self.require_unsafe("access to union field") + self.require_unsafe("access to union field", + "the field may not be properly initialized: using \ + uninitialized data will cause undefined behavior") } } } @@ -208,7 +224,9 @@ fn visit_place(&mut self, } &Place::Static(box Static { def_id, ty: _ }) => { if self.tcx.is_static(def_id) == Some(hir::Mutability::MutMutable) { - self.require_unsafe("use of mutable static"); + self.require_unsafe("use of mutable static", + "mutable statics can be mutated by multiple threads: aliasing violations \ + or data races will cause undefined behavior"); } else if self.tcx.is_foreign_item(def_id) { let source_info = self.source_info; let lint_root = @@ -216,6 +234,11 @@ fn visit_place(&mut self, self.register_violations(&[UnsafetyViolation { source_info, description: Symbol::intern("use of extern static").as_interned_str(), + details: + Symbol::intern("extern statics are not controlled by the Rust type \ + system: invalid data, aliasing violations or data \ + races will cause undefined behavior") + .as_interned_str(), kind: UnsafetyViolationKind::ExternStatic(lint_root) }], &[]); } @@ -227,12 +250,14 @@ fn visit_place(&mut self, impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { fn require_unsafe(&mut self, - description: &'static str) + description: &'static str, + details: &'static str) { let source_info = self.source_info; self.register_violations(&[UnsafetyViolation { source_info, description: Symbol::intern(description).as_interned_str(), + details: Symbol::intern(details).as_interned_str(), kind: UnsafetyViolationKind::General, }], &[]); } @@ -437,33 +462,36 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { } = tcx.unsafety_check_result(def_id); for &UnsafetyViolation { - source_info, description, kind + source_info, description, details, kind } in violations.iter() { // Report an error. match kind { UnsafetyViolationKind::General => { struct_span_err!( tcx.sess, source_info.span, E0133, - "{} requires unsafe function or block", description) + "{} is unsafe and requires unsafe function or block", description) .span_label(source_info.span, &description.as_str()[..]) + .note(&details.as_str()[..]) .emit(); } UnsafetyViolationKind::ExternStatic(lint_node_id) => { - tcx.lint_node(SAFE_EXTERN_STATICS, + tcx.lint_node_note(SAFE_EXTERN_STATICS, lint_node_id, source_info.span, - &format!("{} requires unsafe function or \ - block (error E0133)", &description.as_str()[..])); + &format!("{} is unsafe and requires unsafe function or block \ + (error E0133)", &description.as_str()[..]), + &details.as_str()[..]); } UnsafetyViolationKind::BorrowPacked(lint_node_id) => { if let Some(impl_def_id) = builtin_derive_def_id(tcx, def_id) { tcx.unsafe_derive_on_repr_packed(impl_def_id); } else { - tcx.lint_node(SAFE_PACKED_BORROWS, + tcx.lint_node_note(SAFE_PACKED_BORROWS, lint_node_id, source_info.span, - &format!("{} requires unsafe function or \ - block (error E0133)", &description.as_str()[..])); + &format!("{} is unsafe and requires unsafe function or block \ + (error E0133)", &description.as_str()[..]), + &details.as_str()[..]); } } } diff --git a/src/test/compile-fail/foreign-unsafe-fn-called.rs b/src/test/compile-fail/foreign-unsafe-fn-called.rs index 88fe9cd44a39e26af233b4071e5bf2ad033c43ed..5fad4c3677c0d79b1360f124ad155fe54fcb2764 100644 --- a/src/test/compile-fail/foreign-unsafe-fn-called.rs +++ b/src/test/compile-fail/foreign-unsafe-fn-called.rs @@ -17,5 +17,5 @@ mod test { fn main() { test::free(); - //~^ ERROR call to unsafe function requires unsafe function or block + //~^ ERROR call to unsafe function is unsafe } diff --git a/src/test/compile-fail/forget-init-unsafe.rs b/src/test/compile-fail/init-unsafe.rs similarity index 87% rename from src/test/compile-fail/forget-init-unsafe.rs rename to src/test/compile-fail/init-unsafe.rs index 48c9fda31e8c80707674537252d6a2fe4306d0a9..9e599cebd7a1ceb8266a4ef1716a3d2be643f7da 100644 --- a/src/test/compile-fail/forget-init-unsafe.rs +++ b/src/test/compile-fail/init-unsafe.rs @@ -12,7 +12,7 @@ use std::intrinsics::{init}; -// Test that the `forget` and `init` intrinsics are really unsafe +// Test that the `init` intrinsic is really unsafe pub fn main() { - let stuff = init::(); //~ ERROR call to unsafe function requires unsafe + let stuff = init::(); //~ ERROR call to unsafe function is unsafe } diff --git a/src/test/compile-fail/issue-43733.rs b/src/test/compile-fail/issue-43733.rs index 90ccc589b4ea7378667a788541a1285349209a00..7b1364ff41c4023754343aa601bd9c38ccd74cf7 100644 --- a/src/test/compile-fail/issue-43733.rs +++ b/src/test/compile-fail/issue-43733.rs @@ -27,12 +27,12 @@ fn __getit() -> std::option::Option< &'static std::cell::UnsafeCell< std::option::Option>> { - __KEY.get() //~ ERROR call to unsafe function requires unsafe + __KEY.get() //~ ERROR call to unsafe function is unsafe } static FOO: std::thread::LocalKey = std::thread::LocalKey::new(__getit, Default::default); -//~^ ERROR call to unsafe function requires unsafe +//~^ ERROR call to unsafe function is unsafe fn main() { FOO.with(|foo| println!("{}", foo.borrow())); diff --git a/src/test/compile-fail/issue-45087-unreachable-unsafe.rs b/src/test/compile-fail/issue-45087-unreachable-unsafe.rs index eeb66fa0e2c3b01de118b62f85fa9b94fd8e62e4..5af0bf6be56e93147665903733a5106a985724cd 100644 --- a/src/test/compile-fail/issue-45087-unreachable-unsafe.rs +++ b/src/test/compile-fail/issue-45087-unreachable-unsafe.rs @@ -11,5 +11,5 @@ fn main() { return; *(1 as *mut u32) = 42; - //~^ ERROR dereference of raw pointer requires unsafe + //~^ ERROR dereference of raw pointer is unsafe } diff --git a/src/test/compile-fail/issue-45729-unsafe-in-generator.rs b/src/test/compile-fail/issue-45729-unsafe-in-generator.rs index 489e91797f3d76ccd79166cee1df25a0cc24ef48..b42ced07583f4f0fc63df3fe40f5c11047a9850d 100644 --- a/src/test/compile-fail/issue-45729-unsafe-in-generator.rs +++ b/src/test/compile-fail/issue-45729-unsafe-in-generator.rs @@ -13,7 +13,7 @@ fn main() { let _ = || { *(1 as *mut u32) = 42; - //~^ ERROR dereference of raw pointer requires unsafe + //~^ ERROR dereference of raw pointer is unsafe yield; }; } diff --git a/src/test/compile-fail/issue-47412.rs b/src/test/compile-fail/issue-47412.rs index 7481befcb7952c91dc17b0e8de7d604216993dca..683ef876f4e37ca7ac3b4e0bb3c9bdde1d275589 100644 --- a/src/test/compile-fail/issue-47412.rs +++ b/src/test/compile-fail/issue-47412.rs @@ -19,13 +19,13 @@ fn union_field() { union Union { unit: (), void: Void } let u = Union { unit: () }; match u.void {} - //~^ ERROR access to union field requires unsafe function or block + //~^ ERROR access to union field is unsafe } fn raw_ptr_deref() { let ptr = std::ptr::null::(); match *ptr {} - //~^ ERROR dereference of raw pointer requires unsafe function or block + //~^ ERROR dereference of raw pointer is unsafe } fn main() {} diff --git a/src/test/compile-fail/safe-extern-statics-mut.rs b/src/test/compile-fail/safe-extern-statics-mut.rs index ed8d5900776a9f79be0576a736a69b67d3718b75..35ea6dd52c4f28fe29ff3cc19f326ca5e9fb46b4 100644 --- a/src/test/compile-fail/safe-extern-statics-mut.rs +++ b/src/test/compile-fail/safe-extern-statics-mut.rs @@ -18,8 +18,8 @@ } fn main() { - let b = B; //~ ERROR use of mutable static requires unsafe function or block - let rb = &B; //~ ERROR use of mutable static requires unsafe function or block - let xb = XB; //~ ERROR use of mutable static requires unsafe function or block - let xrb = &XB; //~ ERROR use of mutable static requires unsafe function or block + let b = B; //~ ERROR use of mutable static is unsafe + let rb = &B; //~ ERROR use of mutable static is unsafe + let xb = XB; //~ ERROR use of mutable static is unsafe + let xrb = &XB; //~ ERROR use of mutable static is unsafe } diff --git a/src/test/compile-fail/safe-extern-statics.rs b/src/test/compile-fail/safe-extern-statics.rs index 4d939f33c46dccd67ce03f54812efed0a7d2615c..83aa4b3316da0b7b9781ac2df49f1e977525c66c 100644 --- a/src/test/compile-fail/safe-extern-statics.rs +++ b/src/test/compile-fail/safe-extern-statics.rs @@ -20,12 +20,12 @@ } fn main() { - let a = A; //~ ERROR use of extern static requires unsafe function or block + let a = A; //~ ERROR use of extern static is unsafe //~^ WARN this was previously accepted by the compiler - let ra = &A; //~ ERROR use of extern static requires unsafe function or block + let ra = &A; //~ ERROR use of extern static is unsafe //~^ WARN this was previously accepted by the compiler - let xa = XA; //~ ERROR use of extern static requires unsafe function or block + let xa = XA; //~ ERROR use of extern static is unsafe //~^ WARN this was previously accepted by the compiler - let xra = &XA; //~ ERROR use of extern static requires unsafe function or block + let xra = &XA; //~ ERROR use of extern static is unsafe //~^ WARN this was previously accepted by the compiler } diff --git a/src/test/compile-fail/union/union-unsafe.rs b/src/test/compile-fail/union/union-unsafe.rs index e57d65dcb891f7b5b1439969f12ac5e80e617be9..d993816e6f476f6234f1e8db55766ef8362bb0c8 100644 --- a/src/test/compile-fail/union/union-unsafe.rs +++ b/src/test/compile-fail/union/union-unsafe.rs @@ -28,7 +28,7 @@ union U4 { fn generic_noncopy() { let mut u3 = U3 { a: T::default() }; - u3.a = T::default(); //~ ERROR assignment to non-`Copy` union field requires unsafe + u3.a = T::default(); //~ ERROR assignment to non-`Copy` union field is unsafe } fn generic_copy() { @@ -40,16 +40,16 @@ fn generic_copy() { fn main() { let mut u1 = U1 { a: 10 }; // OK - let a = u1.a; //~ ERROR access to union field requires unsafe + let a = u1.a; //~ ERROR access to union field is unsafe u1.a = 11; // OK - let U1 { a } = u1; //~ ERROR access to union field requires unsafe - if let U1 { a: 12 } = u1 {} //~ ERROR access to union field requires unsafe + let U1 { a } = u1; //~ ERROR access to union field is unsafe + if let U1 { a: 12 } = u1 {} //~ ERROR access to union field is unsafe // let U1 { .. } = u1; // OK let mut u2 = U2 { a: String::from("old") }; // OK - u2.a = String::from("new"); //~ ERROR assignment to non-`Copy` union field requires unsafe + u2.a = String::from("new"); //~ ERROR assignment to non-`Copy` union field is unsafe let mut u3 = U3 { a: 0 }; // OK u3.a = 1; // OK let mut u3 = U3 { a: String::from("old") }; // OK - u3.a = String::from("new"); //~ ERROR assignment to non-`Copy` union field requires unsafe + u3.a = String::from("new"); //~ ERROR assignment to non-`Copy` union field is unsafe } diff --git a/src/test/compile-fail/unsafe-fn-assign-deref-ptr.rs b/src/test/compile-fail/unsafe-fn-assign-deref-ptr.rs index f30da250f6ac80f2eb8a0ec66d429a4d17c6d077..baf2002a94fc905157f2e3403c5219e98a5c2a67 100644 --- a/src/test/compile-fail/unsafe-fn-assign-deref-ptr.rs +++ b/src/test/compile-fail/unsafe-fn-assign-deref-ptr.rs @@ -11,7 +11,7 @@ fn f(p: *mut u8) { - *p = 0; //~ ERROR dereference of raw pointer requires unsafe function or block + *p = 0; //~ ERROR dereference of raw pointer is unsafe return; } diff --git a/src/test/compile-fail/unsafe-fn-called-from-safe.rs b/src/test/compile-fail/unsafe-fn-called-from-safe.rs index 15bcad95cb22b36568e7e2e388fcaa1ee1248965..46f28da43d03b4493cbc5ce12750482fe2009f8a 100644 --- a/src/test/compile-fail/unsafe-fn-called-from-safe.rs +++ b/src/test/compile-fail/unsafe-fn-called-from-safe.rs @@ -12,5 +12,5 @@ unsafe fn f() { return; } fn main() { - f(); //~ ERROR call to unsafe function requires unsafe function or block + f(); //~ ERROR call to unsafe function is unsafe } diff --git a/src/test/compile-fail/unsafe-fn-deref-ptr.rs b/src/test/compile-fail/unsafe-fn-deref-ptr.rs index bf87df71fd87dc77163aebfe05b48caec1ef56c1..8e3ce8ff9b57d84fa1c373afeb7ae1f8b73ca21d 100644 --- a/src/test/compile-fail/unsafe-fn-deref-ptr.rs +++ b/src/test/compile-fail/unsafe-fn-deref-ptr.rs @@ -10,7 +10,7 @@ fn f(p: *const u8) -> u8 { - return *p; //~ ERROR dereference of raw pointer requires unsafe function or block + return *p; //~ ERROR dereference of raw pointer is unsafe } fn main() { diff --git a/src/test/compile-fail/unsafe-fn-used-as-value.rs b/src/test/compile-fail/unsafe-fn-used-as-value.rs index 8e2d82b8fdbf448fab5d5f4b6c730fdaebc7f760..f09a0c7107a8a847e41bf8ab86d32669068c94ab 100644 --- a/src/test/compile-fail/unsafe-fn-used-as-value.rs +++ b/src/test/compile-fail/unsafe-fn-used-as-value.rs @@ -13,5 +13,5 @@ fn main() { let x = f; - x(); //~ ERROR call to unsafe function requires unsafe function or block + x(); //~ ERROR call to unsafe function is unsafe } diff --git a/src/test/compile-fail/unsafe-move-val-init.rs b/src/test/compile-fail/unsafe-move-val-init.rs index 84a8c84a0dbd203ae46cf6ca2e64a06e097b4fb6..b4e425e7bbff130ecdaa3c230735d5ca1200408e 100644 --- a/src/test/compile-fail/unsafe-move-val-init.rs +++ b/src/test/compile-fail/unsafe-move-val-init.rs @@ -16,5 +16,5 @@ // as unsafe. fn main() { intrinsics::move_val_init(1 as *mut u32, 1); - //~^ ERROR dereference of raw pointer requires unsafe function or block + //~^ ERROR dereference of raw pointer is unsafe } diff --git a/src/test/ui/error-codes/E0133.stderr b/src/test/ui/error-codes/E0133.stderr index dc57a6274445f1eb64de577649f9a6b1dcf388dd..9be80f8f21baa4dcb6c8b62f2fa0a5c9cd035679 100644 --- a/src/test/ui/error-codes/E0133.stderr +++ b/src/test/ui/error-codes/E0133.stderr @@ -1,8 +1,10 @@ -error[E0133]: call to unsafe function requires unsafe function or block +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block --> $DIR/E0133.rs:14:5 | LL | f(); | ^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior error: aborting due to previous error diff --git a/src/test/compile-fail/issue-27060.rs b/src/test/ui/issue-27060.rs similarity index 88% rename from src/test/compile-fail/issue-27060.rs rename to src/test/ui/issue-27060.rs index 37369d551fc7702270b03d505eeefb53dc047b2d..f88c2137e77ef44353eb51728ff18e35d2133a90 100644 --- a/src/test/compile-fail/issue-27060.rs +++ b/src/test/ui/issue-27060.rs @@ -33,9 +33,9 @@ fn main() { let _ = &good.data2[0]; // ok } - let _ = &good.data; //~ ERROR borrow of packed field requires unsafe + let _ = &good.data; //~ ERROR borrow of packed field is unsafe //~| hard error - let _ = &good.data2[0]; //~ ERROR borrow of packed field requires unsafe + let _ = &good.data2[0]; //~ ERROR borrow of packed field is unsafe //~| hard error let _ = &*good.data; // ok, behind a pointer let _ = &good.aligned; // ok, has align 1 diff --git a/src/test/ui/issue-27060.stderr b/src/test/ui/issue-27060.stderr new file mode 100644 index 0000000000000000000000000000000000000000..bd01f75d8fbc991ba2eef7bdc47bf705d5789119 --- /dev/null +++ b/src/test/ui/issue-27060.stderr @@ -0,0 +1,27 @@ +error: borrow of packed field is unsafe and requires unsafe function or block (error E0133) + --> $DIR/issue-27060.rs:36:13 + | +LL | let _ = &good.data; //~ ERROR borrow of packed field is unsafe + | ^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/issue-27060.rs:23:8 + | +LL | #[deny(safe_packed_borrows)] + | ^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + +error: borrow of packed field is unsafe and requires unsafe function or block (error E0133) + --> $DIR/issue-27060.rs:38:13 + | +LL | let _ = &good.data2[0]; //~ ERROR borrow of packed field is unsafe + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/issue-28776.stderr b/src/test/ui/issue-28776.stderr index 3b468a882054433e4023d6a94575294a754bc12f..aef0d9cd1d8c6bba1267a8490c8d56e38a2acf09 100644 --- a/src/test/ui/issue-28776.stderr +++ b/src/test/ui/issue-28776.stderr @@ -1,8 +1,10 @@ -error[E0133]: call to unsafe function requires unsafe function or block +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block --> $DIR/issue-28776.rs:14:5 | LL | (&ptr::write)(1 as *mut _, 42); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior error: aborting due to previous error diff --git a/src/test/ui/trait-safety-fn-body.stderr b/src/test/ui/trait-safety-fn-body.stderr index 432df4382227819854f806f70bc6e9cb68cce869..0b7b6e6167867b08e4ea7e17a71e7fdde84223c7 100644 --- a/src/test/ui/trait-safety-fn-body.stderr +++ b/src/test/ui/trait-safety-fn-body.stderr @@ -1,8 +1,10 @@ -error[E0133]: dereference of raw pointer requires unsafe function or block +error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block --> $DIR/trait-safety-fn-body.rs:21:9 | LL | *self += 1; | ^^^^^^^^^^ dereference of raw pointer + | + = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior error: aborting due to previous error diff --git a/src/test/ui/unsafe-const-fn.stderr b/src/test/ui/unsafe-const-fn.stderr index 270b90ec3fcbe90fe4470c3436d665bc19503d08..d4b3ed687e5e43b956c595f7004e9f29cb1d9e00 100644 --- a/src/test/ui/unsafe-const-fn.stderr +++ b/src/test/ui/unsafe-const-fn.stderr @@ -1,8 +1,10 @@ -error[E0133]: call to unsafe function requires unsafe function or block +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block --> $DIR/unsafe-const-fn.rs:19:18 | LL | const VAL: u32 = dummy(0xFFFF); | ^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior error: aborting due to previous error