Is ManuallyDrop<Box<T>> with mem::uninitialized defined behavior? - rust

I have an array with [ManuallyDrop<Box<T>>] which is filled lazily. To realize this, I "initialize" the array with ManuallyDrop::new(mem::uninitialized()).
Is this well-defined behavior as long as I only call ManuallyDrop::drop() on initialized elements?

Provided that you do not read from uninitialized memory or create pointers to it, then this should not be UB.
You will need to do some careful bookkeeping to disallow access to uninitialized items, and only drop initialized ones. Adding a new item where there is uninitialized memory needs to be done with ptr::write(), to avoid an invalid drop on the underlying memory. But if you overwrite an existing valid value, then you should not use ptr::write because you need that value to be correctly dropped.

Related

What happens to the memory that was 'moved into'?

Does rust drop the memory after move is used to reassign a value?
What happens to the string "aaa" in this example?
let mut s = String::from("aaa");
s = String::from("bbb");
I'm guessing that the "aaa" String is dropped - it makes sense, as it is not used anymore. However, I cannot find anything confirming this in the docs. (for example, the Book only provides an explanation of what happens when we assign a new value using move).
I'm trying to wrap my head around the rules Rust uses to ensure memory safety, but I cannot find an explicit rule of what happens in such a situation.
Yes, assignment to a variable will drop the value that is being replaced.
Not dropping the replaced value would be a disaster - since Drop is frequently used for deallocation and other cleanup, if the value wasn't dropped, you'd end up with all sorts of leaks.
Move semantics are implicit here. The data in s is initialized by moving from the String produced by String::from("bbb"). The original data stored in s is dropped by side-effect (the process of replacing it leaves it with no owner, so it's dropped as part of the operation).
Per the destructor documentation (emphasis added):
When an initialized variable or temporary goes out of scope, its destructor is run, or it is dropped. Assignment also runs the destructor of its left-hand operand, if it's initialized. If a variable has been partially initialized, only its initialized fields are dropped.

Point a pointer to local variable created within a function

Here is the code:
var timePointer *[]time.Time
func UpdateHolidayList() error {
//updating logic: pulling list of holidays from API
holidaySlice := make([]time.Time, 0)
//appending some holidays of type time.Time to holidaySlice
//now holidaySlice contains a few time.Time values
timePointer = &holidaySlice
return nil
}
func main() {
//run UpdateHoliday every 7 days
go func() {
for {
UpdateHoliday()
time.Sleep(7 * 3600 * time.Hour)
}
}()
}
I have 4 questions:
holidaySlice is a local variable, is it safe to point a (global) pointer to it?
Is this whole code multi-thread safe?
After pointing timePointer to holidaySlice, can I access the values via timePointer
(If answer to 3. is "yes") The holiday list is constantly changing, so holidaySlice will be different each update. Will the values accessed via timePointer change accordingly then?
holidaySlice is a local variable allocated on the heap. Any variable pointing to the same heap location can access the data structure at that location. Whether or not it is safe depends on how you access it. Even if holidaySlice was not explicitly allocated on the heap, once you make a global variable point to it, Go compiler would detect that it "escapes", so it would allocate that on the heap.
The code is not thread-safe. You are modifying a shared variable (the global variable) without any explicit synchronization, so there is no guarantee on when or if other goroutines will see the updates to that variable.
If you update the contents of the timePointer array without explicit synchronization, there is no guarantee on when or if other goroutines will see those updates. You have to use synchronization primitives like sync/Mutex to delimit read/write access to data structures that can be updated/read by multiple goroutines.
As long as your main does not end timePointer will have access to the pointer that holidaySlice creates - since its heap allocated, compiler will detect its escape and not free the memory.
Nope, absolutely not. Look at the sync package
Yes you can. Just remember to iterate using *timePointer instead of timePointer
It will change - but not accordingly. Since you have not done any synchronization - you have no defined way of knowing what data is stored at slice pointed to by timePointer when it is read.

How to free up the memory of objects removed from a vec?

If I have a vec of structs, calling vec.remove(index) will remove the struct stored in the vec at index index. However, the docs don't explicitly mention what happens to these removed objects. How do I ensure they're freed up?
If objects in rust are freed up when they go out of scope, what happens to these removed objects, since the vector might go out of scope, but the removed objects could be dangling in memory? The code for the Vec::remove(index) seems to be only offsetting the elements in the vector to overwrite the element being removed:
// Shift everything down to fill in that spot.
ptr::copy(ptr.offset(1), ptr, len - index - 1);
Vec::remove(i) copies the element out of the vector and shifts everything else down to fill the spot. It then returns that element to you. It is up to you to do whatever you want with that element. If you drop it, the object will be freed from memory, just like any other object:
vec.remove(i); // <- the element at index `i` is dropped and freed from memory

Placing a small object at the beggining of memory block

I need to store a object describing the memory details of a memory block allocated by sbrk(), at the beggining of the memory block itself.
for example:
metaData det();
void* alloc = sbrk(sizeof(det)+50000);
//a code piece to locate det at the beggining of alocate.
I am not allowed to use placement new, And not allowed to allocate memory using new/malloc etc.
I know that simply assigning it to the memory block would cause undefined behaviour.
I was thinking about using memcpy (i think that can cause problems as det is not dynamicly allocated).
Could assigning a pointer to the object at the beginning work (only if theres no other choise), or memcpy?
thanks.
I am not allowed to use placement new
Placement new is the only way to place an object in an existing block of memory.
[intro.object] An object is created by a definition, by a new-expression, when implicitly changing the active member of a union, or when a temporary object is created
You cannot make a definition to refer to an existing memory region, so that's out.
There's no union, so that's also out.
A temporary object cannot be created in an existing block of memory, so that's also out.
The only remaining way is with a new expression, and of those, only placement new can refer to an existing block of memory.
So you are out of luck as far as the C++ standard goes.
However the same problem exists with malloc. There are tons of code out there that use malloc without bothering to use placement new. Such code just casts the result of malloc to the target type and proceeds from there. This method works in practice, and there is no sign of it being ever broken.
metaData *det = static_cast<metaData *>(alloc);
On an unrelated note, metaData det(); declares a function, and sizeof is not applicable to functions.

Implementing reference counting in a stack-based approach in C

I am making an interpreter in C, and I'm having a problem with my reference counting.
Each value (which is the interpreter's representation... of a value) is allocated with refcount 0. Once it gets added to the stack, it increments the refcount.
The only way to get a value off the stack is to pop it off it, but that leads to problems. My popping function returns the value that is popped, but if the refcount is 0 and I destroy the value I can no longer return it.
I get that I should probably put the refcount check somewhere else, but that just seems ugly as there are a lot of places that use the popping function.
What can I do to workaround this issue? Is implementing a real GC algorithm necessary in this case?
I use my own data base system which also uses a kind of refcount.
When an object is stored into a data base, then its refcount is incremented. When I get an object from a data base, its refcount remains unchanged. It is decremented only if the object is deleted by any way (usually the deletion of a data base containing it or its replacement by another object in a data base containing it). The object is really destroyed only when its refcount is equal to zero AND its deletion is required.
whenever you create object or value in your case, you should set the refcount to 1. On pushing to the stack, increment it. On poping, decrement. On pop each operation decrement and check th refcount, destroy value if refcount is zero. Which function destoy-value already be doing so you just need to call that function on pop.
As a general rule, increment the count when creating a reference and decrement when deleting a reference. But there's also a third type of transaction (or an optimized composition of the two) where there's just a transfer and you don't change the count at all.
This is the case if you pop the value from the stack and them proceed to use the value (in a local variable, maybe). First the object was on the stack, and now its in a variable; but there's still only one object. The reference count doesn't change until you're done with it and ready to discard the reference.

Resources