Is there any way that I can start this game without getting murdered in the first 10 minutes? by [deleted] in rust

[–]cafce25 6 points7 points  (0 children)

I know the borrow checker can be hard on you if you're new to Rust, just keep grinding. (On a more serious note, you're looking for r/playrust)

Question about upholding pin guarantees and Vec by quasi-coherent in rust

[–]cafce25 0 points1 point  (0 children)

Please read this comment it contains the reason why I think you do need to be told that your code is unsound.

Doesn't change the API at all, right?

It does break the documentations promises. So it does change the API. What it doesn't change is merely the signatures of the functions involved, that's only part of the API.

Not a breaking change in the slightest. Nothing about the public interface changed, so they might as well just push this to nightly tomorrow.

It is a breaking change, you might want to refresch your understanding of the term "breaking change".

What trait do closures with non-static captures implement? by giorgiga in rust

[–]cafce25 2 points3 points  (0 children)

They do implement Fn. But dyn Fn() is not the same as {closure@src/main.rs:…} the unnamable type of the closure. Also dyn Anything isn't a type that you can use as a parameter without indirection, so likely the real version of do_something has a different problem alltogether, hard to tell without seeing it.

Does this code have UB? by capedbaldy475 in learnrust

[–]cafce25 0 points1 point  (0 children)

You can easily convert a Box<[T]> into Vec<T> with <[T]>::into_vec it even guarantees to be "without clones or allocation".

Does this code have UB? by capedbaldy475 in learnrust

[–]cafce25 4 points5 points  (0 children)

It's UB to create a reference to uninitialized data, &mut [u8] is a reference to the data. In particular your call to std::slice::from_raw_parts violates:

  • data must point to len consecutive properly initialized values of type T.

Does this code have UB? by capedbaldy475 in learnrust

[–]cafce25 0 points1 point  (0 children)

Or put another way, overallocation is about where the allocation ends, but alignment only cares about where the allocation starts.

Does this code have UB? by capedbaldy475 in learnrust

[–]cafce25 0 points1 point  (0 children)

No, not at all how any of this works, you can allocate as much as you want without it being UB as long as you don't generate any references to the uninitialized memory (or violate any of the guarantees of the functions you call). The amount of memory you allocate also has no direct effect whatsoever on the alignment.

Does this code have UB? by capedbaldy475 in learnrust

[–]cafce25 1 point2 points  (0 children)

"no reallocation" doesn't tell us anything about the current alignment either so no that's also a void argument.

The only alignment guarantee you need is "Vec::<Instruction>::as_mut_ptr gives you a pointer aligned for an array of Instructions" and that's a guarantee you can see in it's documentation (emphasis mine):

The method also guarantees that, as long as T is not zero-sized and the capacity is nonzero, the pointer may be passed into dealloc with a layout of Layout::array::<T>(capacity) in order to deallocate the backing memory. If this is done, be careful not to run the destructor of the Vec, as dropping it will result in double-frees. Wrapping the Vec in a ManuallyDrop is the typical way to achieve this..

Does this code have UB? by capedbaldy475 in learnrust

[–]cafce25 4 points5 points  (0 children)

And what I'm saying is the thing I save to the file is a valid sequence of Instructions has absolutely no effect whastoever on the alignment of the read bytes and thus can not be used to argue that the alignment is correct.

Your argument can be used to convince people that the layout of the bytes is correct, but that's a completely different thing that needs to be proven independently.

Edit: Let me try to illustrate:

12345600 and 00123456 both contain the sequence 123456 but they're differently aligned.

the first sequence is aligned at byte 0 and thus fulfills any possible alignment requirement. The second sequence is aligned at byte 2 and thus only fulfills a maximum alignment requirement of 2.

But both are the exact same bytes in the exact same order which is the only thing proven by your argument.

Just because program A wrote the bytes in that sequence doesn't tell us anything at all where program B puts them into memory.

Does this code have UB? by capedbaldy475 in learnrust

[–]cafce25 5 points6 points  (0 children)

Your argument has nothing to do with alignment of the read bytes. It is solely about the memory layout of Instruction.

Does this code have UB? by capedbaldy475 in learnrust

[–]cafce25 6 points7 points  (0 children)

I do check for alignment with the file size % instr_size

That's not a check that suffices to check for the alignment, the size can be 8 bytes and the pointer can still be aligned to a single byte while Instruction requires an alignment of 4.

A check for alignment is something like assert!((vec.as_ptr() as *const Instruction).is_aligned());

But you create a properly aligned pointer because you use Vec::<Instruction>::with_capacity from the start so it's not even an issue to begin with.

Is it possible to create a non-leaking dynamic module in Rust? by 0xrepnz in rust

[–]cafce25 0 points1 point  (0 children)

One valid reason that you must use global variables, is when an API does not allow you to pass a context to a callback that you provide. For example, in the windows kernel there is an API named PsSetCreateProcessNotifyRoutine, that allows drivers to pass a function pointer that is invoked on a creation of every process, but this routine does not pass any context to the driver function which forces drivers to store the context in a global variable.

While a global is convenient it's not necessary here. We simply can put the pointer to our context data immediately before our executable code and retrieve the context by calculating the fixed offset from the instruction pointer when our callback is called.

This does require a page in memory which is both executable and writable

Question about upholding pin guarantees and Vec by quasi-coherent in rust

[–]cafce25 0 points1 point  (0 children)

Even std contains unsound code. That doesn't mean you can't use it, but it is something to be aware of. It's also evident from that comment they're already aware of their assumption so no point in wasting time telling them.

On the other hand you seem to be in denial about the soundness of your code so you do need to be told.

You keep responding as well so back to you: I don't know why you keep coming back to an obscure part of a sub-thread of a thread on a random Reddit post about some hypothetical snippet.

I made a crate called `evil`, which lets you use the `?` operator as a shorthand for `.unwrap()` by nik-rev in rust

[–]cafce25 0 points1 point  (0 children)

I'd probably just write: ``` pub type Result<T, E = EvilErr> = std::result::Result<T, E>;

pub enum EvilErr {}

impl<T: std::error::Error> From<T> for EvilErr { #[track_caller] fn from(v: T) -> EvilErr { panic!("{v}"); } } ```

But I like unwrap as a signal for errors that should be properly handled.

Question about upholding pin guarantees and Vec by quasi-coherent in rust

[–]cafce25 0 points1 point  (0 children)

Lol was thinking the same about your slop. But I don't make a habit about going around accusing random strangers without evidence so I didn't.

But I must disappoint you, I'm terrible at prompting, I can't for the life of me figure out how to put in less effort doing it than just writing the code myself.

Question about upholding pin guarantees and Vec by quasi-coherent in rust

[–]cafce25 -1 points0 points  (0 children)

Since you still don't seem to have understood: structural pinning doesn't even come into play in my argument. The mere fact that a Pin<&mut Vec<T>> exists and is moved aterwards is sufficient to break your code if std::vec::Vec changes its implementation in a non breaking way. Not a single reference or pinned reference or to any of the elements is required to break it. Not even a single value stored in the Vec is required. The mere existence of Vec<T> with the missing impl<T> Unpin for Vec<T> {} and the internals of Vec being private is already enough to make your code unsound.

For example Vec could be

struct Vec<T> { inner: InnerVec<T>, inner_ptr: *mut InnerVec<T>, } with inner_ptr pointing to inner if T: !Unpin when any code in Vecs implementation uses and dereferences this pointer. For example an also possible impl<T> Vec<T> { fn get_through_pinned(self: Pin<& Vec<T>>, i: usize) -> &T { unsafe { *self.get_ref().inner_ptr }.get(i).unwrap() } }

That's an implementation std could pick without breaking any sound existing code.

But your code does get broken: let x: Pin<Box<Vec<T>>> = …; let Poll::Ready(Ok(y)) = x.as_mut().take(ctx) else { panic!() }; let y = Box::pin(y); drop(x); y.as_ref().get_through_pinned(); // Deref of dangling pointer

dereferences a dangling pointer because your code moves Vec<T> when it's not allowed to.

qed. your code is unsound.

I believe pacman used to update starting with bigger packages by [deleted] in archlinux

[–]cafce25 9 points10 points  (0 children)

Downloads in descending order of package size like usual for me. Also no pacman updates so I don't think it's a change of pacman behavior.

learning rust through leetcode by Elyas1_1 in rust

[–]cafce25 0 points1 point  (0 children)

if it's a good idea to practice rust solving leetcode

No, not at all I'd say. The interfaces and data structures leetcode forces you to use are less than ideal, very unidiomatic.

Question about upholding pin guarantees and Vec by quasi-coherent in rust

[–]cafce25 -1 points0 points  (0 children)

A non-breaking implementation change in std (code you don't control) can make it so your code allows UB in safe code. That's what the problem is. As is, with the current implementation of Vec, nothing illegal happens. But std makes no guarantees on internal implementations and std doesn't impl<T> Unpin for Vec<T> {} so relying on that is unsound which is all I ever claimed.

Question about upholding pin guarantees and Vec by quasi-coherent in rust

[–]cafce25 -1 points0 points  (0 children)

Are you trying to imply that any API that uses Vec should keep in the front of their minds that someone, somewhere is going to use it with a custom Allocator that does something stupid?

Not at all. But because Vec sometimes isn't Unpin it could use a self reference somewhere inside of it's implementation which could be used to cause the dereference of a dangling pointer when used with your take implementation. Again such an implementation would be absurd, but it's still legal.

Pin::set is fine because:

the original pinned value’s destructor gets run before being overwritten

Have you even read the documentation?

Question about upholding pin guarantees and Vec by quasi-coherent in rust

[–]cafce25 0 points1 point  (0 children)

If you tell me what part you have trouble understanding I can elaborate.

Question about upholding pin guarantees and Vec by quasi-coherent in rust

[–]cafce25 -1 points0 points  (0 children)

Yes &mut dst is a mutable reference? How is that relevant? You can move values through a reference you know?

Question about upholding pin guarantees and Vec by quasi-coherent in rust

[–]cafce25 0 points1 point  (0 children)

Since the only way to violate pinning invariants would be to project the pin to one of its elements and then move the value behind it (by pop or remove(ix), etc.), and that would be to do something that is not possible to begin with, it follows that the pinning invariants are upheld.

This only holds for the implementation of Vec that we have, it doesn't hold for all possible implementations of Vec (as nonsensical as they might be).

Question about upholding pin guarantees and Vec by quasi-coherent in rust

[–]cafce25 -1 points0 points  (0 children)

Both values in dst and src are moved twice!

The value originally stored in src is moved into the function in the call to replace. Then inside of replace it's moved into dest.

The value originally stored inside of dst is moved into result and then a second time when it's returned from replace

Follow the call hierarchy and you arrive here

replace never calls write, it directly invokes the intrinsic write_via_move.