-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Span's From<&[T]>
and From<&[T; N]>
facilitate UB
#33
Comments
From<&[T]>
and From<&[T; N]>
encourage UBFrom<&[T]>
and From<&[T; N]>
facilitate UB
These functions have been deprecated to the extent possible is v4.4.2. They will be removed in v5. |
The README still show the old way: https://github.com/SFBdragon/talc?tab=readme-ov-file#setup What's the new way to create a global allocator? |
Hey, thanks for reaching out. I naively hoped that wouldn't confuse too many people before 1.83 lands. I missed it when pushing out the update. Here's the currently recommended way to do that exact thing https://github.com/SFBdragon/talc/blob/master/stable_examples/examples/std_global_allocator.rs #[global_allocator]
static ALLOCATOR: Talck<spin::Mutex<()>, ClaimOnOom> = Talc::new(unsafe {
ClaimOnOom::new(Span::from_array(addr_of!(ARENA) as *mut [u8; 10000]))
}).lock(); Either (Aiming to overhaul the READMEs and documentation situation before too long. Just finished exams so there'll be more movement over the next few weeks.) |
Thank you! It works. Clippy suggested using Span::from_array(addr_of!(ARENA).cast_mut()) https://rust-lang.github.io/rust-clippy/master/index.html#ptr_cast_constness |
No problem! Ah, that I got an email about a reply but I can't see it anywhere. Maybe you intentionally deleted it but I'll quickly reply anyway in case it's nonetheless useful
Instructions for WASM stuff is here, but this is documenting the old method as well. https://github.com/SFBdragon/talc/blob/master/talc/README_WASM.md If arena allocation is preferable to dynamic heap growth, then use #[global_allocator]
static ALLOCATOR: talc::Talck<talc::locking::AssumeUnlockable, talc::ClaimOnOom> = {
static mut MEMORY: [u8; 0x1000000] = [0; 0x1000000];
let span = talc::Span::from_array(std::ptr::addr_of!(MEMORY).cast_mut());
talc::Talc::new(unsafe { talc::ClaimOnOom::new(span) }).lock()
}; I don't like |
Yeah, I removed my comment when I realized that old code used unlockable and the new one that I copied from your example uses the lock, hence the size difference. I switched back to unlockable because Firefly Zero runs the games in a single thread. Later, I found the wasm usage instructions and switched to If you're interested, this is the PR: |
Maybe try writing an allocator that forwards allocation requests to a real allocator (like talc) but does something else if it detects a massive allocation request. (Alternatively, make the fake allocator log allocations so you have a better idea of what to look for using // This is just a rough sketch
pub struct InspectorAlloc { pub talc: TalckWasm... }
#[global_allocator]
static MIDDLE_MAN_ALLOC: InspectorAlloc = ...;
impl GlobalAlloc for InspectorAlloc {
fn alloc(&self, layout: Layout) -> *mut u8 {
if layout.size > 10 * 64 * 1024 {
// panic with backtrace, or log stuff like allocation sizes, or ???
}
self.talc.alloc(layout)
}
fn dealloc(&self, ptr: *mut u8, layout: Layout) { self.talc.dealloc(ptr, layout); }
} Might help narrow the issue down. I keep writing types like this or modifying |
Thank you! I gave it a spin and found out that the biggest single allocation that happens is just 2048 bytes. So, no, it's not an allocation. Even more, this memory is allocated not dynamically but statically, the wasm binary specifies that the memory must be at least 17 pages by default. So, I think there might be a rust/llvm flag for that. For posterity, this is the complete implementation of the allocator: pub struct InspectorAlloc {
pub talc: talc::TalckWasm,
}
#[global_allocator]
static ALLOCATOR: InspectorAlloc = InspectorAlloc {
talc: unsafe { talc::TalckWasm::new_global() },
};
unsafe impl GlobalAlloc for InspectorAlloc {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
assert!(layout.size() < 2 * 1024, "{}", layout.size());
self.talc.alloc(layout)
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
self.talc.dealloc(ptr, layout);
}
} |
I've calculated the total allocations, it dynamically allocates just over 7 Kb. And the data section isn't that big. So it's certainly not a problem with talc. |
Try passing something like |
It works! Thank you. I even found an example in WASM-4: |
Dereferencing
&x as *const _ as *mut _
is UB.This means some of the API surface of Talc is genuinely problematic, particularly the
From
implementations on Span for&[T]
and&[T; N]
. Not UB in itself (and technicallyTalc
's docs on unsafety cover this), but it makes UB needlessly easy to invoke.Here, the .into() is doing the legwork in hiding the issue as per the above. MIRI indeed takes issue with it.
These
From
implementations should be removed. This is a breaking change though and will necessitate a major version bump.The text was updated successfully, but these errors were encountered: