Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,17 @@ impl<Prov: Provenance> ProvenanceMap<Prov> {
}
}

/// Gets the provenances of all bytes (including from pointers) in a range.
pub fn get_range(
&self,
cx: &impl HasDataLayout,
range: AllocRange,
) -> impl Iterator<Item = Prov> {
let ptr_provs = self.range_ptrs_get(range, cx).iter().map(|(_, p)| *p);
let byte_provs = self.range_bytes_get(range).iter().map(|(_, (p, _))| *p);
ptr_provs.chain(byte_provs)
}

/// Attempt to merge per-byte provenance back into ptr chunks, if the right fragments
/// sit next to each other. Return `false` is that is not possible due to partial pointers.
pub fn merge_bytes(&mut self, cx: &impl HasDataLayout) -> bool {
Expand Down
47 changes: 26 additions & 21 deletions library/core/src/char/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1872,28 +1872,33 @@ pub const unsafe fn encode_utf8_raw_unchecked(code: u32, dst: *mut u8) {
// SAFETY: The caller must guarantee that the buffer pointed to by `dst`
// is at least `len` bytes long.
unsafe {
match len {
1 => {
*dst = code as u8;
}
2 => {
*dst = (code >> 6 & 0x1F) as u8 | TAG_TWO_B;
*dst.add(1) = (code & 0x3F) as u8 | TAG_CONT;
}
3 => {
*dst = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
*dst.add(1) = (code >> 6 & 0x3F) as u8 | TAG_CONT;
*dst.add(2) = (code & 0x3F) as u8 | TAG_CONT;
}
4 => {
*dst = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
*dst.add(1) = (code >> 12 & 0x3F) as u8 | TAG_CONT;
*dst.add(2) = (code >> 6 & 0x3F) as u8 | TAG_CONT;
*dst.add(3) = (code & 0x3F) as u8 | TAG_CONT;
}
// SAFETY: `char` always takes between 1 and 4 bytes to encode in UTF-8.
_ => crate::hint::unreachable_unchecked(),
if len == 1 {
*dst = code as u8;
return;
}

let last1 = (code >> 0 & 0x3F) as u8 | TAG_CONT;
let last2 = (code >> 6 & 0x3F) as u8 | TAG_CONT;
let last3 = (code >> 12 & 0x3F) as u8 | TAG_CONT;
let last4 = (code >> 18 & 0x3F) as u8 | TAG_FOUR_B;

if len == 2 {
*dst = last2 | TAG_TWO_B;
*dst.add(1) = last1;
return;
}

if len == 3 {
*dst = last3 | TAG_THREE_B;
*dst.add(1) = last2;
*dst.add(2) = last1;
return;
}

*dst = last4;
*dst.add(1) = last3;
*dst.add(2) = last2;
*dst.add(3) = last1;
}
}

Expand Down
9 changes: 6 additions & 3 deletions library/std/src/sync/lazy_lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,11 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
#[inline]
#[stable(feature = "lazy_cell", since = "1.80.0")]
pub fn force(this: &LazyLock<T, F>) -> &T {
this.once.call_once(|| {
this.once.call_once_force(|state| {
if state.is_poisoned() {
panic_poisoned();
}

// SAFETY: `call_once` only runs this closure once, ever.
let data = unsafe { &mut *this.data.get() };
let f = unsafe { ManuallyDrop::take(&mut data.f) };
Expand All @@ -257,8 +261,7 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
// * the closure was called and initialized `value`.
// * the closure was called and panicked, so this point is never reached.
// * the closure was not called, but a previous call initialized `value`.
// * the closure was not called because the Once is poisoned, so this point
// is never reached.
// * the closure was not called because the Once is poisoned, which we handled above.
// So `value` has definitely been initialized and will not be modified again.
unsafe { &*(*this.data.get()).value }
}
Expand Down
6 changes: 3 additions & 3 deletions library/std/src/sys/fd/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ pub struct FileDesc(OwnedFd);
//
// On Apple targets however, apparently the 64-bit libc is either buggy or
// intentionally showing odd behavior by rejecting any read with a size
// larger than or equal to INT_MAX. To handle both of these the read
// size is capped on both platforms.
// larger than INT_MAX. To handle both of these the read size is capped on
// both platforms.
const READ_LIMIT: usize = if cfg!(target_vendor = "apple") {
libc::c_int::MAX as usize - 1
libc::c_int::MAX as usize
} else {
libc::ssize_t::MAX as usize
};
Expand Down
84 changes: 53 additions & 31 deletions library/std/tests/sync/lazy_lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,6 @@ fn lazy_default() {
assert_eq!(CALLED.load(SeqCst), 1);
}

#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
fn lazy_poisoning() {
let x: LazyCell<String> = LazyCell::new(|| panic!("kaboom"));
for _ in 0..2 {
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len()));
assert!(res.is_err());
}
}

#[test]
#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
fn sync_lazy_new() {
Expand Down Expand Up @@ -123,16 +113,6 @@ fn static_sync_lazy_via_fn() {
assert_eq!(xs(), &vec![1, 2, 3]);
}

#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
fn sync_lazy_poisoning() {
let x: LazyLock<String> = LazyLock::new(|| panic!("kaboom"));
for _ in 0..2 {
let res = panic::catch_unwind(|| x.len());
assert!(res.is_err());
}
}

// Check that we can infer `T` from closure's type.
#[test]
fn lazy_type_inference() {
Expand All @@ -145,17 +125,6 @@ fn is_sync_send() {
assert_traits::<LazyLock<String>>();
}

#[test]
#[should_panic = "has previously been poisoned"]
fn lazy_force_mut_panic() {
let mut lazy = LazyLock::<String>::new(|| panic!());
panic::catch_unwind(panic::AssertUnwindSafe(|| {
let _ = LazyLock::force_mut(&mut lazy);
}))
.unwrap_err();
let _ = &*lazy;
}

#[test]
fn lazy_force_mut() {
let s = "abc".to_owned();
Expand All @@ -165,3 +134,56 @@ fn lazy_force_mut() {
p.clear();
LazyLock::force_mut(&mut lazy);
}

#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
fn lazy_poisoning() {
let x: LazyCell<String> = LazyCell::new(|| panic!("kaboom"));
for _ in 0..2 {
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len()));
assert!(res.is_err());
}
}

/// Verifies that when a `LazyLock` is poisoned, it panics with the correct error message ("LazyLock
/// instance has previously been poisoned") instead of the underlying `Once` error message.
#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
#[should_panic(expected = "LazyLock instance has previously been poisoned")]
fn lazy_lock_deref_panic() {
let lazy: LazyLock<String> = LazyLock::new(|| panic!("initialization failed"));

// First access will panic during initialization.
let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| {
let _ = &*lazy;
}));

// Second access should panic with the poisoned message.
let _ = &*lazy;
}

#[test]
#[should_panic(expected = "LazyLock instance has previously been poisoned")]
fn lazy_lock_deref_mut_panic() {
let mut lazy: LazyLock<String> = LazyLock::new(|| panic!("initialization failed"));

// First access will panic during initialization.
let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| {
let _ = LazyLock::force_mut(&mut lazy);
}));

// Second access should panic with the poisoned message.
let _ = &*lazy;
}

/// Verifies that when the initialization closure panics with a custom message, that message is
/// preserved and not overridden by `LazyLock`.
#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
#[should_panic(expected = "custom panic message from closure")]
fn lazy_lock_preserves_closure_panic_message() {
let lazy: LazyLock<String> = LazyLock::new(|| panic!("custom panic message from closure"));

// This should panic with the original message from the closure.
let _ = &*lazy;
}
4 changes: 3 additions & 1 deletion src/bootstrap/src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,14 +198,16 @@ fn check_version(config: &Config) -> Option<String> {
Some(ChangeId::Id(id)) if id == latest_change_id => return None,
Some(ChangeId::Ignore) => return None,
Some(ChangeId::Id(id)) => id,
None => {
// The warning is only useful for development, not release tarballs
None if !config.rust_info.is_from_tarball() => {
msg.push_str("WARNING: The `change-id` is missing in the `bootstrap.toml`. This means that you will not be able to track the major changes made to the bootstrap configurations.\n");
msg.push_str("NOTE: to silence this warning, ");
msg.push_str(&format!(
"add `change-id = {latest_change_id}` or `change-id = \"ignore\"` at the top of `bootstrap.toml`"
));
return Some(msg);
}
None => return None,
};

// Always try to use `change-id` from .last-warned-change-id first. If it doesn't exist,
Expand Down
53 changes: 0 additions & 53 deletions src/bootstrap/src/core/config/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,59 +327,6 @@ pub struct Config {
}

impl Config {
#[cfg_attr(
feature = "tracing",
instrument(target = "CONFIG_HANDLING", level = "trace", name = "Config::default_opts")
)]
pub fn default_opts() -> Config {
#[cfg(feature = "tracing")]
span!(target: "CONFIG_HANDLING", tracing::Level::TRACE, "constructing default config");

Config {
bypass_bootstrap_lock: false,
llvm_optimize: true,
ninja_in_file: true,
llvm_static_stdcpp: false,
llvm_libzstd: false,
backtrace: true,
rust_optimize: RustOptimize::Bool(true),
rust_optimize_tests: true,
rust_randomize_layout: false,
submodules: None,
docs: true,
docs_minification: true,
rust_rpath: true,
rust_strip: false,
channel: "dev".to_string(),
codegen_tests: true,
rust_dist_src: true,
rust_codegen_backends: vec![CodegenBackendKind::Llvm],
deny_warnings: true,
bindir: "bin".into(),
dist_include_mingw_linker: true,
dist_compression_profile: "fast".into(),

stdout_is_tty: std::io::stdout().is_terminal(),
stderr_is_tty: std::io::stderr().is_terminal(),

// set by build.rs
host_target: get_host_target(),

src: {
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
// Undo `src/bootstrap`
manifest_dir.parent().unwrap().parent().unwrap().to_owned()
},
out: PathBuf::from("build"),

// This is needed by codegen_ssa on macOS to ship `llvm-objcopy` aliased to
// `rust-objcopy` to workaround bad `strip`s on macOS.
llvm_tools_enabled: true,

..Default::default()
}
}

pub fn set_dry_run(&mut self, dry_run: DryRun) {
self.exec_ctx.set_dry_run(dry_run);
}
Expand Down
7 changes: 0 additions & 7 deletions src/tools/clippy/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,6 @@ harness = false
name = "dogfood"
harness = false

# quine-mc_cluskey makes up a significant part of the runtime in dogfood
# due to the number of conditions in the clippy_lints crate
# and enabling optimizations for that specific dependency helps a bit
# without increasing total build times.
[profile.dev.package.quine-mc_cluskey]
opt-level = 3

[lints.rust.unexpected_cfgs]
level = "warn"
check-cfg = ['cfg(bootstrap)']
11 changes: 3 additions & 8 deletions src/tools/miri/src/shims/native_lib/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,14 +242,9 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {

match evt {
AccessEvent::Read(_) => {
// FIXME: ProvenanceMap should have something like get_range().
let p_map = alloc.provenance();
for idx in overlap {
// If a provenance was read by the foreign code, expose it.
if let Some((prov, _idx)) = p_map.get_byte(Size::from_bytes(idx), this)
{
this.expose_provenance(prov)?;
}
// If a provenance was read by the foreign code, expose it.
for prov in alloc.provenance().get_range(this, overlap.into()) {
this.expose_provenance(prov)?;
}
}
AccessEvent::Write(_, certain) => {
Expand Down
Loading