Auto merge of #130483 - matthiaskrgr:rollup-q1r0g0y, r=matthiaskrgr
Rollup of 5 pull requests Successful merges: - #129477 (Fix fluent diagnostics) - #129674 (Add new_cyclic_in for Rc and Arc) - #130452 (Update Trusty target maintainers) - #130467 (Miri subtree update) - #130477 (Revert #129749 to fix segfault in LLVM) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
28e8f01c2a
92
Cargo.lock
92
Cargo.lock
@ -104,15 +104,6 @@ dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.15"
|
||||
@ -714,7 +705,7 @@ dependencies = [
|
||||
"miow",
|
||||
"miropt-test-tools",
|
||||
"regex",
|
||||
"rustfix 0.8.1",
|
||||
"rustfix",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tracing",
|
||||
@ -2278,7 +2269,7 @@ dependencies = [
|
||||
"rustc_version",
|
||||
"smallvec",
|
||||
"tempfile",
|
||||
"ui_test 0.21.2",
|
||||
"ui_test 0.26.5",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
@ -2807,16 +2798,6 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
|
||||
|
||||
[[package]]
|
||||
name = "prettydiff"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ff1fec61082821f8236cf6c0c14e8172b62ce8a72a0eedc30d3b247bb68dc11"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"pad",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prettydiff"
|
||||
version = "0.7.0"
|
||||
@ -4625,18 +4606,6 @@ dependencies = [
|
||||
"rustdoc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustfix"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecd2853d9e26988467753bd9912c3a126f642d05d229a4b53f5752ee36c56481"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustfix"
|
||||
version = "0.8.1"
|
||||
@ -5516,33 +5485,6 @@ version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
|
||||
|
||||
[[package]]
|
||||
name = "ui_test"
|
||||
version = "0.21.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aaf4bf7c184b8dfc7a4d3b90df789b1eb992ee42811cd115f32a7a1eb781058d"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.2",
|
||||
"anyhow",
|
||||
"bstr",
|
||||
"cargo-platform",
|
||||
"cargo_metadata 0.15.4",
|
||||
"color-eyre",
|
||||
"colored",
|
||||
"comma",
|
||||
"crossbeam-channel",
|
||||
"indicatif",
|
||||
"lazy_static",
|
||||
"levenshtein",
|
||||
"prettydiff 0.6.4",
|
||||
"regex",
|
||||
"rustc_version",
|
||||
"rustfix 0.6.1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ui_test"
|
||||
version = "0.25.0"
|
||||
@ -5561,10 +5503,36 @@ dependencies = [
|
||||
"indicatif",
|
||||
"lazy_static",
|
||||
"levenshtein",
|
||||
"prettydiff 0.7.0",
|
||||
"prettydiff",
|
||||
"regex",
|
||||
"rustc_version",
|
||||
"rustfix 0.8.1",
|
||||
"rustfix",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"spanned",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ui_test"
|
||||
version = "0.26.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32ee4c40e5a5f9fa6864ff976473e5d6a6e9884b6ce68b40690d9f87e1994c83"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.11.4",
|
||||
"anyhow",
|
||||
"bstr",
|
||||
"cargo-platform",
|
||||
"cargo_metadata 0.18.1",
|
||||
"color-eyre",
|
||||
"colored",
|
||||
"comma",
|
||||
"crossbeam-channel",
|
||||
"indicatif",
|
||||
"levenshtein",
|
||||
"prettydiff",
|
||||
"regex",
|
||||
"rustc_version",
|
||||
"rustfix",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"spanned",
|
||||
|
@ -138,25 +138,8 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
|
||||
// with a lowercase as rustc errors do.
|
||||
err.replace_range(0..1, &err.chars().next().unwrap().to_lowercase().to_string());
|
||||
|
||||
let line_starts: Vec<usize> = std::iter::once(0)
|
||||
.chain(
|
||||
this.source()
|
||||
.char_indices()
|
||||
.filter_map(|(i, c)| Some(i + 1).filter(|_| c == '\n')),
|
||||
)
|
||||
.collect();
|
||||
let line_start = line_starts
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(line, idx)| (line + 1, idx))
|
||||
.filter(|(_, idx)| **idx <= pos.start)
|
||||
.last()
|
||||
.unwrap()
|
||||
.0;
|
||||
|
||||
let message = annotate_snippets::Level::Error.title(&err).snippet(
|
||||
Snippet::source(this.source())
|
||||
.line_start(line_start)
|
||||
.origin(&relative_ftl_path)
|
||||
.fold(true)
|
||||
.annotation(annotate_snippets::Level::Error.span(pos.start..pos.end - 1)),
|
||||
|
@ -1211,11 +1211,7 @@ struct LLVMRustThinLTOData {
|
||||
// Not 100% sure what these are, but they impact what's internalized and
|
||||
// what's inlined across modules, I believe.
|
||||
#if LLVM_VERSION_GE(18, 0)
|
||||
#if LLVM_VERSION_GE(20, 0)
|
||||
FunctionImporter::ImportListsTy ImportLists;
|
||||
#else
|
||||
DenseMap<StringRef, FunctionImporter::ImportMapTy> ImportLists;
|
||||
#endif
|
||||
DenseMap<StringRef, FunctionImporter::ExportSetTy> ExportLists;
|
||||
DenseMap<StringRef, GVSummaryMapTy> ModuleToDefinedGVSummaries;
|
||||
#else
|
||||
@ -1424,13 +1420,13 @@ LLVMRustPrepareThinLTOInternalize(const LLVMRustThinLTOData *Data,
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" bool LLVMRustPrepareThinLTOImport(LLVMRustThinLTOData *Data,
|
||||
extern "C" bool LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data,
|
||||
LLVMModuleRef M,
|
||||
LLVMTargetMachineRef TM) {
|
||||
Module &Mod = *unwrap(M);
|
||||
TargetMachine &Target = *unwrap(TM);
|
||||
|
||||
const auto &ImportList = Data->ImportLists[Mod.getModuleIdentifier()];
|
||||
const auto &ImportList = Data->ImportLists.lookup(Mod.getModuleIdentifier());
|
||||
auto Loader = [&](StringRef Identifier) {
|
||||
const auto &Memory = Data->ModuleMap.lookup(Identifier);
|
||||
auto &Context = Mod.getContext();
|
||||
@ -1613,7 +1609,7 @@ extern "C" void LLVMRustComputeLTOCacheKey(RustStringRef KeyOut,
|
||||
LLVMRustThinLTOData *Data) {
|
||||
SmallString<40> Key;
|
||||
llvm::lto::Config conf;
|
||||
const auto &ImportList = Data->ImportLists[ModId];
|
||||
const auto &ImportList = Data->ImportLists.lookup(ModId);
|
||||
const auto &ExportList = Data->ExportLists.lookup(ModId);
|
||||
const auto &ResolvedODR = Data->ResolvedODR.lookup(ModId);
|
||||
const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(ModId);
|
||||
|
@ -460,42 +460,7 @@ pub fn new_cyclic<F>(data_fn: F) -> Rc<T>
|
||||
where
|
||||
F: FnOnce(&Weak<T>) -> T,
|
||||
{
|
||||
// Construct the inner in the "uninitialized" state with a single
|
||||
// weak reference.
|
||||
let uninit_ptr: NonNull<_> = Box::leak(Box::new(RcBox {
|
||||
strong: Cell::new(0),
|
||||
weak: Cell::new(1),
|
||||
value: mem::MaybeUninit::<T>::uninit(),
|
||||
}))
|
||||
.into();
|
||||
|
||||
let init_ptr: NonNull<RcBox<T>> = uninit_ptr.cast();
|
||||
|
||||
let weak = Weak { ptr: init_ptr, alloc: Global };
|
||||
|
||||
// It's important we don't give up ownership of the weak pointer, or
|
||||
// else the memory might be freed by the time `data_fn` returns. If
|
||||
// we really wanted to pass ownership, we could create an additional
|
||||
// weak pointer for ourselves, but this would result in additional
|
||||
// updates to the weak reference count which might not be necessary
|
||||
// otherwise.
|
||||
let data = data_fn(&weak);
|
||||
|
||||
let strong = unsafe {
|
||||
let inner = init_ptr.as_ptr();
|
||||
ptr::write(ptr::addr_of_mut!((*inner).value), data);
|
||||
|
||||
let prev_value = (*inner).strong.get();
|
||||
debug_assert_eq!(prev_value, 0, "No prior strong references should exist");
|
||||
(*inner).strong.set(1);
|
||||
|
||||
Rc::from_inner(init_ptr)
|
||||
};
|
||||
|
||||
// Strong references should collectively own a shared weak reference,
|
||||
// so don't run the destructor for our old weak reference.
|
||||
mem::forget(weak);
|
||||
strong
|
||||
Self::new_cyclic_in(data_fn, Global)
|
||||
}
|
||||
|
||||
/// Constructs a new `Rc` with uninitialized contents.
|
||||
@ -762,6 +727,84 @@ pub fn new_zeroed_in(alloc: A) -> Rc<mem::MaybeUninit<T>, A> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a new `Rc<T, A>` in the given allocator while giving you a `Weak<T, A>` to the allocation,
|
||||
/// to allow you to construct a `T` which holds a weak pointer to itself.
|
||||
///
|
||||
/// Generally, a structure circularly referencing itself, either directly or
|
||||
/// indirectly, should not hold a strong reference to itself to prevent a memory leak.
|
||||
/// Using this function, you get access to the weak pointer during the
|
||||
/// initialization of `T`, before the `Rc<T, A>` is created, such that you can
|
||||
/// clone and store it inside the `T`.
|
||||
///
|
||||
/// `new_cyclic_in` first allocates the managed allocation for the `Rc<T, A>`,
|
||||
/// then calls your closure, giving it a `Weak<T, A>` to this allocation,
|
||||
/// and only afterwards completes the construction of the `Rc<T, A>` by placing
|
||||
/// the `T` returned from your closure into the allocation.
|
||||
///
|
||||
/// Since the new `Rc<T, A>` is not fully-constructed until `Rc<T, A>::new_cyclic_in`
|
||||
/// returns, calling [`upgrade`] on the weak reference inside your closure will
|
||||
/// fail and result in a `None` value.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If `data_fn` panics, the panic is propagated to the caller, and the
|
||||
/// temporary [`Weak<T, A>`] is dropped normally.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// See [`new_cyclic`].
|
||||
///
|
||||
/// [`new_cyclic`]: Rc::new_cyclic
|
||||
/// [`upgrade`]: Weak::upgrade
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
pub fn new_cyclic_in<F>(data_fn: F, alloc: A) -> Rc<T, A>
|
||||
where
|
||||
F: FnOnce(&Weak<T, A>) -> T,
|
||||
{
|
||||
// Construct the inner in the "uninitialized" state with a single
|
||||
// weak reference.
|
||||
let (uninit_raw_ptr, alloc) = Box::into_raw_with_allocator(Box::new_in(
|
||||
RcBox {
|
||||
strong: Cell::new(0),
|
||||
weak: Cell::new(1),
|
||||
value: mem::MaybeUninit::<T>::uninit(),
|
||||
},
|
||||
alloc,
|
||||
));
|
||||
let uninit_ptr: NonNull<_> = (unsafe { &mut *uninit_raw_ptr }).into();
|
||||
let init_ptr: NonNull<RcBox<T>> = uninit_ptr.cast();
|
||||
|
||||
let weak = Weak { ptr: init_ptr, alloc: alloc };
|
||||
|
||||
// It's important we don't give up ownership of the weak pointer, or
|
||||
// else the memory might be freed by the time `data_fn` returns. If
|
||||
// we really wanted to pass ownership, we could create an additional
|
||||
// weak pointer for ourselves, but this would result in additional
|
||||
// updates to the weak reference count which might not be necessary
|
||||
// otherwise.
|
||||
let data = data_fn(&weak);
|
||||
|
||||
let strong = unsafe {
|
||||
let inner = init_ptr.as_ptr();
|
||||
ptr::write(ptr::addr_of_mut!((*inner).value), data);
|
||||
|
||||
let prev_value = (*inner).strong.get();
|
||||
debug_assert_eq!(prev_value, 0, "No prior strong references should exist");
|
||||
(*inner).strong.set(1);
|
||||
|
||||
// Strong references should collectively own a shared weak reference,
|
||||
// so don't run the destructor for our old weak reference.
|
||||
// Calling into_raw_with_allocator has the double effect of giving us back the allocator,
|
||||
// and forgetting the weak reference.
|
||||
let alloc = weak.into_raw_with_allocator().1;
|
||||
|
||||
Rc::from_inner_in(init_ptr, alloc)
|
||||
};
|
||||
|
||||
strong
|
||||
}
|
||||
|
||||
/// Constructs a new `Rc<T>` in the provided allocator, returning an error if the allocation
|
||||
/// fails
|
||||
///
|
||||
|
@ -450,54 +450,7 @@ pub fn new_cyclic<F>(data_fn: F) -> Arc<T>
|
||||
where
|
||||
F: FnOnce(&Weak<T>) -> T,
|
||||
{
|
||||
// Construct the inner in the "uninitialized" state with a single
|
||||
// weak reference.
|
||||
let uninit_ptr: NonNull<_> = Box::leak(Box::new(ArcInner {
|
||||
strong: atomic::AtomicUsize::new(0),
|
||||
weak: atomic::AtomicUsize::new(1),
|
||||
data: mem::MaybeUninit::<T>::uninit(),
|
||||
}))
|
||||
.into();
|
||||
let init_ptr: NonNull<ArcInner<T>> = uninit_ptr.cast();
|
||||
|
||||
let weak = Weak { ptr: init_ptr, alloc: Global };
|
||||
|
||||
// It's important we don't give up ownership of the weak pointer, or
|
||||
// else the memory might be freed by the time `data_fn` returns. If
|
||||
// we really wanted to pass ownership, we could create an additional
|
||||
// weak pointer for ourselves, but this would result in additional
|
||||
// updates to the weak reference count which might not be necessary
|
||||
// otherwise.
|
||||
let data = data_fn(&weak);
|
||||
|
||||
// Now we can properly initialize the inner value and turn our weak
|
||||
// reference into a strong reference.
|
||||
let strong = unsafe {
|
||||
let inner = init_ptr.as_ptr();
|
||||
ptr::write(ptr::addr_of_mut!((*inner).data), data);
|
||||
|
||||
// The above write to the data field must be visible to any threads which
|
||||
// observe a non-zero strong count. Therefore we need at least "Release" ordering
|
||||
// in order to synchronize with the `compare_exchange_weak` in `Weak::upgrade`.
|
||||
//
|
||||
// "Acquire" ordering is not required. When considering the possible behaviours
|
||||
// of `data_fn` we only need to look at what it could do with a reference to a
|
||||
// non-upgradeable `Weak`:
|
||||
// - It can *clone* the `Weak`, increasing the weak reference count.
|
||||
// - It can drop those clones, decreasing the weak reference count (but never to zero).
|
||||
//
|
||||
// These side effects do not impact us in any way, and no other side effects are
|
||||
// possible with safe code alone.
|
||||
let prev_value = (*inner).strong.fetch_add(1, Release);
|
||||
debug_assert_eq!(prev_value, 0, "No prior strong references should exist");
|
||||
|
||||
Arc::from_inner(init_ptr)
|
||||
};
|
||||
|
||||
// Strong references should collectively own a shared weak reference,
|
||||
// so don't run the destructor for our old weak reference.
|
||||
mem::forget(weak);
|
||||
strong
|
||||
Self::new_cyclic_in(data_fn, Global)
|
||||
}
|
||||
|
||||
/// Constructs a new `Arc` with uninitialized contents.
|
||||
@ -781,6 +734,98 @@ pub fn new_zeroed_in(alloc: A) -> Arc<mem::MaybeUninit<T>, A> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a new `Arc<T, A>` in the given allocator while giving you a `Weak<T, A>` to the allocation,
|
||||
/// to allow you to construct a `T` which holds a weak pointer to itself.
|
||||
///
|
||||
/// Generally, a structure circularly referencing itself, either directly or
|
||||
/// indirectly, should not hold a strong reference to itself to prevent a memory leak.
|
||||
/// Using this function, you get access to the weak pointer during the
|
||||
/// initialization of `T`, before the `Arc<T, A>` is created, such that you can
|
||||
/// clone and store it inside the `T`.
|
||||
///
|
||||
/// `new_cyclic_in` first allocates the managed allocation for the `Arc<T, A>`,
|
||||
/// then calls your closure, giving it a `Weak<T, A>` to this allocation,
|
||||
/// and only afterwards completes the construction of the `Arc<T, A>` by placing
|
||||
/// the `T` returned from your closure into the allocation.
|
||||
///
|
||||
/// Since the new `Arc<T, A>` is not fully-constructed until `Arc<T, A>::new_cyclic_in`
|
||||
/// returns, calling [`upgrade`] on the weak reference inside your closure will
|
||||
/// fail and result in a `None` value.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If `data_fn` panics, the panic is propagated to the caller, and the
|
||||
/// temporary [`Weak<T>`] is dropped normally.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// See [`new_cyclic`]
|
||||
///
|
||||
/// [`new_cyclic`]: Arc::new_cyclic
|
||||
/// [`upgrade`]: Weak::upgrade
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
#[inline]
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
pub fn new_cyclic_in<F>(data_fn: F, alloc: A) -> Arc<T, A>
|
||||
where
|
||||
F: FnOnce(&Weak<T, A>) -> T,
|
||||
{
|
||||
// Construct the inner in the "uninitialized" state with a single
|
||||
// weak reference.
|
||||
let (uninit_raw_ptr, alloc) = Box::into_raw_with_allocator(Box::new_in(
|
||||
ArcInner {
|
||||
strong: atomic::AtomicUsize::new(0),
|
||||
weak: atomic::AtomicUsize::new(1),
|
||||
data: mem::MaybeUninit::<T>::uninit(),
|
||||
},
|
||||
alloc,
|
||||
));
|
||||
let uninit_ptr: NonNull<_> = (unsafe { &mut *uninit_raw_ptr }).into();
|
||||
let init_ptr: NonNull<ArcInner<T>> = uninit_ptr.cast();
|
||||
|
||||
let weak = Weak { ptr: init_ptr, alloc: alloc };
|
||||
|
||||
// It's important we don't give up ownership of the weak pointer, or
|
||||
// else the memory might be freed by the time `data_fn` returns. If
|
||||
// we really wanted to pass ownership, we could create an additional
|
||||
// weak pointer for ourselves, but this would result in additional
|
||||
// updates to the weak reference count which might not be necessary
|
||||
// otherwise.
|
||||
let data = data_fn(&weak);
|
||||
|
||||
// Now we can properly initialize the inner value and turn our weak
|
||||
// reference into a strong reference.
|
||||
let strong = unsafe {
|
||||
let inner = init_ptr.as_ptr();
|
||||
ptr::write(ptr::addr_of_mut!((*inner).data), data);
|
||||
|
||||
// The above write to the data field must be visible to any threads which
|
||||
// observe a non-zero strong count. Therefore we need at least "Release" ordering
|
||||
// in order to synchronize with the `compare_exchange_weak` in `Weak::upgrade`.
|
||||
//
|
||||
// "Acquire" ordering is not required. When considering the possible behaviours
|
||||
// of `data_fn` we only need to look at what it could do with a reference to a
|
||||
// non-upgradeable `Weak`:
|
||||
// - It can *clone* the `Weak`, increasing the weak reference count.
|
||||
// - It can drop those clones, decreasing the weak reference count (but never to zero).
|
||||
//
|
||||
// These side effects do not impact us in any way, and no other side effects are
|
||||
// possible with safe code alone.
|
||||
let prev_value = (*inner).strong.fetch_add(1, Release);
|
||||
debug_assert_eq!(prev_value, 0, "No prior strong references should exist");
|
||||
|
||||
// Strong references should collectively own a shared weak reference,
|
||||
// so don't run the destructor for our old weak reference.
|
||||
// Calling into_raw_with_allocator has the double effect of giving us back the allocator,
|
||||
// and forgetting the weak reference.
|
||||
let alloc = weak.into_raw_with_allocator().1;
|
||||
|
||||
Arc::from_inner_in(init_ptr, alloc)
|
||||
};
|
||||
|
||||
strong
|
||||
}
|
||||
|
||||
/// Constructs a new `Pin<Arc<T, A>>` in the provided allocator. If `T` does not implement `Unpin`,
|
||||
/// then `data` will be pinned in memory and unable to be moved.
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
|
@ -8,7 +8,8 @@ Environment (TEE) for Android.
|
||||
## Target maintainers
|
||||
|
||||
- Nicole LeGare (@randomPoison)
|
||||
- Stephen Crane (@rinon)
|
||||
- Andrei Homescu (@ahomescu)
|
||||
- Chris Wailes (chriswailes@google.com)
|
||||
- As a fallback trusty-dev-team@google.com can be contacted
|
||||
|
||||
## Requirements
|
||||
|
@ -13,7 +13,7 @@ jobs:
|
||||
name: Build the sysroots
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Build the sysroots
|
||||
run: |
|
||||
cargo install -f rustup-toolchain-install-master
|
||||
|
@ -39,22 +39,19 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "annotate-snippets"
|
||||
version = "0.9.2"
|
||||
version = "0.11.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccaf7e9dfbb6ab22c82e473cd1a8a7bd313c19a5b7e40970f3d89ef5a5c9e81e"
|
||||
checksum = "24e35ed54e5ea7997c14ed4c70ba043478db1112e98263b3b035907aa197d991"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"unicode-width",
|
||||
"yansi-term",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
name = "anstyle"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
@ -126,9 +123,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cargo_metadata"
|
||||
version = "0.15.4"
|
||||
version = "0.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a"
|
||||
checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037"
|
||||
dependencies = [
|
||||
"camino",
|
||||
"cargo-platform",
|
||||
@ -737,11 +734,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "prettydiff"
|
||||
version = "0.6.4"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ff1fec61082821f8236cf6c0c14e8172b62ce8a72a0eedc30d3b247bb68dc11"
|
||||
checksum = "abec3fb083c10660b3854367697da94c674e9e82aa7511014dc958beeb7215e9"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"owo-colors",
|
||||
"pad",
|
||||
]
|
||||
|
||||
@ -865,14 +862,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustfix"
|
||||
version = "0.6.1"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecd2853d9e26988467753bd9912c3a126f642d05d229a4b53f5752ee36c56481"
|
||||
checksum = "70f5b7fc8060f4f8373f9381a630304b42e1183535d9beb1d3f596b236c9106a"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -962,6 +959,16 @@ version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "spanned"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86af297923fbcfd107c20a189a6e9c872160df71a7190ae4a7a6c5dce4b2feb6"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"color-eyre",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.72"
|
||||
@ -1065,9 +1072,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
[[package]]
|
||||
name = "ui_test"
|
||||
version = "0.21.2"
|
||||
version = "0.26.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aaf4bf7c184b8dfc7a4d3b90df789b1eb992ee42811cd115f32a7a1eb781058d"
|
||||
checksum = "32ee4c40e5a5f9fa6864ff976473e5d6a6e9884b6ce68b40690d9f87e1994c83"
|
||||
dependencies = [
|
||||
"annotate-snippets",
|
||||
"anyhow",
|
||||
@ -1079,7 +1086,6 @@ dependencies = [
|
||||
"comma",
|
||||
"crossbeam-channel",
|
||||
"indicatif",
|
||||
"lazy_static",
|
||||
"levenshtein",
|
||||
"prettydiff",
|
||||
"regex",
|
||||
@ -1087,7 +1093,7 @@ dependencies = [
|
||||
"rustfix",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
"spanned",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1120,28 +1126,6 @@ version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
@ -1281,15 +1265,6 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "yansi-term"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
|
@ -49,7 +49,7 @@ windows-sys = { version = "0.52", features = [
|
||||
|
||||
[dev-dependencies]
|
||||
colored = "2"
|
||||
ui_test = "0.21.1"
|
||||
ui_test = "0.26.5"
|
||||
rustc_version = "0.4"
|
||||
regex = "1.5.5"
|
||||
tempfile = "3"
|
||||
|
@ -187,7 +187,7 @@ Here is an example job for GitHub Actions:
|
||||
name: "Miri"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install Miri
|
||||
run: |
|
||||
rustup toolchain install nightly --component miri
|
||||
@ -216,9 +216,9 @@ degree documented below):
|
||||
- For every other target with OS `linux`, `macos`, or `windows`, Miri should generally work, but we
|
||||
make no promises and we don't run tests for such targets.
|
||||
- We have unofficial support (not maintained by the Miri team itself) for some further operating systems.
|
||||
- `solaris` / `illumos`: maintained by @devnexen. Supports `std::{env, thread, sync}`, but not `std::fs`.
|
||||
- `freebsd`: **maintainer wanted**. Supports `std::env` and parts of `std::{thread, fs}`, but not `std::sync`.
|
||||
- `android`: **maintainer wanted**. Support very incomplete, but a basic "hello world" works.
|
||||
- `solaris` / `illumos`: maintained by @devnexen. Support very incomplete, but a basic "hello world" works.
|
||||
- `wasm`: **maintainer wanted**. Support very incomplete, not even standard output works, but an empty `main` function works.
|
||||
- For targets on other operating systems, Miri might fail before even reaching the `main` function.
|
||||
|
||||
|
@ -26,7 +26,7 @@ time ./miri install
|
||||
# We enable all features to make sure the Stacked Borrows consistency check runs.
|
||||
echo "Building debug version of Miri"
|
||||
export CARGO_EXTRA_FLAGS="$CARGO_EXTRA_FLAGS --all-features"
|
||||
time ./miri build --all-targets # the build that all the `./miri test` below will use
|
||||
time ./miri build # the build that all the `./miri test` below will use
|
||||
|
||||
endgroup
|
||||
|
||||
@ -66,7 +66,7 @@ function run_tests {
|
||||
time MIRIFLAGS="${MIRIFLAGS-} -O -Zmir-opt-level=4 -Cdebug-assertions=yes" MIRI_SKIP_UI_CHECKS=1 ./miri test $TARGET_FLAG tests/{pass,panic}
|
||||
fi
|
||||
if [ -n "${MANY_SEEDS-}" ]; then
|
||||
# Also run some many-seeds tests.
|
||||
# Also run some many-seeds tests. (Also tests `./miri run`.)
|
||||
time for FILE in tests/many-seeds/*.rs; do
|
||||
./miri run "--many-seeds=0..$MANY_SEEDS" $TARGET_FLAG "$FILE"
|
||||
done
|
||||
@ -75,6 +75,8 @@ function run_tests {
|
||||
# Check that the benchmarks build and run, but only once.
|
||||
time HYPERFINE="hyperfine -w0 -r1" ./miri bench $TARGET_FLAG
|
||||
fi
|
||||
# Smoke-test `./miri run --dep`.
|
||||
./miri run $TARGET_FLAG --dep tests/pass-dep/getrandom.rs
|
||||
|
||||
## test-cargo-miri
|
||||
# On Windows, there is always "python", not "python3" or "python2".
|
||||
@ -148,11 +150,11 @@ case $HOST_TARGET in
|
||||
# Partially supported targets (tier 2)
|
||||
BASIC="empty_main integer vec string btreemap hello hashmap heap_alloc align" # ensures we have the basics: stdout/stderr, system allocator, randomness (for HashMap initialization)
|
||||
UNIX="panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there
|
||||
TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname libc-time fs
|
||||
TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname libc-time fs
|
||||
TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX threadname pthread-sync available-parallelism libc-time tls
|
||||
TEST_TARGET=x86_64-pc-solaris run_tests_minimal $BASIC $UNIX threadname pthread-sync available-parallelism libc-time tls
|
||||
TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX
|
||||
TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname pthread time fs
|
||||
TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname pthread time fs
|
||||
TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX thread sync available-parallelism time tls
|
||||
TEST_TARGET=x86_64-pc-solaris run_tests_minimal $BASIC $UNIX thread sync available-parallelism time tls
|
||||
TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX pthread --skip threadname --skip pthread_cond_timedwait
|
||||
TEST_TARGET=wasm32-wasip2 run_tests_minimal empty_main wasm heap_alloc libc-mem
|
||||
TEST_TARGET=wasm32-unknown-unknown run_tests_minimal empty_main wasm
|
||||
TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std
|
||||
|
@ -61,9 +61,9 @@ checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.8"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
|
||||
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
@ -98,6 +98,12 @@ dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.153"
|
||||
@ -117,9 +123,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.13"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
|
||||
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "miri-script"
|
||||
@ -131,6 +143,7 @@ dependencies = [
|
||||
"itertools",
|
||||
"path_macro",
|
||||
"rustc_version",
|
||||
"serde_json",
|
||||
"shell-words",
|
||||
"walkdir",
|
||||
"which",
|
||||
@ -204,9 +217,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.31"
|
||||
version = "0.38.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
|
||||
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
|
||||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
"errno",
|
||||
@ -215,6 +228,12 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
@ -230,6 +249,38 @@ version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.210"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.210"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.128"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shell-words"
|
||||
version = "1.1.0"
|
||||
@ -347,7 +398,7 @@ version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.3",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -367,17 +418,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.3"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.3",
|
||||
"windows_aarch64_msvc 0.52.3",
|
||||
"windows_i686_gnu 0.52.3",
|
||||
"windows_i686_msvc 0.52.3",
|
||||
"windows_x86_64_gnu 0.52.3",
|
||||
"windows_x86_64_gnullvm 0.52.3",
|
||||
"windows_x86_64_msvc 0.52.3",
|
||||
"windows_aarch64_gnullvm 0.52.6",
|
||||
"windows_aarch64_msvc 0.52.6",
|
||||
"windows_i686_gnu 0.52.6",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc 0.52.6",
|
||||
"windows_x86_64_gnu 0.52.6",
|
||||
"windows_x86_64_gnullvm 0.52.6",
|
||||
"windows_x86_64_msvc 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -388,9 +440,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.3"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
@ -400,9 +452,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.3"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
@ -412,9 +464,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.3"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
@ -424,9 +482,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.3"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
@ -436,9 +494,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.3"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
@ -448,9 +506,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.3"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
@ -460,9 +518,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.3"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "xshell"
|
||||
|
@ -23,3 +23,4 @@ xshell = "0.2.6"
|
||||
rustc_version = "0.4"
|
||||
dunce = "1.0.4"
|
||||
directories = "5"
|
||||
serde_json = "1"
|
||||
|
@ -494,23 +494,25 @@ fn run(
|
||||
flags: Vec<String>,
|
||||
) -> Result<()> {
|
||||
let mut e = MiriEnv::new()?;
|
||||
|
||||
// Preparation: get a sysroot, and get the miri binary.
|
||||
let miri_sysroot = e.build_miri_sysroot(/* quiet */ !verbose, target.as_deref())?;
|
||||
let miri_bin =
|
||||
e.build_get_binary(".").context("failed to get filename of miri executable")?;
|
||||
|
||||
// More flags that we will pass before `flags`
|
||||
// (because `flags` may contain `--`).
|
||||
let mut early_flags = Vec::<OsString>::new();
|
||||
|
||||
// Add target, edition to flags.
|
||||
if let Some(target) = &target {
|
||||
early_flags.push("--target".into());
|
||||
early_flags.push(target.into());
|
||||
}
|
||||
if verbose {
|
||||
early_flags.push("--verbose".into());
|
||||
// In `dep` mode, the target is already passed via `MIRI_TEST_TARGET`
|
||||
if !dep {
|
||||
if let Some(target) = &target {
|
||||
early_flags.push("--target".into());
|
||||
early_flags.push(target.into());
|
||||
}
|
||||
}
|
||||
early_flags.push("--edition".into());
|
||||
early_flags.push(edition.as_deref().unwrap_or("2021").into());
|
||||
|
||||
// Prepare a sysroot, add it to the flags. (Also builds cargo-miri, which we need.)
|
||||
let miri_sysroot = e.build_miri_sysroot(/* quiet */ !verbose, target.as_deref())?;
|
||||
early_flags.push("--sysroot".into());
|
||||
early_flags.push(miri_sysroot.into());
|
||||
|
||||
@ -523,18 +525,19 @@ fn run(
|
||||
let run_miri = |e: &MiriEnv, seed_flag: Option<String>| -> Result<()> {
|
||||
// The basic command that executes the Miri driver.
|
||||
let mut cmd = if dep {
|
||||
// We invoke the test suite as that has all the logic for running with dependencies.
|
||||
e.cargo_cmd(".", "test")
|
||||
.args(&["--test", "ui"])
|
||||
.args(quiet_flag)
|
||||
.arg("--")
|
||||
.args(&["--miri-run-dep-mode"])
|
||||
} else {
|
||||
e.cargo_cmd(".", "run").args(quiet_flag).arg("--")
|
||||
cmd!(e.sh, "{miri_bin}")
|
||||
};
|
||||
cmd.set_quiet(!verbose);
|
||||
// Add Miri flags
|
||||
let mut cmd = cmd.args(&miri_flags).args(&seed_flag).args(&early_flags).args(&flags);
|
||||
// For `--dep` we also need to set the env var.
|
||||
// For `--dep` we also need to set the target in the env var.
|
||||
if dep {
|
||||
if let Some(target) = &target {
|
||||
cmd = cmd.env("MIRI_TEST_TARGET", target);
|
||||
|
@ -1,10 +1,11 @@
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::io::BufRead;
|
||||
use std::ops::Range;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
|
||||
use std::thread;
|
||||
use std::{env, iter, thread};
|
||||
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use dunce::canonicalize;
|
||||
use path_macro::path;
|
||||
use xshell::{cmd, Cmd, Shell};
|
||||
@ -73,8 +74,11 @@ pub fn new() -> Result<Self> {
|
||||
let rustflags = {
|
||||
let mut flags = OsString::new();
|
||||
// We set the rpath so that Miri finds the private rustc libraries it needs.
|
||||
flags.push("-C link-args=-Wl,-rpath,");
|
||||
flags.push(libdir);
|
||||
// (This only makes sense on Unix.)
|
||||
if cfg!(unix) {
|
||||
flags.push("-C link-args=-Wl,-rpath,");
|
||||
flags.push(&libdir);
|
||||
}
|
||||
// Enable rustc-specific lints (ignored without `-Zunstable-options`).
|
||||
flags.push(
|
||||
" -Zunstable-options -Wrustc::internal -Wrust_2018_idioms -Wunused_lifetimes",
|
||||
@ -88,6 +92,14 @@ pub fn new() -> Result<Self> {
|
||||
};
|
||||
sh.set_var("RUSTFLAGS", rustflags);
|
||||
|
||||
// On Windows, the `-Wl,-rpath,` above does not help. Instead we add the libdir to the PATH,
|
||||
// so that Windows can find the DLLs.
|
||||
if cfg!(windows) {
|
||||
let old_path = sh.var("PATH")?;
|
||||
let new_path = env::join_paths(iter::once(libdir).chain(env::split_paths(&old_path)))?;
|
||||
sh.set_var("PATH", new_path);
|
||||
}
|
||||
|
||||
// Get extra flags for cargo.
|
||||
let cargo_extra_flags = std::env::var("CARGO_EXTRA_FLAGS").unwrap_or_default();
|
||||
let cargo_extra_flags = flagsplit(&cargo_extra_flags);
|
||||
@ -126,21 +138,40 @@ pub fn install_to_sysroot(
|
||||
|
||||
pub fn build(&self, crate_dir: impl AsRef<OsStr>, args: &[String], quiet: bool) -> Result<()> {
|
||||
let quiet_flag = if quiet { Some("--quiet") } else { None };
|
||||
// We build the tests as well, (a) to avoid having rebuilds when building the tests later
|
||||
// and (b) to have more parallelism during the build of Miri and its tests.
|
||||
// This means `./miri run` without `--dep` will build Miri twice (for the sysroot with
|
||||
// dev-dependencies, and then for running without dev-dependencies), but the way more common
|
||||
// `./miri test` will avoid building Miri twice.
|
||||
let mut cmd = self
|
||||
.cargo_cmd(crate_dir, "build")
|
||||
.args(&["--bins", "--tests"])
|
||||
.args(quiet_flag)
|
||||
.args(args);
|
||||
// We build all targets, since building *just* the bin target doesnot include
|
||||
// `dev-dependencies` and that changes feature resolution. This also gets us more
|
||||
// parallelism in `./miri test` as we build Miri and its tests together.
|
||||
let mut cmd =
|
||||
self.cargo_cmd(crate_dir, "build").args(&["--all-targets"]).args(quiet_flag).args(args);
|
||||
cmd.set_quiet(quiet);
|
||||
cmd.run()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the path to the main crate binary. Assumes that `build` has been called before.
|
||||
pub fn build_get_binary(&self, crate_dir: impl AsRef<OsStr>) -> Result<PathBuf> {
|
||||
let cmd =
|
||||
self.cargo_cmd(crate_dir, "build").args(&["--all-targets", "--message-format=json"]);
|
||||
let output = cmd.output()?;
|
||||
let mut bin = None;
|
||||
for line in output.stdout.lines() {
|
||||
let line = line?;
|
||||
if line.starts_with("{") {
|
||||
let json: serde_json::Value = serde_json::from_str(&line)?;
|
||||
if json["reason"] == "compiler-artifact"
|
||||
&& !json["profile"]["test"].as_bool().unwrap()
|
||||
&& !json["executable"].is_null()
|
||||
{
|
||||
if bin.is_some() {
|
||||
bail!("found two binaries in cargo output");
|
||||
}
|
||||
bin = Some(PathBuf::from(json["executable"].as_str().unwrap()))
|
||||
}
|
||||
}
|
||||
}
|
||||
bin.ok_or_else(|| anyhow!("found no binary in cargo output"))
|
||||
}
|
||||
|
||||
pub fn check(&self, crate_dir: impl AsRef<OsStr>, args: &[String]) -> Result<()> {
|
||||
self.cargo_cmd(crate_dir, "check").arg("--all-targets").args(args).run()?;
|
||||
Ok(())
|
||||
|
@ -1 +1 @@
|
||||
54fdef7799d9ff9470bb5cabd29fde9471a99eaa
|
||||
e2dc1a1c0f97a90319181a721ab317210307617a
|
||||
|
@ -1165,7 +1165,7 @@ pub fn local_write(&self, local: mir::Local, storage_live: bool, machine: &MiriM
|
||||
} else {
|
||||
// This can fail to exist if `race_detecting` was false when the allocation
|
||||
// occurred, in which case we can backdate this to the beginning of time.
|
||||
let clocks = clocks.entry(local).or_insert_with(Default::default);
|
||||
let clocks = clocks.entry(local).or_default();
|
||||
clocks.write = thread_clocks.clock[index];
|
||||
clocks.write_type = NaWriteType::Write;
|
||||
}
|
||||
@ -1186,7 +1186,7 @@ pub fn local_read(&self, local: mir::Local, machine: &MiriMachine<'_>) {
|
||||
// This can fail to exist if `race_detecting` was false when the allocation
|
||||
// occurred, in which case we can backdate this to the beginning of time.
|
||||
let mut clocks = self.local_clocks.borrow_mut();
|
||||
let clocks = clocks.entry(local).or_insert_with(Default::default);
|
||||
let clocks = clocks.entry(local).or_default();
|
||||
clocks.read = thread_clocks.clock[index];
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use rustc_index::Idx;
|
||||
use rustc_middle::ty::layout::TyAndLayout;
|
||||
|
||||
use super::sync::EvalContextExtPriv as _;
|
||||
use super::vector_clock::VClock;
|
||||
@ -30,14 +29,12 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
|
||||
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
fn init_once_get_or_create_id(
|
||||
&mut self,
|
||||
lock_op: &OpTy<'tcx>,
|
||||
lock_layout: TyAndLayout<'tcx>,
|
||||
lock: &MPlaceTy<'tcx>,
|
||||
offset: u64,
|
||||
) -> InterpResult<'tcx, InitOnceId> {
|
||||
let this = self.eval_context_mut();
|
||||
this.get_or_create_id(
|
||||
lock_op,
|
||||
lock_layout,
|
||||
lock,
|
||||
offset,
|
||||
|ecx| &mut ecx.machine.sync.init_onces,
|
||||
|_| Ok(Default::default()),
|
||||
|
@ -1,10 +1,11 @@
|
||||
use std::any::Any;
|
||||
use std::collections::{hash_map::Entry, VecDeque};
|
||||
use std::ops::Not;
|
||||
use std::time::Duration;
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_index::{Idx, IndexVec};
|
||||
use rustc_middle::ty::layout::TyAndLayout;
|
||||
use rustc_target::abi::Size;
|
||||
|
||||
use super::init_once::InitOnce;
|
||||
use super::vector_clock::VClock;
|
||||
@ -66,27 +67,6 @@ pub fn to_u32_scalar(&self) -> Scalar {
|
||||
|
||||
declare_id!(MutexId);
|
||||
|
||||
/// The mutex kind.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[non_exhaustive]
|
||||
pub enum MutexKind {
|
||||
Invalid,
|
||||
Normal,
|
||||
Default,
|
||||
Recursive,
|
||||
ErrorCheck,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// Additional data that may be used by shim implementations.
|
||||
pub struct AdditionalMutexData {
|
||||
/// The mutex kind, used by some mutex implementations like pthreads mutexes.
|
||||
pub kind: MutexKind,
|
||||
|
||||
/// The address of the mutex.
|
||||
pub address: u64,
|
||||
}
|
||||
|
||||
/// The mutex state.
|
||||
#[derive(Default, Debug)]
|
||||
struct Mutex {
|
||||
@ -100,7 +80,7 @@ struct Mutex {
|
||||
clock: VClock,
|
||||
|
||||
/// Additional data that can be set by shim implementations.
|
||||
data: Option<AdditionalMutexData>,
|
||||
data: Option<Box<dyn Any>>,
|
||||
}
|
||||
|
||||
declare_id!(RwLockId);
|
||||
@ -137,6 +117,9 @@ struct RwLock {
|
||||
/// locks.
|
||||
/// This is only relevant when there is an active reader.
|
||||
clock_current_readers: VClock,
|
||||
|
||||
/// Additional data that can be set by shim implementations.
|
||||
data: Option<Box<dyn Any>>,
|
||||
}
|
||||
|
||||
declare_id!(CondvarId);
|
||||
@ -151,6 +134,9 @@ struct Condvar {
|
||||
/// Contains the clock of the last thread to
|
||||
/// perform a condvar-signal.
|
||||
clock: VClock,
|
||||
|
||||
/// Additional data that can be set by shim implementations.
|
||||
data: Option<Box<dyn Any>>,
|
||||
}
|
||||
|
||||
/// The futex state.
|
||||
@ -196,21 +182,21 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
#[inline]
|
||||
fn get_or_create_id<Id: SyncId + Idx, T>(
|
||||
&mut self,
|
||||
lock_op: &OpTy<'tcx>,
|
||||
lock_layout: TyAndLayout<'tcx>,
|
||||
lock: &MPlaceTy<'tcx>,
|
||||
offset: u64,
|
||||
get_objs: impl for<'a> Fn(&'a mut MiriInterpCx<'tcx>) -> &'a mut IndexVec<Id, T>,
|
||||
create_obj: impl for<'a> FnOnce(&'a mut MiriInterpCx<'tcx>) -> InterpResult<'tcx, T>,
|
||||
) -> InterpResult<'tcx, Option<Id>> {
|
||||
let this = self.eval_context_mut();
|
||||
let value_place =
|
||||
this.deref_pointer_and_offset(lock_op, offset, lock_layout, this.machine.layouts.u32)?;
|
||||
let offset = Size::from_bytes(offset);
|
||||
assert!(lock.layout.size >= offset + this.machine.layouts.u32.size);
|
||||
let id_place = lock.offset(offset, this.machine.layouts.u32, this)?;
|
||||
let next_index = get_objs(this).next_index();
|
||||
|
||||
// Since we are lazy, this update has to be atomic.
|
||||
let (old, success) = this
|
||||
.atomic_compare_exchange_scalar(
|
||||
&value_place,
|
||||
&id_place,
|
||||
&ImmTy::from_uint(0u32, this.machine.layouts.u32),
|
||||
Scalar::from_u32(next_index.to_u32()),
|
||||
AtomicRwOrd::Relaxed, // deliberately *no* synchronization
|
||||
@ -248,18 +234,18 @@ fn get_or_create_id<Id: SyncId + Idx, T>(
|
||||
/// - `obj` must be the new sync object.
|
||||
fn create_id<Id: SyncId + Idx, T>(
|
||||
&mut self,
|
||||
lock_op: &OpTy<'tcx>,
|
||||
lock_layout: TyAndLayout<'tcx>,
|
||||
lock: &MPlaceTy<'tcx>,
|
||||
offset: u64,
|
||||
get_objs: impl for<'a> Fn(&'a mut MiriInterpCx<'tcx>) -> &'a mut IndexVec<Id, T>,
|
||||
obj: T,
|
||||
) -> InterpResult<'tcx, Id> {
|
||||
let this = self.eval_context_mut();
|
||||
let value_place =
|
||||
this.deref_pointer_and_offset(lock_op, offset, lock_layout, this.machine.layouts.u32)?;
|
||||
let offset = Size::from_bytes(offset);
|
||||
assert!(lock.layout.size >= offset + this.machine.layouts.u32.size);
|
||||
let id_place = lock.offset(offset, this.machine.layouts.u32, this)?;
|
||||
|
||||
let new_index = get_objs(this).push(obj);
|
||||
this.write_scalar(Scalar::from_u32(new_index.to_u32()), &value_place)?;
|
||||
this.write_scalar(Scalar::from_u32(new_index.to_u32()), &id_place)?;
|
||||
Ok(new_index)
|
||||
}
|
||||
|
||||
@ -292,15 +278,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
/// Eagerly create and initialize a new mutex.
|
||||
fn mutex_create(
|
||||
&mut self,
|
||||
lock_op: &OpTy<'tcx>,
|
||||
lock_layout: TyAndLayout<'tcx>,
|
||||
lock: &MPlaceTy<'tcx>,
|
||||
offset: u64,
|
||||
data: Option<AdditionalMutexData>,
|
||||
data: Option<Box<dyn Any>>,
|
||||
) -> InterpResult<'tcx, MutexId> {
|
||||
let this = self.eval_context_mut();
|
||||
this.create_id(
|
||||
lock_op,
|
||||
lock_layout,
|
||||
lock,
|
||||
offset,
|
||||
|ecx| &mut ecx.machine.sync.mutexes,
|
||||
Mutex { data, ..Default::default() },
|
||||
@ -311,17 +295,15 @@ fn mutex_create(
|
||||
/// `initialize_data` must return any additional data that a user wants to associate with the mutex.
|
||||
fn mutex_get_or_create_id(
|
||||
&mut self,
|
||||
lock_op: &OpTy<'tcx>,
|
||||
lock_layout: TyAndLayout<'tcx>,
|
||||
lock: &MPlaceTy<'tcx>,
|
||||
offset: u64,
|
||||
initialize_data: impl for<'a> FnOnce(
|
||||
&'a mut MiriInterpCx<'tcx>,
|
||||
) -> InterpResult<'tcx, Option<AdditionalMutexData>>,
|
||||
) -> InterpResult<'tcx, Option<Box<dyn Any>>>,
|
||||
) -> InterpResult<'tcx, MutexId> {
|
||||
let this = self.eval_context_mut();
|
||||
this.get_or_create_id(
|
||||
lock_op,
|
||||
lock_layout,
|
||||
lock,
|
||||
offset,
|
||||
|ecx| &mut ecx.machine.sync.mutexes,
|
||||
|ecx| initialize_data(ecx).map(|data| Mutex { data, ..Default::default() }),
|
||||
@ -330,48 +312,84 @@ fn mutex_get_or_create_id(
|
||||
}
|
||||
|
||||
/// Retrieve the additional data stored for a mutex.
|
||||
fn mutex_get_data<'a>(&'a mut self, id: MutexId) -> Option<&'a AdditionalMutexData>
|
||||
fn mutex_get_data<'a, T: 'static>(&'a mut self, id: MutexId) -> Option<&'a T>
|
||||
where
|
||||
'tcx: 'a,
|
||||
{
|
||||
let this = self.eval_context_ref();
|
||||
this.machine.sync.mutexes[id].data.as_ref()
|
||||
this.machine.sync.mutexes[id].data.as_deref().and_then(|p| p.downcast_ref::<T>())
|
||||
}
|
||||
|
||||
fn rwlock_get_or_create_id(
|
||||
&mut self,
|
||||
lock_op: &OpTy<'tcx>,
|
||||
lock_layout: TyAndLayout<'tcx>,
|
||||
lock: &MPlaceTy<'tcx>,
|
||||
offset: u64,
|
||||
initialize_data: impl for<'a> FnOnce(
|
||||
&'a mut MiriInterpCx<'tcx>,
|
||||
) -> InterpResult<'tcx, Option<Box<dyn Any>>>,
|
||||
) -> InterpResult<'tcx, RwLockId> {
|
||||
let this = self.eval_context_mut();
|
||||
this.get_or_create_id(
|
||||
lock_op,
|
||||
lock_layout,
|
||||
lock,
|
||||
offset,
|
||||
|ecx| &mut ecx.machine.sync.rwlocks,
|
||||
|_| Ok(Default::default()),
|
||||
|ecx| initialize_data(ecx).map(|data| RwLock { data, ..Default::default() }),
|
||||
)?
|
||||
.ok_or_else(|| err_ub_format!("rwlock has invalid ID").into())
|
||||
}
|
||||
|
||||
/// Retrieve the additional data stored for a rwlock.
|
||||
fn rwlock_get_data<'a, T: 'static>(&'a mut self, id: RwLockId) -> Option<&'a T>
|
||||
where
|
||||
'tcx: 'a,
|
||||
{
|
||||
let this = self.eval_context_ref();
|
||||
this.machine.sync.rwlocks[id].data.as_deref().and_then(|p| p.downcast_ref::<T>())
|
||||
}
|
||||
|
||||
/// Eagerly create and initialize a new condvar.
|
||||
fn condvar_create(
|
||||
&mut self,
|
||||
condvar: &MPlaceTy<'tcx>,
|
||||
offset: u64,
|
||||
data: Option<Box<dyn Any>>,
|
||||
) -> InterpResult<'tcx, CondvarId> {
|
||||
let this = self.eval_context_mut();
|
||||
this.create_id(
|
||||
condvar,
|
||||
offset,
|
||||
|ecx| &mut ecx.machine.sync.condvars,
|
||||
Condvar { data, ..Default::default() },
|
||||
)
|
||||
}
|
||||
|
||||
fn condvar_get_or_create_id(
|
||||
&mut self,
|
||||
lock_op: &OpTy<'tcx>,
|
||||
lock_layout: TyAndLayout<'tcx>,
|
||||
lock: &MPlaceTy<'tcx>,
|
||||
offset: u64,
|
||||
initialize_data: impl for<'a> FnOnce(
|
||||
&'a mut MiriInterpCx<'tcx>,
|
||||
) -> InterpResult<'tcx, Option<Box<dyn Any>>>,
|
||||
) -> InterpResult<'tcx, CondvarId> {
|
||||
let this = self.eval_context_mut();
|
||||
this.get_or_create_id(
|
||||
lock_op,
|
||||
lock_layout,
|
||||
lock,
|
||||
offset,
|
||||
|ecx| &mut ecx.machine.sync.condvars,
|
||||
|_| Ok(Default::default()),
|
||||
|ecx| initialize_data(ecx).map(|data| Condvar { data, ..Default::default() }),
|
||||
)?
|
||||
.ok_or_else(|| err_ub_format!("condvar has invalid ID").into())
|
||||
}
|
||||
|
||||
/// Retrieve the additional data stored for a condvar.
|
||||
fn condvar_get_data<'a, T: 'static>(&'a mut self, id: CondvarId) -> Option<&'a T>
|
||||
where
|
||||
'tcx: 'a,
|
||||
{
|
||||
let this = self.eval_context_ref();
|
||||
this.machine.sync.condvars[id].data.as_deref().and_then(|p| p.downcast_ref::<T>())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Get the id of the thread that currently owns this lock.
|
||||
fn mutex_get_owner(&mut self, id: MutexId) -> ThreadId {
|
||||
|
@ -133,10 +133,7 @@
|
||||
cpu_affinity::MAX_CPUS,
|
||||
data_race::{AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, EvalContextExt as _},
|
||||
init_once::{EvalContextExt as _, InitOnceId},
|
||||
sync::{
|
||||
AdditionalMutexData, CondvarId, EvalContextExt as _, MutexId, MutexKind, RwLockId,
|
||||
SynchronizationObjects,
|
||||
},
|
||||
sync::{CondvarId, EvalContextExt as _, MutexId, RwLockId, SynchronizationObjects},
|
||||
thread::{
|
||||
BlockReason, EvalContextExt as _, StackEmptyCallback, ThreadId, ThreadManager,
|
||||
TimeoutAnchor, TimeoutClock, UnblockCallback,
|
||||
|
@ -602,12 +602,8 @@ pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx>) -> Self {
|
||||
let layouts =
|
||||
PrimitiveLayouts::new(layout_cx).expect("Couldn't get layouts of primitive types");
|
||||
let profiler = config.measureme_out.as_ref().map(|out| {
|
||||
let crate_name = tcx
|
||||
.sess
|
||||
.opts
|
||||
.crate_name
|
||||
.clone()
|
||||
.unwrap_or_else(|| "unknown-crate".to_string());
|
||||
let crate_name =
|
||||
tcx.sess.opts.crate_name.clone().unwrap_or_else(|| "unknown-crate".to_string());
|
||||
let pid = process::id();
|
||||
// We adopt the same naming scheme for the profiler output that rustc uses. In rustc,
|
||||
// the PID is padded so that the nondeterministic value of the PID does not spread
|
||||
|
@ -21,7 +21,7 @@ pub(crate) enum FlockOp {
|
||||
Unlock,
|
||||
}
|
||||
|
||||
/// Represents an open file descriptor.
|
||||
/// Represents an open file description.
|
||||
pub trait FileDescription: std::fmt::Debug + Any {
|
||||
fn name(&self) -> &'static str;
|
||||
|
||||
@ -303,7 +303,7 @@ pub struct FdTable {
|
||||
|
||||
impl VisitProvenance for FdTable {
|
||||
fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
|
||||
// All our FileDescriptor do not have any tags.
|
||||
// All our FileDescription instances do not have any tags.
|
||||
}
|
||||
}
|
||||
|
||||
@ -337,18 +337,18 @@ pub fn insert_new(&mut self, fd: impl FileDescription) -> i32 {
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, fd_ref: FileDescriptionRef) -> i32 {
|
||||
self.insert_ref_with_min_fd(fd_ref, 0)
|
||||
self.insert_with_min_num(fd_ref, 0)
|
||||
}
|
||||
|
||||
/// Insert a file description, giving it a file descriptor that is at least `min_fd`.
|
||||
fn insert_ref_with_min_fd(&mut self, file_handle: FileDescriptionRef, min_fd: i32) -> i32 {
|
||||
/// Insert a file description, giving it a file descriptor that is at least `min_fd_num`.
|
||||
fn insert_with_min_num(&mut self, file_handle: FileDescriptionRef, min_fd_num: i32) -> i32 {
|
||||
// Find the lowest unused FD, starting from min_fd. If the first such unused FD is in
|
||||
// between used FDs, the find_map combinator will return it. If the first such unused FD
|
||||
// is after all other used FDs, the find_map combinator will return None, and we will use
|
||||
// the FD following the greatest FD thus far.
|
||||
let candidate_new_fd =
|
||||
self.fds.range(min_fd..).zip(min_fd..).find_map(|((fd, _fh), counter)| {
|
||||
if *fd != counter {
|
||||
self.fds.range(min_fd_num..).zip(min_fd_num..).find_map(|((fd_num, _fd), counter)| {
|
||||
if *fd_num != counter {
|
||||
// There was a gap in the fds stored, return the first unused one
|
||||
// (note that this relies on BTreeMap iterating in key order)
|
||||
Some(counter)
|
||||
@ -357,61 +357,61 @@ fn insert_ref_with_min_fd(&mut self, file_handle: FileDescriptionRef, min_fd: i3
|
||||
None
|
||||
}
|
||||
});
|
||||
let new_fd = candidate_new_fd.unwrap_or_else(|| {
|
||||
let new_fd_num = candidate_new_fd.unwrap_or_else(|| {
|
||||
// find_map ran out of BTreeMap entries before finding a free fd, use one plus the
|
||||
// maximum fd in the map
|
||||
self.fds.last_key_value().map(|(fd, _)| fd.strict_add(1)).unwrap_or(min_fd)
|
||||
self.fds.last_key_value().map(|(fd_num, _)| fd_num.strict_add(1)).unwrap_or(min_fd_num)
|
||||
});
|
||||
|
||||
self.fds.try_insert(new_fd, file_handle).unwrap();
|
||||
new_fd
|
||||
self.fds.try_insert(new_fd_num, file_handle).unwrap();
|
||||
new_fd_num
|
||||
}
|
||||
|
||||
pub fn get(&self, fd: i32) -> Option<FileDescriptionRef> {
|
||||
let fd = self.fds.get(&fd)?;
|
||||
pub fn get(&self, fd_num: i32) -> Option<FileDescriptionRef> {
|
||||
let fd = self.fds.get(&fd_num)?;
|
||||
Some(fd.clone())
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, fd: i32) -> Option<FileDescriptionRef> {
|
||||
self.fds.remove(&fd)
|
||||
pub fn remove(&mut self, fd_num: i32) -> Option<FileDescriptionRef> {
|
||||
self.fds.remove(&fd_num)
|
||||
}
|
||||
|
||||
pub fn is_fd(&self, fd: i32) -> bool {
|
||||
self.fds.contains_key(&fd)
|
||||
pub fn is_fd_num(&self, fd_num: i32) -> bool {
|
||||
self.fds.contains_key(&fd_num)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
|
||||
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
fn dup(&mut self, old_fd: i32) -> InterpResult<'tcx, Scalar> {
|
||||
fn dup(&mut self, old_fd_num: i32) -> InterpResult<'tcx, Scalar> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
let Some(dup_fd) = this.machine.fds.get(old_fd) else {
|
||||
let Some(fd) = this.machine.fds.get(old_fd_num) else {
|
||||
return Ok(Scalar::from_i32(this.fd_not_found()?));
|
||||
};
|
||||
Ok(Scalar::from_i32(this.machine.fds.insert_ref_with_min_fd(dup_fd, 0)))
|
||||
Ok(Scalar::from_i32(this.machine.fds.insert(fd)))
|
||||
}
|
||||
|
||||
fn dup2(&mut self, old_fd: i32, new_fd: i32) -> InterpResult<'tcx, Scalar> {
|
||||
fn dup2(&mut self, old_fd_num: i32, new_fd_num: i32) -> InterpResult<'tcx, Scalar> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
let Some(dup_fd) = this.machine.fds.get(old_fd) else {
|
||||
let Some(fd) = this.machine.fds.get(old_fd_num) else {
|
||||
return Ok(Scalar::from_i32(this.fd_not_found()?));
|
||||
};
|
||||
if new_fd != old_fd {
|
||||
if new_fd_num != old_fd_num {
|
||||
// Close new_fd if it is previously opened.
|
||||
// If old_fd and new_fd point to the same description, then `dup_fd` ensures we keep the underlying file description alive.
|
||||
if let Some(file_description) = this.machine.fds.fds.insert(new_fd, dup_fd) {
|
||||
if let Some(old_new_fd) = this.machine.fds.fds.insert(new_fd_num, fd) {
|
||||
// Ignore close error (not interpreter's) according to dup2() doc.
|
||||
file_description.close(this.machine.communicate(), this)?.ok();
|
||||
old_new_fd.close(this.machine.communicate(), this)?.ok();
|
||||
}
|
||||
}
|
||||
Ok(Scalar::from_i32(new_fd))
|
||||
Ok(Scalar::from_i32(new_fd_num))
|
||||
}
|
||||
|
||||
fn flock(&mut self, fd: i32, op: i32) -> InterpResult<'tcx, Scalar> {
|
||||
fn flock(&mut self, fd_num: i32, op: i32) -> InterpResult<'tcx, Scalar> {
|
||||
let this = self.eval_context_mut();
|
||||
let Some(file_descriptor) = this.machine.fds.get(fd) else {
|
||||
let Some(fd) = this.machine.fds.get(fd_num) else {
|
||||
return Ok(Scalar::from_i32(this.fd_not_found()?));
|
||||
};
|
||||
|
||||
@ -436,8 +436,8 @@ fn flock(&mut self, fd: i32, op: i32) -> InterpResult<'tcx, Scalar> {
|
||||
throw_unsup_format!("unsupported flags {:#x}", op);
|
||||
};
|
||||
|
||||
let result = file_descriptor.flock(this.machine.communicate(), parsed_op)?;
|
||||
drop(file_descriptor);
|
||||
let result = fd.flock(this.machine.communicate(), parsed_op)?;
|
||||
drop(fd);
|
||||
// return `0` if flock is successful
|
||||
let result = result.map(|()| 0i32);
|
||||
Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
|
||||
@ -452,7 +452,7 @@ fn fcntl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> {
|
||||
args.len()
|
||||
);
|
||||
}
|
||||
let fd = this.read_scalar(&args[0])?.to_i32()?;
|
||||
let fd_num = this.read_scalar(&args[0])?.to_i32()?;
|
||||
let cmd = this.read_scalar(&args[1])?.to_i32()?;
|
||||
|
||||
// We only support getting the flags for a descriptor.
|
||||
@ -461,7 +461,7 @@ fn fcntl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> {
|
||||
// `FD_CLOEXEC` value without checking if the flag is set for the file because `std`
|
||||
// always sets this flag when opening a file. However we still need to check that the
|
||||
// file itself is open.
|
||||
Ok(Scalar::from_i32(if this.machine.fds.is_fd(fd) {
|
||||
Ok(Scalar::from_i32(if this.machine.fds.is_fd_num(fd_num) {
|
||||
this.eval_libc_i32("FD_CLOEXEC")
|
||||
} else {
|
||||
this.fd_not_found()?
|
||||
@ -481,9 +481,8 @@ fn fcntl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> {
|
||||
}
|
||||
let start = this.read_scalar(&args[2])?.to_i32()?;
|
||||
|
||||
match this.machine.fds.get(fd) {
|
||||
Some(dup_fd) =>
|
||||
Ok(Scalar::from_i32(this.machine.fds.insert_ref_with_min_fd(dup_fd, start))),
|
||||
match this.machine.fds.get(fd_num) {
|
||||
Some(fd) => Ok(Scalar::from_i32(this.machine.fds.insert_with_min_num(fd, start))),
|
||||
None => Ok(Scalar::from_i32(this.fd_not_found()?)),
|
||||
}
|
||||
} else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC") {
|
||||
@ -494,7 +493,7 @@ fn fcntl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> {
|
||||
return Ok(Scalar::from_i32(-1));
|
||||
}
|
||||
|
||||
this.ffullsync_fd(fd)
|
||||
this.ffullsync_fd(fd_num)
|
||||
} else {
|
||||
throw_unsup_format!("the {:#x} command is not supported for `fcntl`)", cmd);
|
||||
}
|
||||
@ -503,12 +502,12 @@ fn fcntl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> {
|
||||
fn close(&mut self, fd_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
let fd = this.read_scalar(fd_op)?.to_i32()?;
|
||||
let fd_num = this.read_scalar(fd_op)?.to_i32()?;
|
||||
|
||||
let Some(file_description) = this.machine.fds.remove(fd) else {
|
||||
let Some(fd) = this.machine.fds.remove(fd_num) else {
|
||||
return Ok(Scalar::from_i32(this.fd_not_found()?));
|
||||
};
|
||||
let result = file_description.close(this.machine.communicate(), this)?;
|
||||
let result = fd.close(this.machine.communicate(), this)?;
|
||||
// return `0` if close is successful
|
||||
let result = result.map(|()| 0i32);
|
||||
Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
|
||||
@ -532,16 +531,16 @@ fn fd_not_found<T: From<i32>>(&mut self) -> InterpResult<'tcx, T> {
|
||||
/// and keeps the cursor unchanged.
|
||||
fn read(
|
||||
&mut self,
|
||||
fd: i32,
|
||||
fd_num: i32,
|
||||
buf: Pointer,
|
||||
count: u64,
|
||||
offset: Option<i128>,
|
||||
) -> InterpResult<'tcx, Scalar> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
// Isolation check is done via `FileDescriptor` trait.
|
||||
// Isolation check is done via `FileDescription` trait.
|
||||
|
||||
trace!("Reading from FD {}, size {}", fd, count);
|
||||
trace!("Reading from FD {}, size {}", fd_num, count);
|
||||
|
||||
// Check that the *entire* buffer is actually valid memory.
|
||||
this.check_ptr_access(buf, Size::from_bytes(count), CheckInAllocMsg::MemoryAccessTest)?;
|
||||
@ -554,7 +553,7 @@ fn read(
|
||||
let communicate = this.machine.communicate();
|
||||
|
||||
// We temporarily dup the FD to be able to retain mutable access to `this`.
|
||||
let Some(fd) = this.machine.fds.get(fd) else {
|
||||
let Some(fd) = this.machine.fds.get(fd_num) else {
|
||||
trace!("read: FD not found");
|
||||
return Ok(Scalar::from_target_isize(this.fd_not_found()?, this));
|
||||
};
|
||||
@ -597,14 +596,14 @@ fn read(
|
||||
|
||||
fn write(
|
||||
&mut self,
|
||||
fd: i32,
|
||||
fd_num: i32,
|
||||
buf: Pointer,
|
||||
count: u64,
|
||||
offset: Option<i128>,
|
||||
) -> InterpResult<'tcx, Scalar> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
// Isolation check is done via `FileDescriptor` trait.
|
||||
// Isolation check is done via `FileDescription` trait.
|
||||
|
||||
// Check that the *entire* buffer is actually valid memory.
|
||||
this.check_ptr_access(buf, Size::from_bytes(count), CheckInAllocMsg::MemoryAccessTest)?;
|
||||
@ -618,7 +617,7 @@ fn write(
|
||||
|
||||
let bytes = this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(count))?.to_owned();
|
||||
// We temporarily dup the FD to be able to retain mutable access to `this`.
|
||||
let Some(fd) = this.machine.fds.get(fd) else {
|
||||
let Some(fd) = this.machine.fds.get(fd_num) else {
|
||||
return Ok(Scalar::from_target_isize(this.fd_not_found()?, this));
|
||||
};
|
||||
|
||||
|
@ -554,10 +554,10 @@ fn open(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> {
|
||||
Ok(Scalar::from_i32(this.try_unwrap_io_result(fd)?))
|
||||
}
|
||||
|
||||
fn lseek64(&mut self, fd: i32, offset: i128, whence: i32) -> InterpResult<'tcx, Scalar> {
|
||||
fn lseek64(&mut self, fd_num: i32, offset: i128, whence: i32) -> InterpResult<'tcx, Scalar> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
// Isolation check is done via `FileDescriptor` trait.
|
||||
// Isolation check is done via `FileDescription` trait.
|
||||
|
||||
let seek_from = if whence == this.eval_libc_i32("SEEK_SET") {
|
||||
if offset < 0 {
|
||||
@ -580,13 +580,11 @@ fn lseek64(&mut self, fd: i32, offset: i128, whence: i32) -> InterpResult<'tcx,
|
||||
|
||||
let communicate = this.machine.communicate();
|
||||
|
||||
let Some(file_description) = this.machine.fds.get(fd) else {
|
||||
let Some(fd) = this.machine.fds.get(fd_num) else {
|
||||
return Ok(Scalar::from_i64(this.fd_not_found()?));
|
||||
};
|
||||
let result = file_description
|
||||
.seek(communicate, seek_from)?
|
||||
.map(|offset| i64::try_from(offset).unwrap());
|
||||
drop(file_description);
|
||||
let result = fd.seek(communicate, seek_from)?.map(|offset| i64::try_from(offset).unwrap());
|
||||
drop(fd);
|
||||
|
||||
let result = this.try_unwrap_io_result(result)?;
|
||||
Ok(Scalar::from_i64(result))
|
||||
@ -721,7 +719,7 @@ fn macos_fbsd_fstat(
|
||||
return Ok(Scalar::from_i32(this.fd_not_found()?));
|
||||
}
|
||||
|
||||
let metadata = match FileMetadata::from_fd(this, fd)? {
|
||||
let metadata = match FileMetadata::from_fd_num(this, fd)? {
|
||||
Some(metadata) => metadata,
|
||||
None => return Ok(Scalar::from_i32(-1)),
|
||||
};
|
||||
@ -808,7 +806,7 @@ fn linux_statx(
|
||||
// If the path is empty, and the AT_EMPTY_PATH flag is set, we query the open file
|
||||
// represented by dirfd, whether it's a directory or otherwise.
|
||||
let metadata = if path.as_os_str().is_empty() && empty_path_flag {
|
||||
FileMetadata::from_fd(this, dirfd)?
|
||||
FileMetadata::from_fd_num(this, dirfd)?
|
||||
} else {
|
||||
FileMetadata::from_path(this, &path, follow_symlink)?
|
||||
};
|
||||
@ -1260,7 +1258,7 @@ fn closedir(&mut self, dirp_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
|
||||
}))
|
||||
}
|
||||
|
||||
fn ftruncate64(&mut self, fd: i32, length: i128) -> InterpResult<'tcx, Scalar> {
|
||||
fn ftruncate64(&mut self, fd_num: i32, length: i128) -> InterpResult<'tcx, Scalar> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
// Reject if isolation is enabled.
|
||||
@ -1270,30 +1268,29 @@ fn ftruncate64(&mut self, fd: i32, length: i128) -> InterpResult<'tcx, Scalar> {
|
||||
return Ok(Scalar::from_i32(this.fd_not_found()?));
|
||||
}
|
||||
|
||||
let Some(file_description) = this.machine.fds.get(fd) else {
|
||||
let Some(fd) = this.machine.fds.get(fd_num) else {
|
||||
return Ok(Scalar::from_i32(this.fd_not_found()?));
|
||||
};
|
||||
|
||||
// FIXME: Support ftruncate64 for all FDs
|
||||
let FileHandle { file, writable } =
|
||||
file_description.downcast::<FileHandle>().ok_or_else(|| {
|
||||
err_unsup_format!("`ftruncate64` is only supported on file-backed file descriptors")
|
||||
})?;
|
||||
let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
|
||||
err_unsup_format!("`ftruncate64` is only supported on file-backed file descriptors")
|
||||
})?;
|
||||
|
||||
if *writable {
|
||||
if let Ok(length) = length.try_into() {
|
||||
let result = file.set_len(length);
|
||||
drop(file_description);
|
||||
drop(fd);
|
||||
let result = this.try_unwrap_io_result(result.map(|_| 0i32))?;
|
||||
Ok(Scalar::from_i32(result))
|
||||
} else {
|
||||
drop(file_description);
|
||||
drop(fd);
|
||||
let einval = this.eval_libc("EINVAL");
|
||||
this.set_last_error(einval)?;
|
||||
Ok(Scalar::from_i32(-1))
|
||||
}
|
||||
} else {
|
||||
drop(file_description);
|
||||
drop(fd);
|
||||
// The file is not writable
|
||||
let einval = this.eval_libc("EINVAL");
|
||||
this.set_last_error(einval)?;
|
||||
@ -1321,18 +1318,17 @@ fn fsync(&mut self, fd_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
|
||||
self.ffullsync_fd(fd)
|
||||
}
|
||||
|
||||
fn ffullsync_fd(&mut self, fd: i32) -> InterpResult<'tcx, Scalar> {
|
||||
fn ffullsync_fd(&mut self, fd_num: i32) -> InterpResult<'tcx, Scalar> {
|
||||
let this = self.eval_context_mut();
|
||||
let Some(file_description) = this.machine.fds.get(fd) else {
|
||||
let Some(fd) = this.machine.fds.get(fd_num) else {
|
||||
return Ok(Scalar::from_i32(this.fd_not_found()?));
|
||||
};
|
||||
// Only regular files support synchronization.
|
||||
let FileHandle { file, writable } =
|
||||
file_description.downcast::<FileHandle>().ok_or_else(|| {
|
||||
err_unsup_format!("`fsync` is only supported on file-backed file descriptors")
|
||||
})?;
|
||||
let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
|
||||
err_unsup_format!("`fsync` is only supported on file-backed file descriptors")
|
||||
})?;
|
||||
let io_result = maybe_sync_file(file, *writable, File::sync_all);
|
||||
drop(file_description);
|
||||
drop(fd);
|
||||
Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
|
||||
}
|
||||
|
||||
@ -1348,16 +1344,15 @@ fn fdatasync(&mut self, fd_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
|
||||
return Ok(Scalar::from_i32(this.fd_not_found()?));
|
||||
}
|
||||
|
||||
let Some(file_description) = this.machine.fds.get(fd) else {
|
||||
let Some(fd) = this.machine.fds.get(fd) else {
|
||||
return Ok(Scalar::from_i32(this.fd_not_found()?));
|
||||
};
|
||||
// Only regular files support synchronization.
|
||||
let FileHandle { file, writable } =
|
||||
file_description.downcast::<FileHandle>().ok_or_else(|| {
|
||||
err_unsup_format!("`fdatasync` is only supported on file-backed file descriptors")
|
||||
})?;
|
||||
let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
|
||||
err_unsup_format!("`fdatasync` is only supported on file-backed file descriptors")
|
||||
})?;
|
||||
let io_result = maybe_sync_file(file, *writable, File::sync_data);
|
||||
drop(file_description);
|
||||
drop(fd);
|
||||
Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
|
||||
}
|
||||
|
||||
@ -1396,18 +1391,15 @@ fn sync_file_range(
|
||||
return Ok(Scalar::from_i32(this.fd_not_found()?));
|
||||
}
|
||||
|
||||
let Some(file_description) = this.machine.fds.get(fd) else {
|
||||
let Some(fd) = this.machine.fds.get(fd) else {
|
||||
return Ok(Scalar::from_i32(this.fd_not_found()?));
|
||||
};
|
||||
// Only regular files support synchronization.
|
||||
let FileHandle { file, writable } =
|
||||
file_description.downcast::<FileHandle>().ok_or_else(|| {
|
||||
err_unsup_format!(
|
||||
"`sync_data_range` is only supported on file-backed file descriptors"
|
||||
)
|
||||
})?;
|
||||
let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
|
||||
err_unsup_format!("`sync_data_range` is only supported on file-backed file descriptors")
|
||||
})?;
|
||||
let io_result = maybe_sync_file(file, *writable, File::sync_data);
|
||||
drop(file_description);
|
||||
drop(fd);
|
||||
Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
|
||||
}
|
||||
|
||||
@ -1699,15 +1691,15 @@ fn from_path<'tcx>(
|
||||
FileMetadata::from_meta(ecx, metadata)
|
||||
}
|
||||
|
||||
fn from_fd<'tcx>(
|
||||
fn from_fd_num<'tcx>(
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
fd: i32,
|
||||
fd_num: i32,
|
||||
) -> InterpResult<'tcx, Option<FileMetadata>> {
|
||||
let Some(file_description) = ecx.machine.fds.get(fd) else {
|
||||
let Some(fd) = ecx.machine.fds.get(fd_num) else {
|
||||
return ecx.fd_not_found().map(|_: i32| None);
|
||||
};
|
||||
|
||||
let file = &file_description
|
||||
let file = &fd
|
||||
.downcast::<FileHandle>()
|
||||
.ok_or_else(|| {
|
||||
err_unsup_format!(
|
||||
@ -1717,7 +1709,7 @@ fn from_fd<'tcx>(
|
||||
.file;
|
||||
|
||||
let metadata = file.metadata();
|
||||
drop(file_description);
|
||||
drop(fd);
|
||||
FileMetadata::from_meta(ecx, metadata)
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,10 @@ pub fn new(events: u32, data: u64) -> EpollEventInstance {
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EpollEventInterest {
|
||||
/// The file descriptor value of the file description registered.
|
||||
file_descriptor: i32,
|
||||
/// This is only used for ready_list, to inform userspace which FD triggered an event.
|
||||
/// For that, it is crucial to preserve the original FD number.
|
||||
/// This FD number must never be "dereferenced" to a file description inside Miri.
|
||||
fd_num: i32,
|
||||
/// The events bitmask retrieved from `epoll_event`.
|
||||
events: u32,
|
||||
/// The data retrieved from `epoll_event`.
|
||||
@ -61,8 +64,8 @@ pub struct EpollEventInterest {
|
||||
data: u64,
|
||||
/// Ready list of the epoll instance under which this EpollEventInterest is registered.
|
||||
ready_list: Rc<RefCell<BTreeMap<(FdId, i32), EpollEventInstance>>>,
|
||||
/// The file descriptor value that this EpollEventInterest is registered under.
|
||||
epfd: i32,
|
||||
/// The epoll file description that this EpollEventInterest is registered under.
|
||||
weak_epfd: WeakFileDescriptionRef,
|
||||
}
|
||||
|
||||
/// EpollReadyEvents reflects the readiness of a file description.
|
||||
@ -339,11 +342,11 @@ fn epoll_ctl(
|
||||
|
||||
// Create an epoll_interest.
|
||||
let interest = Rc::new(RefCell::new(EpollEventInterest {
|
||||
file_descriptor: fd,
|
||||
fd_num: fd,
|
||||
events,
|
||||
data,
|
||||
ready_list: Rc::clone(ready_list),
|
||||
epfd: epfd_value,
|
||||
weak_epfd: epfd.downgrade(),
|
||||
}));
|
||||
|
||||
if op == epoll_ctl_add {
|
||||
@ -553,12 +556,12 @@ fn check_and_update_readiness(
|
||||
if is_updated {
|
||||
// Edge-triggered notification only notify one thread even if there are
|
||||
// multiple threads block on the same epfd.
|
||||
let epfd = this.machine.fds.get(epoll_interest.borrow().epfd).unwrap();
|
||||
|
||||
// This unwrap can never fail because if the current epoll instance were
|
||||
// closed and its epfd value reused, the upgrade of weak_epoll_interest
|
||||
// closed, the upgrade of weak_epoll_interest
|
||||
// above would fail. This guarantee holds because only the epoll instance
|
||||
// holds a strong ref to epoll_interest.
|
||||
let epfd = epoll_interest.borrow().weak_epfd.upgrade().unwrap();
|
||||
// FIXME: We can randomly pick a thread to unblock.
|
||||
if let Some(thread_id) =
|
||||
epfd.downcast::<Epoll>().unwrap().thread_id.borrow_mut().pop()
|
||||
@ -615,7 +618,7 @@ fn check_and_update_one_event_interest<'tcx>(
|
||||
// If there is any event that we are interested in being specified as ready,
|
||||
// insert an epoll_return to the ready list.
|
||||
if flags != 0 {
|
||||
let epoll_key = (id, epoll_event_interest.file_descriptor);
|
||||
let epoll_key = (id, epoll_event_interest.fd_num);
|
||||
let ready_list = &mut epoll_event_interest.ready_list.borrow_mut();
|
||||
let event_instance = EpollEventInstance::new(flags, epoll_event_interest.data);
|
||||
// Triggers the notification by inserting it to the ready list.
|
||||
|
@ -14,12 +14,13 @@
|
||||
|
||||
impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {}
|
||||
trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
fn os_unfair_lock_getid(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx, MutexId> {
|
||||
fn os_unfair_lock_getid(&mut self, lock_ptr: &OpTy<'tcx>) -> InterpResult<'tcx, MutexId> {
|
||||
let this = self.eval_context_mut();
|
||||
let lock = this.deref_pointer(lock_ptr)?;
|
||||
// os_unfair_lock holds a 32-bit value, is initialized with zero and
|
||||
// must be assumed to be opaque. Therefore, we can just store our
|
||||
// internal mutex ID in the structure without anyone noticing.
|
||||
this.mutex_get_or_create_id(lock_op, this.libc_ty_layout("os_unfair_lock"), 0, |_| Ok(None))
|
||||
this.mutex_get_or_create_id(&lock, 0, |_| Ok(None))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,10 +42,10 @@ fn mmap(
|
||||
let map_shared = this.eval_libc_i32("MAP_SHARED");
|
||||
let map_fixed = this.eval_libc_i32("MAP_FIXED");
|
||||
|
||||
// This is a horrible hack, but on MacOS and Solaris the guard page mechanism uses mmap
|
||||
// This is a horrible hack, but on MacOS and Solarish the guard page mechanism uses mmap
|
||||
// in a way we do not support. We just give it the return value it expects.
|
||||
if this.frame_in_std()
|
||||
&& matches!(&*this.tcx.sess.target.os, "macos" | "solaris")
|
||||
&& matches!(&*this.tcx.sess.target.os, "macos" | "solaris" | "illumos")
|
||||
&& (flags & map_fixed) != 0
|
||||
{
|
||||
return Ok(Scalar::from_maybe_pointer(Pointer::from_addr_invalid(addr), this));
|
||||
|
@ -11,17 +11,17 @@
|
||||
#[inline]
|
||||
fn mutexattr_kind_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
|
||||
Ok(match &*ecx.tcx.sess.target.os {
|
||||
"linux" | "illumos" | "solaris" | "macos" => 0,
|
||||
"linux" | "illumos" | "solaris" | "macos" | "freebsd" | "android" => 0,
|
||||
os => throw_unsup_format!("`pthread_mutexattr` is not supported on {os}"),
|
||||
})
|
||||
}
|
||||
|
||||
fn mutexattr_get_kind<'tcx>(
|
||||
ecx: &MiriInterpCx<'tcx>,
|
||||
attr_op: &OpTy<'tcx>,
|
||||
attr_ptr: &OpTy<'tcx>,
|
||||
) -> InterpResult<'tcx, i32> {
|
||||
ecx.deref_pointer_and_read(
|
||||
attr_op,
|
||||
attr_ptr,
|
||||
mutexattr_kind_offset(ecx)?,
|
||||
ecx.libc_ty_layout("pthread_mutexattr_t"),
|
||||
ecx.machine.layouts.i32,
|
||||
@ -31,11 +31,11 @@ fn mutexattr_get_kind<'tcx>(
|
||||
|
||||
fn mutexattr_set_kind<'tcx>(
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
attr_op: &OpTy<'tcx>,
|
||||
attr_ptr: &OpTy<'tcx>,
|
||||
kind: i32,
|
||||
) -> InterpResult<'tcx, ()> {
|
||||
ecx.deref_pointer_and_write(
|
||||
attr_op,
|
||||
attr_ptr,
|
||||
mutexattr_kind_offset(ecx)?,
|
||||
Scalar::from_i32(kind),
|
||||
ecx.libc_ty_layout("pthread_mutexattr_t"),
|
||||
@ -43,29 +43,40 @@ fn mutexattr_set_kind<'tcx>(
|
||||
)
|
||||
}
|
||||
|
||||
/// A flag that allows to distinguish `PTHREAD_MUTEX_NORMAL` from
|
||||
/// `PTHREAD_MUTEX_DEFAULT`. Since in `glibc` they have the same numeric values,
|
||||
/// but different behaviour, we need a way to distinguish them. We do this by
|
||||
/// setting this bit flag to the `PTHREAD_MUTEX_NORMAL` mutexes. See the comment
|
||||
/// in `pthread_mutexattr_settype` function.
|
||||
const PTHREAD_MUTEX_NORMAL_FLAG: i32 = 0x8000000;
|
||||
/// To differentiate "the mutex kind has not been changed" from
|
||||
/// "the mutex kind has been set to PTHREAD_MUTEX_DEFAULT and that is
|
||||
/// equal to some other mutex kind", we make the default value of this
|
||||
/// field *not* PTHREAD_MUTEX_DEFAULT but this special flag.
|
||||
const PTHREAD_MUTEX_KIND_UNCHANGED: i32 = 0x8000000;
|
||||
|
||||
fn is_mutex_kind_default<'tcx>(ecx: &MiriInterpCx<'tcx>, kind: i32) -> InterpResult<'tcx, bool> {
|
||||
Ok(kind == ecx.eval_libc_i32("PTHREAD_MUTEX_DEFAULT"))
|
||||
/// The mutex kind.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum MutexKind {
|
||||
Normal,
|
||||
Default,
|
||||
Recursive,
|
||||
ErrorCheck,
|
||||
}
|
||||
|
||||
fn is_mutex_kind_normal<'tcx>(ecx: &MiriInterpCx<'tcx>, kind: i32) -> InterpResult<'tcx, bool> {
|
||||
let mutex_normal_kind = ecx.eval_libc_i32("PTHREAD_MUTEX_NORMAL");
|
||||
Ok(kind == (mutex_normal_kind | PTHREAD_MUTEX_NORMAL_FLAG))
|
||||
#[derive(Debug)]
|
||||
/// Additional data that we attach with each mutex instance.
|
||||
pub struct AdditionalMutexData {
|
||||
/// The mutex kind, used by some mutex implementations like pthreads mutexes.
|
||||
pub kind: MutexKind,
|
||||
|
||||
/// The address of the mutex.
|
||||
pub address: u64,
|
||||
}
|
||||
|
||||
// pthread_mutex_t is between 24 and 48 bytes, depending on the platform.
|
||||
// pthread_mutex_t is between 4 and 48 bytes, depending on the platform.
|
||||
// We ignore the platform layout and store our own fields:
|
||||
// - id: u32
|
||||
|
||||
fn mutex_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
|
||||
// When adding a new OS, make sure we also support all its static initializers in
|
||||
// `mutex_kind_from_static_initializer`!
|
||||
let offset = match &*ecx.tcx.sess.target.os {
|
||||
"linux" | "illumos" | "solaris" => 0,
|
||||
"linux" | "illumos" | "solaris" | "freebsd" | "android" => 0,
|
||||
// macOS stores a signature in the first bytes, so we have to move to offset 4.
|
||||
"macos" => 4,
|
||||
os => throw_unsup_format!("`pthread_mutex` is not supported on {os}"),
|
||||
@ -77,15 +88,28 @@ fn mutex_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
|
||||
// recursive or error checking mutexes. We should also add thme in this sanity check.
|
||||
static SANITY: AtomicBool = AtomicBool::new(false);
|
||||
if !SANITY.swap(true, Ordering::Relaxed) {
|
||||
let static_initializer = ecx.eval_path(&["libc", "PTHREAD_MUTEX_INITIALIZER"]);
|
||||
let id_field = static_initializer
|
||||
.offset(Size::from_bytes(offset), ecx.machine.layouts.u32, ecx)
|
||||
.unwrap();
|
||||
let id = ecx.read_scalar(&id_field).unwrap().to_u32().unwrap();
|
||||
assert_eq!(
|
||||
id, 0,
|
||||
"PTHREAD_MUTEX_INITIALIZER is incompatible with our pthread_mutex layout: id is not 0"
|
||||
);
|
||||
let check_static_initializer = |name| {
|
||||
let static_initializer = ecx.eval_path(&["libc", name]);
|
||||
let id_field = static_initializer
|
||||
.offset(Size::from_bytes(offset), ecx.machine.layouts.u32, ecx)
|
||||
.unwrap();
|
||||
let id = ecx.read_scalar(&id_field).unwrap().to_u32().unwrap();
|
||||
assert_eq!(id, 0, "{name} is incompatible with our pthread_mutex layout: id is not 0");
|
||||
};
|
||||
|
||||
check_static_initializer("PTHREAD_MUTEX_INITIALIZER");
|
||||
// Check non-standard initializers.
|
||||
match &*ecx.tcx.sess.target.os {
|
||||
"linux" => {
|
||||
check_static_initializer("PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP");
|
||||
check_static_initializer("PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP");
|
||||
check_static_initializer("PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP");
|
||||
}
|
||||
"illumos" | "solaris" | "macos" | "freebsd" | "android" => {
|
||||
// No non-standard initializers.
|
||||
}
|
||||
os => throw_unsup_format!("`pthread_mutex` is not supported on {os}"),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(offset)
|
||||
@ -94,15 +118,13 @@ fn mutex_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
|
||||
/// Eagerly create and initialize a new mutex.
|
||||
fn mutex_create<'tcx>(
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
mutex_op: &OpTy<'tcx>,
|
||||
kind: i32,
|
||||
mutex_ptr: &OpTy<'tcx>,
|
||||
kind: MutexKind,
|
||||
) -> InterpResult<'tcx> {
|
||||
// FIXME: might be worth changing mutex_create to take the mplace
|
||||
// rather than the `OpTy`.
|
||||
let address = ecx.read_pointer(mutex_op)?.addr().bytes();
|
||||
let kind = translate_kind(ecx, kind)?;
|
||||
let data = Some(AdditionalMutexData { address, kind });
|
||||
ecx.mutex_create(mutex_op, ecx.libc_ty_layout("pthread_mutex_t"), mutex_id_offset(ecx)?, data)?;
|
||||
let mutex = ecx.deref_pointer(mutex_ptr)?;
|
||||
let address = mutex.ptr().addr().bytes();
|
||||
let data = Box::new(AdditionalMutexData { address, kind });
|
||||
ecx.mutex_create(&mutex, mutex_id_offset(ecx)?, Some(data))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -112,27 +134,23 @@ fn mutex_create<'tcx>(
|
||||
/// return an error if it has.
|
||||
fn mutex_get_id<'tcx>(
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
mutex_op: &OpTy<'tcx>,
|
||||
mutex_ptr: &OpTy<'tcx>,
|
||||
) -> InterpResult<'tcx, MutexId> {
|
||||
let address = ecx.read_pointer(mutex_op)?.addr().bytes();
|
||||
let mutex = ecx.deref_pointer(mutex_ptr)?;
|
||||
let address = mutex.ptr().addr().bytes();
|
||||
|
||||
// FIXME: might be worth changing mutex_get_or_create_id to take the mplace
|
||||
// rather than the `OpTy`.
|
||||
let id = ecx.mutex_get_or_create_id(
|
||||
mutex_op,
|
||||
ecx.libc_ty_layout("pthread_mutex_t"),
|
||||
mutex_id_offset(ecx)?,
|
||||
|ecx| {
|
||||
// This is called if a static initializer was used and the lock has not been assigned
|
||||
// an ID yet. We have to determine the mutex kind from the static initializer.
|
||||
let kind = kind_from_static_initializer(ecx, mutex_op)?;
|
||||
let id = ecx.mutex_get_or_create_id(&mutex, mutex_id_offset(ecx)?, |ecx| {
|
||||
// This is called if a static initializer was used and the lock has not been assigned
|
||||
// an ID yet. We have to determine the mutex kind from the static initializer.
|
||||
let kind = mutex_kind_from_static_initializer(ecx, &mutex)?;
|
||||
|
||||
Ok(Some(AdditionalMutexData { kind, address }))
|
||||
},
|
||||
)?;
|
||||
Ok(Some(Box::new(AdditionalMutexData { kind, address })))
|
||||
})?;
|
||||
|
||||
// Check that the mutex has not been moved since last use.
|
||||
let data = ecx.mutex_get_data(id).expect("data should be always exist for pthreads");
|
||||
let data = ecx
|
||||
.mutex_get_data::<AdditionalMutexData>(id)
|
||||
.expect("data should always exist for pthreads");
|
||||
if data.address != address {
|
||||
throw_ub_format!("pthread_mutex_t can't be moved after first use")
|
||||
}
|
||||
@ -141,51 +159,64 @@ fn mutex_get_id<'tcx>(
|
||||
}
|
||||
|
||||
/// Returns the kind of a static initializer.
|
||||
fn kind_from_static_initializer<'tcx>(
|
||||
fn mutex_kind_from_static_initializer<'tcx>(
|
||||
ecx: &MiriInterpCx<'tcx>,
|
||||
mutex_op: &OpTy<'tcx>,
|
||||
mutex: &MPlaceTy<'tcx>,
|
||||
) -> InterpResult<'tcx, MutexKind> {
|
||||
// Only linux has static initializers other than PTHREAD_MUTEX_DEFAULT.
|
||||
let kind = match &*ecx.tcx.sess.target.os {
|
||||
Ok(match &*ecx.tcx.sess.target.os {
|
||||
// Only linux has static initializers other than PTHREAD_MUTEX_DEFAULT.
|
||||
"linux" => {
|
||||
let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 };
|
||||
|
||||
ecx.deref_pointer_and_read(
|
||||
mutex_op,
|
||||
offset,
|
||||
ecx.libc_ty_layout("pthread_mutex_t"),
|
||||
ecx.machine.layouts.i32,
|
||||
)?
|
||||
.to_i32()?
|
||||
let kind_place =
|
||||
mutex.offset(Size::from_bytes(offset), ecx.machine.layouts.i32, ecx)?;
|
||||
let kind = ecx.read_scalar(&kind_place)?.to_i32()?;
|
||||
// Here we give PTHREAD_MUTEX_DEFAULT priority so that
|
||||
// PTHREAD_MUTEX_INITIALIZER behaves like `pthread_mutex_init` with a NULL argument.
|
||||
if kind == ecx.eval_libc_i32("PTHREAD_MUTEX_DEFAULT") {
|
||||
MutexKind::Default
|
||||
} else {
|
||||
mutex_translate_kind(ecx, kind)?
|
||||
}
|
||||
}
|
||||
| "illumos" | "solaris" | "macos" => ecx.eval_libc_i32("PTHREAD_MUTEX_DEFAULT"),
|
||||
os => throw_unsup_format!("`pthread_mutex` is not supported on {os}"),
|
||||
};
|
||||
|
||||
translate_kind(ecx, kind)
|
||||
_ => MutexKind::Default,
|
||||
})
|
||||
}
|
||||
|
||||
fn translate_kind<'tcx>(ecx: &MiriInterpCx<'tcx>, kind: i32) -> InterpResult<'tcx, MutexKind> {
|
||||
Ok(if is_mutex_kind_default(ecx, kind)? {
|
||||
MutexKind::Default
|
||||
} else if is_mutex_kind_normal(ecx, kind)? {
|
||||
fn mutex_translate_kind<'tcx>(
|
||||
ecx: &MiriInterpCx<'tcx>,
|
||||
kind: i32,
|
||||
) -> InterpResult<'tcx, MutexKind> {
|
||||
Ok(if kind == (ecx.eval_libc_i32("PTHREAD_MUTEX_NORMAL")) {
|
||||
MutexKind::Normal
|
||||
} else if kind == ecx.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK") {
|
||||
MutexKind::ErrorCheck
|
||||
} else if kind == ecx.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE") {
|
||||
MutexKind::Recursive
|
||||
} else if kind == ecx.eval_libc_i32("PTHREAD_MUTEX_DEFAULT")
|
||||
|| kind == PTHREAD_MUTEX_KIND_UNCHANGED
|
||||
{
|
||||
// We check this *last* since PTHREAD_MUTEX_DEFAULT may be numerically equal to one of the
|
||||
// others, and we want an explicit `mutexattr_settype` to work as expected.
|
||||
MutexKind::Default
|
||||
} else {
|
||||
throw_unsup_format!("unsupported type of mutex: {kind}");
|
||||
})
|
||||
}
|
||||
|
||||
// pthread_rwlock_t is between 32 and 56 bytes, depending on the platform.
|
||||
// pthread_rwlock_t is between 4 and 56 bytes, depending on the platform.
|
||||
// We ignore the platform layout and store our own fields:
|
||||
// - id: u32
|
||||
|
||||
#[derive(Debug)]
|
||||
/// Additional data that we attach with each rwlock instance.
|
||||
pub struct AdditionalRwLockData {
|
||||
/// The address of the rwlock.
|
||||
pub address: u64,
|
||||
}
|
||||
|
||||
fn rwlock_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
|
||||
let offset = match &*ecx.tcx.sess.target.os {
|
||||
"linux" | "illumos" | "solaris" => 0,
|
||||
"linux" | "illumos" | "solaris" | "freebsd" | "android" => 0,
|
||||
// macOS stores a signature in the first bytes, so we have to move to offset 4.
|
||||
"macos" => 4,
|
||||
os => throw_unsup_format!("`pthread_rwlock` is not supported on {os}"),
|
||||
@ -211,13 +242,24 @@ fn rwlock_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
|
||||
|
||||
fn rwlock_get_id<'tcx>(
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
rwlock_op: &OpTy<'tcx>,
|
||||
rwlock_ptr: &OpTy<'tcx>,
|
||||
) -> InterpResult<'tcx, RwLockId> {
|
||||
ecx.rwlock_get_or_create_id(
|
||||
rwlock_op,
|
||||
ecx.libc_ty_layout("pthread_rwlock_t"),
|
||||
rwlock_id_offset(ecx)?,
|
||||
)
|
||||
let rwlock = ecx.deref_pointer(rwlock_ptr)?;
|
||||
let address = rwlock.ptr().addr().bytes();
|
||||
|
||||
let id = ecx.rwlock_get_or_create_id(&rwlock, rwlock_id_offset(ecx)?, |_| {
|
||||
Ok(Some(Box::new(AdditionalRwLockData { address })))
|
||||
})?;
|
||||
|
||||
// Check that the rwlock has not been moved since last use.
|
||||
let data = ecx
|
||||
.rwlock_get_data::<AdditionalRwLockData>(id)
|
||||
.expect("data should always exist for pthreads");
|
||||
if data.address != address {
|
||||
throw_ub_format!("pthread_rwlock_t can't be moved after first use")
|
||||
}
|
||||
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
// pthread_condattr_t.
|
||||
@ -227,7 +269,7 @@ fn rwlock_get_id<'tcx>(
|
||||
#[inline]
|
||||
fn condattr_clock_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
|
||||
Ok(match &*ecx.tcx.sess.target.os {
|
||||
"linux" | "illumos" | "solaris" => 0,
|
||||
"linux" | "illumos" | "solaris" | "freebsd" | "android" => 0,
|
||||
// macOS does not have a clock attribute.
|
||||
os => throw_unsup_format!("`pthread_condattr` clock field is not supported on {os}"),
|
||||
})
|
||||
@ -235,10 +277,10 @@ fn condattr_clock_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u
|
||||
|
||||
fn condattr_get_clock_id<'tcx>(
|
||||
ecx: &MiriInterpCx<'tcx>,
|
||||
attr_op: &OpTy<'tcx>,
|
||||
attr_ptr: &OpTy<'tcx>,
|
||||
) -> InterpResult<'tcx, i32> {
|
||||
ecx.deref_pointer_and_read(
|
||||
attr_op,
|
||||
attr_ptr,
|
||||
condattr_clock_offset(ecx)?,
|
||||
ecx.libc_ty_layout("pthread_condattr_t"),
|
||||
ecx.machine.layouts.i32,
|
||||
@ -246,13 +288,26 @@ fn condattr_get_clock_id<'tcx>(
|
||||
.to_i32()
|
||||
}
|
||||
|
||||
fn cond_translate_clock_id<'tcx>(
|
||||
ecx: &MiriInterpCx<'tcx>,
|
||||
raw_id: i32,
|
||||
) -> InterpResult<'tcx, ClockId> {
|
||||
Ok(if raw_id == ecx.eval_libc_i32("CLOCK_REALTIME") {
|
||||
ClockId::Realtime
|
||||
} else if raw_id == ecx.eval_libc_i32("CLOCK_MONOTONIC") {
|
||||
ClockId::Monotonic
|
||||
} else {
|
||||
throw_unsup_format!("unsupported clock id: {raw_id}");
|
||||
})
|
||||
}
|
||||
|
||||
fn condattr_set_clock_id<'tcx>(
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
attr_op: &OpTy<'tcx>,
|
||||
attr_ptr: &OpTy<'tcx>,
|
||||
clock_id: i32,
|
||||
) -> InterpResult<'tcx, ()> {
|
||||
ecx.deref_pointer_and_write(
|
||||
attr_op,
|
||||
attr_ptr,
|
||||
condattr_clock_offset(ecx)?,
|
||||
Scalar::from_i32(clock_id),
|
||||
ecx.libc_ty_layout("pthread_condattr_t"),
|
||||
@ -260,14 +315,13 @@ fn condattr_set_clock_id<'tcx>(
|
||||
)
|
||||
}
|
||||
|
||||
// pthread_cond_t.
|
||||
// pthread_cond_t can be only 4 bytes in size, depending on the platform.
|
||||
// We ignore the platform layout and store our own fields:
|
||||
// - id: u32
|
||||
// - clock: i32
|
||||
|
||||
fn cond_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
|
||||
let offset = match &*ecx.tcx.sess.target.os {
|
||||
"linux" | "illumos" | "solaris" => 0,
|
||||
"linux" | "illumos" | "solaris" | "freebsd" | "android" => 0,
|
||||
// macOS stores a signature in the first bytes, so we have to move to offset 4.
|
||||
"macos" => 4,
|
||||
os => throw_unsup_format!("`pthread_cond` is not supported on {os}"),
|
||||
@ -291,88 +345,42 @@ fn cond_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
|
||||
Ok(offset)
|
||||
}
|
||||
|
||||
/// Determines whether this clock represents the real-time clock, CLOCK_REALTIME.
|
||||
fn is_cond_clock_realtime<'tcx>(ecx: &MiriInterpCx<'tcx>, clock_id: i32) -> bool {
|
||||
// To ensure compatibility with PTHREAD_COND_INITIALIZER on all platforms,
|
||||
// we can't just compare with CLOCK_REALTIME: on Solarish, PTHREAD_COND_INITIALIZER
|
||||
// makes the clock 0 but CLOCK_REALTIME is 3.
|
||||
// However, we need to always be able to distinguish this from CLOCK_MONOTONIC.
|
||||
clock_id == ecx.eval_libc_i32("CLOCK_REALTIME")
|
||||
|| (clock_id == 0 && clock_id != ecx.eval_libc_i32("CLOCK_MONOTONIC"))
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum ClockId {
|
||||
Realtime,
|
||||
Monotonic,
|
||||
}
|
||||
|
||||
fn cond_clock_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> u64 {
|
||||
// macOS doesn't have a clock attribute, but to keep the code uniform we store
|
||||
// a clock ID in the pthread_cond_t anyway. There's enough space.
|
||||
let offset = 8;
|
||||
#[derive(Debug)]
|
||||
/// Additional data that we attach with each cond instance.
|
||||
struct AdditionalCondData {
|
||||
/// The address of the cond.
|
||||
address: u64,
|
||||
|
||||
// Sanity-check this against PTHREAD_COND_INITIALIZER (but only once):
|
||||
// the clock must start out as CLOCK_REALTIME.
|
||||
static SANITY: AtomicBool = AtomicBool::new(false);
|
||||
if !SANITY.swap(true, Ordering::Relaxed) {
|
||||
let static_initializer = ecx.eval_path(&["libc", "PTHREAD_COND_INITIALIZER"]);
|
||||
let id_field = static_initializer
|
||||
.offset(Size::from_bytes(offset), ecx.machine.layouts.i32, ecx)
|
||||
.unwrap();
|
||||
let id = ecx.read_scalar(&id_field).unwrap().to_i32().unwrap();
|
||||
assert!(
|
||||
is_cond_clock_realtime(ecx, id),
|
||||
"PTHREAD_COND_INITIALIZER is incompatible with our pthread_cond layout: clock is not CLOCK_REALTIME"
|
||||
);
|
||||
}
|
||||
|
||||
offset
|
||||
/// The clock id of the cond.
|
||||
clock_id: ClockId,
|
||||
}
|
||||
|
||||
fn cond_get_id<'tcx>(
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
cond_op: &OpTy<'tcx>,
|
||||
cond_ptr: &OpTy<'tcx>,
|
||||
) -> InterpResult<'tcx, CondvarId> {
|
||||
ecx.condvar_get_or_create_id(
|
||||
cond_op,
|
||||
ecx.libc_ty_layout("pthread_cond_t"),
|
||||
cond_id_offset(ecx)?,
|
||||
)
|
||||
}
|
||||
let cond = ecx.deref_pointer(cond_ptr)?;
|
||||
let address = cond.ptr().addr().bytes();
|
||||
let id = ecx.condvar_get_or_create_id(&cond, cond_id_offset(ecx)?, |_ecx| {
|
||||
// This used the static initializer. The clock there is always CLOCK_REALTIME.
|
||||
Ok(Some(Box::new(AdditionalCondData { address, clock_id: ClockId::Realtime })))
|
||||
})?;
|
||||
|
||||
fn cond_reset_id<'tcx>(
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
cond_op: &OpTy<'tcx>,
|
||||
) -> InterpResult<'tcx, ()> {
|
||||
ecx.deref_pointer_and_write(
|
||||
cond_op,
|
||||
cond_id_offset(ecx)?,
|
||||
Scalar::from_i32(0),
|
||||
ecx.libc_ty_layout("pthread_cond_t"),
|
||||
ecx.machine.layouts.u32,
|
||||
)
|
||||
}
|
||||
// Check that the mutex has not been moved since last use.
|
||||
let data = ecx
|
||||
.condvar_get_data::<AdditionalCondData>(id)
|
||||
.expect("data should always exist for pthreads");
|
||||
if data.address != address {
|
||||
throw_ub_format!("pthread_cond_t can't be moved after first use")
|
||||
}
|
||||
|
||||
fn cond_get_clock_id<'tcx>(
|
||||
ecx: &MiriInterpCx<'tcx>,
|
||||
cond_op: &OpTy<'tcx>,
|
||||
) -> InterpResult<'tcx, i32> {
|
||||
ecx.deref_pointer_and_read(
|
||||
cond_op,
|
||||
cond_clock_offset(ecx),
|
||||
ecx.libc_ty_layout("pthread_cond_t"),
|
||||
ecx.machine.layouts.i32,
|
||||
)?
|
||||
.to_i32()
|
||||
}
|
||||
|
||||
fn cond_set_clock_id<'tcx>(
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
cond_op: &OpTy<'tcx>,
|
||||
clock_id: i32,
|
||||
) -> InterpResult<'tcx, ()> {
|
||||
ecx.deref_pointer_and_write(
|
||||
cond_op,
|
||||
cond_clock_offset(ecx),
|
||||
Scalar::from_i32(clock_id),
|
||||
ecx.libc_ty_layout("pthread_cond_t"),
|
||||
ecx.machine.layouts.i32,
|
||||
)
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
|
||||
@ -380,8 +388,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
fn pthread_mutexattr_init(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
let default_kind = this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT");
|
||||
mutexattr_set_kind(this, attr_op, default_kind)?;
|
||||
mutexattr_set_kind(this, attr_op, PTHREAD_MUTEX_KIND_UNCHANGED)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -394,30 +401,13 @@ fn pthread_mutexattr_settype(
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
let kind = this.read_scalar(kind_op)?.to_i32()?;
|
||||
if kind == this.eval_libc_i32("PTHREAD_MUTEX_NORMAL") {
|
||||
// In `glibc` implementation, the numeric values of
|
||||
// `PTHREAD_MUTEX_NORMAL` and `PTHREAD_MUTEX_DEFAULT` are equal.
|
||||
// However, a mutex created by explicitly passing
|
||||
// `PTHREAD_MUTEX_NORMAL` type has in some cases different behaviour
|
||||
// from the default mutex for which the type was not explicitly
|
||||
// specified. For a more detailed discussion, please see
|
||||
// https://github.com/rust-lang/miri/issues/1419.
|
||||
//
|
||||
// To distinguish these two cases in already constructed mutexes, we
|
||||
// use the same trick as glibc: for the case when
|
||||
// `pthread_mutexattr_settype` is called explicitly, we set the
|
||||
// `PTHREAD_MUTEX_NORMAL_FLAG` flag.
|
||||
let normal_kind = kind | PTHREAD_MUTEX_NORMAL_FLAG;
|
||||
// Check that after setting the flag, the kind is distinguishable
|
||||
// from all other kinds.
|
||||
assert_ne!(normal_kind, this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT"));
|
||||
assert_ne!(normal_kind, this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK"));
|
||||
assert_ne!(normal_kind, this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE"));
|
||||
mutexattr_set_kind(this, attr_op, normal_kind)?;
|
||||
} else if kind == this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT")
|
||||
if kind == this.eval_libc_i32("PTHREAD_MUTEX_NORMAL")
|
||||
|| kind == this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT")
|
||||
|| kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK")
|
||||
|| kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE")
|
||||
{
|
||||
// Make sure we do not mix this up with the "unchanged" kind.
|
||||
assert_ne!(kind, PTHREAD_MUTEX_KIND_UNCHANGED);
|
||||
mutexattr_set_kind(this, attr_op, kind)?;
|
||||
} else {
|
||||
let einval = this.eval_libc_i32("EINVAL");
|
||||
@ -461,9 +451,9 @@ fn pthread_mutex_init(
|
||||
|
||||
let attr = this.read_pointer(attr_op)?;
|
||||
let kind = if this.ptr_is_null(attr)? {
|
||||
this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT")
|
||||
MutexKind::Default
|
||||
} else {
|
||||
mutexattr_get_kind(this, attr_op)?
|
||||
mutex_translate_kind(this, mutexattr_get_kind(this, attr_op)?)?
|
||||
};
|
||||
|
||||
mutex_create(this, mutex_op, kind)?;
|
||||
@ -479,8 +469,10 @@ fn pthread_mutex_lock(
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
let id = mutex_get_id(this, mutex_op)?;
|
||||
let kind =
|
||||
this.mutex_get_data(id).expect("data should always exist for pthread mutexes").kind;
|
||||
let kind = this
|
||||
.mutex_get_data::<AdditionalMutexData>(id)
|
||||
.expect("data should always exist for pthread mutexes")
|
||||
.kind;
|
||||
|
||||
let ret = if this.mutex_is_locked(id) {
|
||||
let owner_thread = this.mutex_get_owner(id);
|
||||
@ -498,10 +490,6 @@ fn pthread_mutex_lock(
|
||||
this.mutex_lock(id);
|
||||
0
|
||||
}
|
||||
_ =>
|
||||
throw_unsup_format!(
|
||||
"called pthread_mutex_lock on an unsupported type of mutex"
|
||||
),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -517,8 +505,10 @@ fn pthread_mutex_trylock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx,
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
let id = mutex_get_id(this, mutex_op)?;
|
||||
let kind =
|
||||
this.mutex_get_data(id).expect("data should always exist for pthread mutexes").kind;
|
||||
let kind = this
|
||||
.mutex_get_data::<AdditionalMutexData>(id)
|
||||
.expect("data should always exist for pthread mutexes")
|
||||
.kind;
|
||||
|
||||
Ok(Scalar::from_i32(if this.mutex_is_locked(id) {
|
||||
let owner_thread = this.mutex_get_owner(id);
|
||||
@ -532,10 +522,6 @@ fn pthread_mutex_trylock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx,
|
||||
this.mutex_lock(id);
|
||||
0
|
||||
}
|
||||
_ =>
|
||||
throw_unsup_format!(
|
||||
"called pthread_mutex_trylock on an unsupported type of mutex"
|
||||
),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -549,8 +535,10 @@ fn pthread_mutex_unlock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx,
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
let id = mutex_get_id(this, mutex_op)?;
|
||||
let kind =
|
||||
this.mutex_get_data(id).expect("data should always exist for pthread mutexes").kind;
|
||||
let kind = this
|
||||
.mutex_get_data::<AdditionalMutexData>(id)
|
||||
.expect("data should always exist for pthread mutexes")
|
||||
.kind;
|
||||
|
||||
if let Some(_old_locked_count) = this.mutex_unlock(id)? {
|
||||
// The mutex was locked by the current thread.
|
||||
@ -570,10 +558,6 @@ fn pthread_mutex_unlock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx,
|
||||
),
|
||||
MutexKind::ErrorCheck | MutexKind::Recursive =>
|
||||
Ok(Scalar::from_i32(this.eval_libc_i32("EPERM"))),
|
||||
_ =>
|
||||
throw_unsup_format!(
|
||||
"called pthread_mutex_unlock on an unsupported type of mutex"
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -581,15 +565,14 @@ fn pthread_mutex_unlock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx,
|
||||
fn pthread_mutex_destroy(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
// Reading the field also has the side-effect that we detect double-`destroy`
|
||||
// since we make the field unint below.
|
||||
let id = mutex_get_id(this, mutex_op)?;
|
||||
|
||||
if this.mutex_is_locked(id) {
|
||||
throw_ub_format!("destroyed a locked mutex");
|
||||
}
|
||||
|
||||
// Destroying an uninit pthread_mutex is UB, so check to make sure it's not uninit.
|
||||
mutex_get_id(this, mutex_op)?;
|
||||
|
||||
// This might lead to false positives, see comment in pthread_mutexattr_destroy
|
||||
this.write_uninit(
|
||||
&this.deref_pointer_as(mutex_op, this.libc_ty_layout("pthread_mutex_t"))?,
|
||||
@ -691,15 +674,14 @@ fn pthread_rwlock_unlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx
|
||||
fn pthread_rwlock_destroy(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
// Reading the field also has the side-effect that we detect double-`destroy`
|
||||
// since we make the field unint below.
|
||||
let id = rwlock_get_id(this, rwlock_op)?;
|
||||
|
||||
if this.rwlock_is_locked(id) {
|
||||
throw_ub_format!("destroyed a locked rwlock");
|
||||
}
|
||||
|
||||
// Destroying an uninit pthread_rwlock is UB, so check to make sure it's not uninit.
|
||||
rwlock_get_id(this, rwlock_op)?;
|
||||
|
||||
// This might lead to false positives, see comment in pthread_mutexattr_destroy
|
||||
this.write_uninit(
|
||||
&this.deref_pointer_as(rwlock_op, this.libc_ty_layout("pthread_rwlock_t"))?,
|
||||
@ -789,11 +771,15 @@ fn pthread_cond_init(
|
||||
} else {
|
||||
condattr_get_clock_id(this, attr_op)?
|
||||
};
|
||||
let clock_id = cond_translate_clock_id(this, clock_id)?;
|
||||
|
||||
// Write 0 to use the same code path as the static initializers.
|
||||
cond_reset_id(this, cond_op)?;
|
||||
|
||||
cond_set_clock_id(this, cond_op, clock_id)?;
|
||||
let cond = this.deref_pointer(cond_op)?;
|
||||
let address = cond.ptr().addr().bytes();
|
||||
this.condvar_create(
|
||||
&cond,
|
||||
cond_id_offset(this)?,
|
||||
Some(Box::new(AdditionalCondData { address, clock_id })),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -848,7 +834,10 @@ fn pthread_cond_timedwait(
|
||||
let mutex_id = mutex_get_id(this, mutex_op)?;
|
||||
|
||||
// Extract the timeout.
|
||||
let clock_id = cond_get_clock_id(this, cond_op)?;
|
||||
let clock_id = this
|
||||
.condvar_get_data::<AdditionalCondData>(id)
|
||||
.expect("additional data should always be present for pthreads")
|
||||
.clock_id;
|
||||
let duration = match this
|
||||
.read_timespec(&this.deref_pointer_as(abstime_op, this.libc_ty_layout("timespec"))?)?
|
||||
{
|
||||
@ -859,13 +848,12 @@ fn pthread_cond_timedwait(
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
let timeout_clock = if is_cond_clock_realtime(this, clock_id) {
|
||||
this.check_no_isolation("`pthread_cond_timedwait` with `CLOCK_REALTIME`")?;
|
||||
TimeoutClock::RealTime
|
||||
} else if clock_id == this.eval_libc_i32("CLOCK_MONOTONIC") {
|
||||
TimeoutClock::Monotonic
|
||||
} else {
|
||||
throw_unsup_format!("unsupported clock id: {}", clock_id);
|
||||
let timeout_clock = match clock_id {
|
||||
ClockId::Realtime => {
|
||||
this.check_no_isolation("`pthread_cond_timedwait` with `CLOCK_REALTIME`")?;
|
||||
TimeoutClock::RealTime
|
||||
}
|
||||
ClockId::Monotonic => TimeoutClock::Monotonic,
|
||||
};
|
||||
|
||||
this.condvar_wait(
|
||||
@ -883,15 +871,13 @@ fn pthread_cond_timedwait(
|
||||
fn pthread_cond_destroy(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
// Reading the field also has the side-effect that we detect double-`destroy`
|
||||
// since we make the field unint below.
|
||||
let id = cond_get_id(this, cond_op)?;
|
||||
if this.condvar_is_awaited(id) {
|
||||
throw_ub_format!("destroying an awaited conditional variable");
|
||||
}
|
||||
|
||||
// Destroying an uninit pthread_cond is UB, so check to make sure it's not uninit.
|
||||
cond_get_id(this, cond_op)?;
|
||||
cond_get_clock_id(this, cond_op)?;
|
||||
|
||||
// This might lead to false positives, see comment in pthread_mutexattr_destroy
|
||||
this.write_uninit(&this.deref_pointer_as(cond_op, this.libc_ty_layout("pthread_cond_t"))?)?;
|
||||
// FIXME: delete interpreter state associated with this condvar.
|
||||
|
@ -10,9 +10,10 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
// Windows sync primitives are pointer sized.
|
||||
// We only use the first 4 bytes for the id.
|
||||
|
||||
fn init_once_get_id(&mut self, init_once_op: &OpTy<'tcx>) -> InterpResult<'tcx, InitOnceId> {
|
||||
fn init_once_get_id(&mut self, init_once_ptr: &OpTy<'tcx>) -> InterpResult<'tcx, InitOnceId> {
|
||||
let this = self.eval_context_mut();
|
||||
this.init_once_get_or_create_id(init_once_op, this.windows_ty_layout("INIT_ONCE"), 0)
|
||||
let init_once = this.deref_pointer(init_once_ptr)?;
|
||||
this.init_once_get_or_create_id(&init_once, 0)
|
||||
}
|
||||
|
||||
/// Returns `true` if we were succssful, `false` if we would block.
|
||||
|
@ -172,6 +172,7 @@ dependencies = [
|
||||
name = "miri-test-deps"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"getrandom 0.1.16",
|
||||
"getrandom 0.2.15",
|
||||
"libc",
|
||||
|
@ -11,6 +11,7 @@ edition = "2021"
|
||||
# all dependencies (and their transitive ones) listed here can be used in `tests/`.
|
||||
libc = "0.2"
|
||||
num_cpus = "1.10.1"
|
||||
cfg-if = "1"
|
||||
|
||||
getrandom_01 = { package = "getrandom", version = "0.1" }
|
||||
getrandom_02 = { package = "getrandom", version = "0.2", features = ["js"] }
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ only-target-darwin
|
||||
//@only-target: darwin
|
||||
|
||||
use std::cell::UnsafeCell;
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
error: abnormal termination: called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread
|
||||
--> $DIR/apple_os_unfair_lock_assert_not_owner.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.rs:LL:CC
|
||||
|
|
||||
LL | libc::os_unfair_lock_assert_not_owner(lock.get());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread
|
||||
|
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/apple_os_unfair_lock_assert_not_owner.rs:LL:CC
|
||||
= note: inside `main` at tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ only-target-darwin
|
||||
//@only-target: darwin
|
||||
|
||||
use std::cell::UnsafeCell;
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
error: abnormal termination: called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread
|
||||
--> $DIR/apple_os_unfair_lock_assert_owner.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.rs:LL:CC
|
||||
|
|
||||
LL | libc::os_unfair_lock_assert_owner(lock.get());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread
|
||||
|
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/apple_os_unfair_lock_assert_owner.rs:LL:CC
|
||||
= note: inside `main` at tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ only-target-darwin
|
||||
//@only-target: darwin
|
||||
|
||||
use std::cell::UnsafeCell;
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
error: abnormal termination: attempted to lock an os_unfair_lock that is already locked by the current thread
|
||||
--> $DIR/apple_os_unfair_lock_reentrant.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.rs:LL:CC
|
||||
|
|
||||
LL | libc::os_unfair_lock_lock(lock.get());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to lock an os_unfair_lock that is already locked by the current thread
|
||||
|
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/apple_os_unfair_lock_reentrant.rs:LL:CC
|
||||
= note: inside `main` at tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ only-target-darwin
|
||||
//@only-target: darwin
|
||||
|
||||
use std::cell::UnsafeCell;
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
error: abnormal termination: attempted to unlock an os_unfair_lock not owned by the current thread
|
||||
--> $DIR/apple_os_unfair_lock_unowned.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.rs:LL:CC
|
||||
|
|
||||
LL | libc::os_unfair_lock_unlock(lock.get());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to unlock an os_unfair_lock not owned by the current thread
|
||||
|
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/apple_os_unfair_lock_unowned.rs:LL:CC
|
||||
= note: inside `main` at tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
|
||||
/// Test that destroying a pthread_cond twice fails, even without a check for number validity
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
|
||||
--> $DIR/libc_pthread_cond_double_destroy.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs:LL:CC
|
||||
|
|
||||
LL | libc::pthread_cond_destroy(cond.as_mut_ptr());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
|
||||
@ -7,7 +7,7 @@ LL | libc::pthread_cond_destroy(cond.as_mut_ptr());
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/libc_pthread_cond_double_destroy.rs:LL:CC
|
||||
= note: inside `main` at tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -0,0 +1,20 @@
|
||||
error: Undefined Behavior: pthread_cond_t can't be moved after first use
|
||||
--> tests/fail-dep/concurrency/libc_pthread_cond_move.rs:LL:CC
|
||||
|
|
||||
LL | libc::pthread_cond_destroy(cond2.as_mut_ptr());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pthread_cond_t can't be moved after first use
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `check` at tests/fail-dep/concurrency/libc_pthread_cond_move.rs:LL:CC
|
||||
note: inside `main`
|
||||
--> tests/fail-dep/concurrency/libc_pthread_cond_move.rs:LL:CC
|
||||
|
|
||||
LL | check()
|
||||
| ^^^^^^^
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
@ -0,0 +1,37 @@
|
||||
//@revisions: static_initializer init
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
|
||||
/// Test that moving a pthread_cond between uses fails.
|
||||
|
||||
fn main() {
|
||||
check()
|
||||
}
|
||||
|
||||
#[cfg(init)]
|
||||
fn check() {
|
||||
unsafe {
|
||||
use core::mem::MaybeUninit;
|
||||
let mut cond = MaybeUninit::<libc::pthread_cond_t>::uninit();
|
||||
|
||||
libc::pthread_cond_init(cond.as_mut_ptr(), std::ptr::null());
|
||||
|
||||
// move pthread_cond_t
|
||||
let mut cond2 = cond;
|
||||
|
||||
libc::pthread_cond_destroy(cond2.as_mut_ptr()); //~[init] ERROR: pthread_cond_t can't be moved after first use
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(static_initializer)]
|
||||
fn check() {
|
||||
unsafe {
|
||||
let mut cond = libc::PTHREAD_COND_INITIALIZER;
|
||||
|
||||
libc::pthread_cond_signal(&mut cond as *mut _);
|
||||
|
||||
// move pthread_cond_t
|
||||
let mut cond2 = cond;
|
||||
|
||||
libc::pthread_cond_destroy(&mut cond2 as *mut _); //~[static_initializer] ERROR: pthread_cond_t can't be moved after first use
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
error: Undefined Behavior: pthread_cond_t can't be moved after first use
|
||||
--> tests/fail-dep/concurrency/libc_pthread_cond_move.rs:LL:CC
|
||||
|
|
||||
LL | libc::pthread_cond_destroy(&mut cond2 as *mut _);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pthread_cond_t can't be moved after first use
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `check` at tests/fail-dep/concurrency/libc_pthread_cond_move.rs:LL:CC
|
||||
note: inside `main`
|
||||
--> tests/fail-dep/concurrency/libc_pthread_cond_move.rs:LL:CC
|
||||
|
|
||||
LL | check()
|
||||
| ^^^^^^^
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
@ -1,5 +1,5 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target-apple: Our macOS condattr don't have any fields so we do not notice this.
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
//@ignore-target: apple # Our macOS condattr don't have any fields so we do not notice this.
|
||||
|
||||
/// Test that destroying a pthread_condattr twice fails, even without a check for number validity
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
|
||||
--> $DIR/libc_pthread_condattr_double_destroy.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs:LL:CC
|
||||
|
|
||||
LL | libc::pthread_condattr_destroy(attr.as_mut_ptr());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
|
||||
@ -7,7 +7,7 @@ LL | libc::pthread_condattr_destroy(attr.as_mut_ptr());
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/libc_pthread_condattr_double_destroy.rs:LL:CC
|
||||
= note: inside `main` at tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
//@error-in-other-file: the main thread terminated without waiting for all remaining threads
|
||||
|
||||
// Check that we terminate the program when the main thread terminates.
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
//~^ERROR: calling a function with more arguments than it expected
|
||||
|
||||
//! The thread function must have exactly one argument.
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
//~^ERROR: calling a function with fewer arguments than it requires
|
||||
|
||||
//! The thread function must have exactly one argument.
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
|
||||
// Joining a detached thread is undefined behavior.
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: Undefined Behavior: trying to join a detached thread
|
||||
--> $DIR/libc_pthread_join_detached.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_join_detached.rs:LL:CC
|
||||
|
|
||||
LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached thread
|
||||
@ -7,7 +7,7 @@ LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0);
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/libc_pthread_join_detached.rs:LL:CC
|
||||
= note: inside `main` at tests/fail-dep/concurrency/libc_pthread_join_detached.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
|
||||
// Joining an already joined thread is undefined behavior.
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: Undefined Behavior: trying to join an already joined thread
|
||||
--> $DIR/libc_pthread_join_joined.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_join_joined.rs:LL:CC
|
||||
|
|
||||
LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join an already joined thread
|
||||
@ -7,7 +7,7 @@ LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0);
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/libc_pthread_join_joined.rs:LL:CC
|
||||
= note: inside `main` at tests/fail-dep/concurrency/libc_pthread_join_joined.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
|
||||
// Joining the main thread is undefined behavior.
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: Undefined Behavior: trying to join a detached thread
|
||||
--> $DIR/libc_pthread_join_main.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_join_main.rs:LL:CC
|
||||
|
|
||||
LL | assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached thread
|
||||
@ -7,7 +7,7 @@ LL | assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0);
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE on thread `unnamed-ID`:
|
||||
= note: inside closure at $DIR/libc_pthread_join_main.rs:LL:CC
|
||||
= note: inside closure at tests/fail-dep/concurrency/libc_pthread_join_main.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
|
||||
// Joining the same thread from multiple threads is undefined behavior.
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: Undefined Behavior: trying to join an already joined thread
|
||||
--> $DIR/libc_pthread_join_multiple.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_join_multiple.rs:LL:CC
|
||||
|
|
||||
LL | ... assert_eq!(libc::pthread_join(native_copy, ptr::null_mut()), 0);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join an already joined thread
|
||||
@ -7,7 +7,7 @@ LL | ... assert_eq!(libc::pthread_join(native_copy, ptr::null_mut()), 0);
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE on thread `unnamed-ID`:
|
||||
= note: inside closure at $DIR/libc_pthread_join_multiple.rs:LL:CC
|
||||
= note: inside closure at tests/fail-dep/concurrency/libc_pthread_join_multiple.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
// We are making scheduler assumptions here.
|
||||
//@compile-flags: -Zmiri-preemption-rate=0
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: Undefined Behavior: trying to join itself
|
||||
--> $DIR/libc_pthread_join_self.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_join_self.rs:LL:CC
|
||||
|
|
||||
LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join itself
|
||||
@ -7,7 +7,7 @@ LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0);
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE on thread `unnamed-ID`:
|
||||
= note: inside closure at $DIR/libc_pthread_join_self.rs:LL:CC
|
||||
= note: inside closure at tests/fail-dep/concurrency/libc_pthread_join_self.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
//
|
||||
// Check that if we pass NULL attribute, then we get the default mutex type.
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: Undefined Behavior: trying to acquire already locked default mutex
|
||||
--> $DIR/libc_pthread_mutex_NULL_deadlock.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs:LL:CC
|
||||
|
|
||||
LL | libc::pthread_mutex_lock(&mut mutex as *mut _);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to acquire already locked default mutex
|
||||
@ -7,7 +7,7 @@ LL | libc::pthread_mutex_lock(&mut mutex as *mut _);
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/libc_pthread_mutex_NULL_deadlock.rs:LL:CC
|
||||
= note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
//@error-in-other-file: deadlock
|
||||
|
||||
use std::cell::UnsafeCell;
|
||||
|
@ -1,11 +1,11 @@
|
||||
error: deadlock: the evaluated program deadlocked
|
||||
--> $DIR/libc_pthread_mutex_deadlock.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs:LL:CC
|
||||
|
|
||||
LL | assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _), 0);
|
||||
| ^ the evaluated program deadlocked
|
||||
|
|
||||
= note: BACKTRACE on thread `unnamed-ID`:
|
||||
= note: inside closure at $DIR/libc_pthread_mutex_deadlock.rs:LL:CC
|
||||
= note: inside closure at tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs:LL:CC
|
||||
|
||||
error: deadlock: the evaluated program deadlocked
|
||||
--> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
@ -18,7 +18,7 @@ LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
|
||||
= note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
= note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
note: inside `main`
|
||||
--> $DIR/libc_pthread_mutex_deadlock.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs:LL:CC
|
||||
|
|
||||
LL | / thread::spawn(move || {
|
||||
LL | | assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _), 0);
|
||||
|
@ -1,10 +1,11 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
//
|
||||
// Check that if we do not set the mutex type, it is the default.
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed();
|
||||
let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed();
|
||||
assert_eq!(libc::pthread_mutexattr_init(&mut mutexattr as *mut _), 0);
|
||||
let mut mutex: libc::pthread_mutex_t = std::mem::zeroed();
|
||||
assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0);
|
||||
assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: Undefined Behavior: trying to acquire already locked default mutex
|
||||
--> $DIR/libc_pthread_mutex_default_deadlock.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs:LL:CC
|
||||
|
|
||||
LL | libc::pthread_mutex_lock(&mut mutex as *mut _);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to acquire already locked default mutex
|
||||
@ -7,7 +7,7 @@ LL | libc::pthread_mutex_lock(&mut mutex as *mut _);
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/libc_pthread_mutex_default_deadlock.rs:LL:CC
|
||||
= note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: Undefined Behavior: destroyed a locked mutex
|
||||
--> $DIR/libc_pthread_mutex_destroy_locked.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_mutex_destroy_locked.rs:LL:CC
|
||||
|
|
||||
LL | libc::pthread_mutex_destroy(&mut mutex as *mut _);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ destroyed a locked mutex
|
||||
@ -7,7 +7,7 @@ LL | libc::pthread_mutex_destroy(&mut mutex as *mut _);
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/libc_pthread_mutex_destroy_locked.rs:LL:CC
|
||||
= note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_destroy_locked.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
|
||||
/// Test that destroying a pthread_mutex twice fails, even without a check for number validity
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
|
||||
--> $DIR/libc_pthread_mutex_double_destroy.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs:LL:CC
|
||||
|
|
||||
LL | libc::pthread_mutex_destroy(mutex.as_mut_ptr());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
|
||||
@ -7,7 +7,7 @@ LL | libc::pthread_mutex_destroy(mutex.as_mut_ptr());
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/libc_pthread_mutex_double_destroy.rs:LL:CC
|
||||
= note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: Undefined Behavior: pthread_mutex_t can't be moved after first use
|
||||
--> $DIR/libc_pthread_mutex_move.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_mutex_move.rs:LL:CC
|
||||
|
|
||||
LL | libc::pthread_mutex_lock(&mut m2 as *mut _);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pthread_mutex_t can't be moved after first use
|
||||
@ -7,9 +7,9 @@ LL | libc::pthread_mutex_lock(&mut m2 as *mut _);
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `check` at $DIR/libc_pthread_mutex_move.rs:LL:CC
|
||||
= note: inside `check` at tests/fail-dep/concurrency/libc_pthread_mutex_move.rs:LL:CC
|
||||
note: inside `main`
|
||||
--> $DIR/libc_pthread_mutex_move.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_mutex_move.rs:LL:CC
|
||||
|
|
||||
LL | check();
|
||||
| ^^^^^^^
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
//@revisions: static_initializer init
|
||||
|
||||
fn main() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: Undefined Behavior: pthread_mutex_t can't be moved after first use
|
||||
--> $DIR/libc_pthread_mutex_move.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_mutex_move.rs:LL:CC
|
||||
|
|
||||
LL | libc::pthread_mutex_unlock(&mut m2 as *mut _);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pthread_mutex_t can't be moved after first use
|
||||
@ -7,9 +7,9 @@ LL | libc::pthread_mutex_unlock(&mut m2 as *mut _);
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `check` at $DIR/libc_pthread_mutex_move.rs:LL:CC
|
||||
= note: inside `check` at tests/fail-dep/concurrency/libc_pthread_mutex_move.rs:LL:CC
|
||||
note: inside `main`
|
||||
--> $DIR/libc_pthread_mutex_move.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_mutex_move.rs:LL:CC
|
||||
|
|
||||
LL | check();
|
||||
| ^^^^^^^
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
|
@ -1,11 +1,11 @@
|
||||
error: deadlock: the evaluated program deadlocked
|
||||
--> $DIR/libc_pthread_mutex_normal_deadlock.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs:LL:CC
|
||||
|
|
||||
LL | libc::pthread_mutex_lock(&mut mutex as *mut _);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program deadlocked
|
||||
|
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/libc_pthread_mutex_normal_deadlock.rs:LL:CC
|
||||
= note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: Undefined Behavior: unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked by the current thread
|
||||
--> $DIR/libc_pthread_mutex_normal_unlock_unlocked.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_mutex_normal_unlock_unlocked.rs:LL:CC
|
||||
|
|
||||
LL | libc::pthread_mutex_unlock(&mut mutex as *mut _);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked by the current thread
|
||||
@ -7,7 +7,7 @@ LL | libc::pthread_mutex_unlock(&mut mutex as *mut _);
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/libc_pthread_mutex_normal_unlock_unlocked.rs:LL:CC
|
||||
= note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_normal_unlock_unlocked.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
|
||||
use std::cell::UnsafeCell;
|
||||
use std::sync::Arc;
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: Undefined Behavior: unlocked a default mutex that was not locked by the current thread
|
||||
--> $DIR/libc_pthread_mutex_wrong_owner.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.rs:LL:CC
|
||||
|
|
||||
LL | ...t_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unlocked a default mutex that was not locked by the current thread
|
||||
@ -7,7 +7,7 @@ LL | ...t_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0);
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE on thread `unnamed-ID`:
|
||||
= note: inside closure at $DIR/libc_pthread_mutex_wrong_owner.rs:LL:CC
|
||||
= note: inside closure at tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
|
||||
/// Test that destroying a pthread_mutexattr twice fails, even without a check for number validity
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
|
||||
--> $DIR/libc_pthread_mutexattr_double_destroy.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs:LL:CC
|
||||
|
|
||||
LL | libc::pthread_mutexattr_destroy(attr.as_mut_ptr());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
|
||||
@ -7,7 +7,7 @@ LL | libc::pthread_mutexattr_destroy(attr.as_mut_ptr());
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/libc_pthread_mutexattr_double_destroy.rs:LL:CC
|
||||
= note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
|
||||
fn main() {
|
||||
let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER);
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: Undefined Behavior: destroyed a locked rwlock
|
||||
--> $DIR/libc_pthread_rwlock_destroy_read_locked.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_read_locked.rs:LL:CC
|
||||
|
|
||||
LL | libc::pthread_rwlock_destroy(rw.get());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ destroyed a locked rwlock
|
||||
@ -7,7 +7,7 @@ LL | libc::pthread_rwlock_destroy(rw.get());
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/libc_pthread_rwlock_destroy_read_locked.rs:LL:CC
|
||||
= note: inside `main` at tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_read_locked.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
|
||||
fn main() {
|
||||
let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER);
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: Undefined Behavior: destroyed a locked rwlock
|
||||
--> $DIR/libc_pthread_rwlock_destroy_write_locked.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_write_locked.rs:LL:CC
|
||||
|
|
||||
LL | libc::pthread_rwlock_destroy(rw.get());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ destroyed a locked rwlock
|
||||
@ -7,7 +7,7 @@ LL | libc::pthread_rwlock_destroy(rw.get());
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/libc_pthread_rwlock_destroy_write_locked.rs:LL:CC
|
||||
= note: inside `main` at tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_write_locked.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
|
||||
/// Test that destroying a pthread_rwlock twice fails, even without a check for number validity
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
|
||||
--> $DIR/libc_pthread_rwlock_double_destroy.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs:LL:CC
|
||||
|
|
||||
LL | libc::pthread_rwlock_destroy(&mut lock);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
|
||||
@ -7,7 +7,7 @@ LL | libc::pthread_rwlock_destroy(&mut lock);
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/libc_pthread_rwlock_double_destroy.rs:LL:CC
|
||||
= note: inside `main` at tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
|
||||
fn main() {
|
||||
let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER);
|
||||
|
@ -1,11 +1,11 @@
|
||||
error: deadlock: the evaluated program deadlocked
|
||||
--> $DIR/libc_pthread_rwlock_read_write_deadlock_single_thread.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.rs:LL:CC
|
||||
|
|
||||
LL | libc::pthread_rwlock_wrlock(rw.get());
|
||||
| ^ the evaluated program deadlocked
|
||||
|
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/libc_pthread_rwlock_read_write_deadlock_single_thread.rs:LL:CC
|
||||
= note: inside `main` at tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
|
||||
use std::cell::UnsafeCell;
|
||||
use std::sync::Arc;
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: Undefined Behavior: unlocked an rwlock that was not locked by the active thread
|
||||
--> $DIR/libc_pthread_rwlock_read_wrong_owner.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.rs:LL:CC
|
||||
|
|
||||
LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), 0);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unlocked an rwlock that was not locked by the active thread
|
||||
@ -7,7 +7,7 @@ LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _),
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE on thread `unnamed-ID`:
|
||||
= note: inside closure at $DIR/libc_pthread_rwlock_read_wrong_owner.rs:LL:CC
|
||||
= note: inside closure at tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
|
||||
fn main() {
|
||||
let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER);
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: Undefined Behavior: unlocked an rwlock that was not locked by the active thread
|
||||
--> $DIR/libc_pthread_rwlock_unlock_unlocked.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_rwlock_unlock_unlocked.rs:LL:CC
|
||||
|
|
||||
LL | libc::pthread_rwlock_unlock(rw.get());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unlocked an rwlock that was not locked by the active thread
|
||||
@ -7,7 +7,7 @@ LL | libc::pthread_rwlock_unlock(rw.get());
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/libc_pthread_rwlock_unlock_unlocked.rs:LL:CC
|
||||
= note: inside `main` at tests/fail-dep/concurrency/libc_pthread_rwlock_unlock_unlocked.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
//@error-in-other-file: deadlock
|
||||
|
||||
use std::cell::UnsafeCell;
|
||||
|
@ -1,11 +1,11 @@
|
||||
error: deadlock: the evaluated program deadlocked
|
||||
--> $DIR/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC
|
||||
|
|
||||
LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0);
|
||||
| ^ the evaluated program deadlocked
|
||||
|
|
||||
= note: BACKTRACE on thread `unnamed-ID`:
|
||||
= note: inside closure at $DIR/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC
|
||||
= note: inside closure at tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC
|
||||
|
||||
error: deadlock: the evaluated program deadlocked
|
||||
--> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
@ -18,7 +18,7 @@ LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
|
||||
= note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
= note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
note: inside `main`
|
||||
--> $DIR/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC
|
||||
|
|
||||
LL | / thread::spawn(move || {
|
||||
LL | | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0);
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
|
||||
fn main() {
|
||||
let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER);
|
||||
|
@ -1,11 +1,11 @@
|
||||
error: deadlock: the evaluated program deadlocked
|
||||
--> $DIR/libc_pthread_rwlock_write_read_deadlock_single_thread.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.rs:LL:CC
|
||||
|
|
||||
LL | libc::pthread_rwlock_rdlock(rw.get());
|
||||
| ^ the evaluated program deadlocked
|
||||
|
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/libc_pthread_rwlock_write_read_deadlock_single_thread.rs:LL:CC
|
||||
= note: inside `main` at tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
//@error-in-other-file: deadlock
|
||||
|
||||
use std::cell::UnsafeCell;
|
||||
|
@ -1,11 +1,11 @@
|
||||
error: deadlock: the evaluated program deadlocked
|
||||
--> $DIR/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC
|
||||
|
|
||||
LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0);
|
||||
| ^ the evaluated program deadlocked
|
||||
|
|
||||
= note: BACKTRACE on thread `unnamed-ID`:
|
||||
= note: inside closure at $DIR/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC
|
||||
= note: inside closure at tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC
|
||||
|
||||
error: deadlock: the evaluated program deadlocked
|
||||
--> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
@ -18,7 +18,7 @@ LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
|
||||
= note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
= note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
note: inside `main`
|
||||
--> $DIR/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC
|
||||
|
|
||||
LL | / thread::spawn(move || {
|
||||
LL | | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0);
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
|
||||
fn main() {
|
||||
let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER);
|
||||
|
@ -1,11 +1,11 @@
|
||||
error: deadlock: the evaluated program deadlocked
|
||||
--> $DIR/libc_pthread_rwlock_write_write_deadlock_single_thread.rs:LL:CC
|
||||
--> tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.rs:LL:CC
|
||||
|
|
||||
LL | libc::pthread_rwlock_wrlock(rw.get());
|
||||
| ^ the evaluated program deadlocked
|
||||
|
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/libc_pthread_rwlock_write_write_deadlock_single_thread.rs:LL:CC
|
||||
= note: inside `main` at tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//@ignore-target-windows: No pthreads on Windows
|
||||
//@ignore-target: windows # No pthreads on Windows
|
||||
|
||||
use std::cell::UnsafeCell;
|
||||
use std::sync::Arc;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user