Wait, what? I don't know rust, at all, but why is path freed? I thought rust didn't have GC? > let path = CString::new(filename.as_str()).unwrap().as_ptr(); Is one of those functions calling free behind the scenes?
Comparative unsafety
81–90 of 99 posts
Re: Comparative unsafety
#82Earlier quoted context omitted.
My understanding is fsync() will tell you more than close() only when a flush of the OS cache fails to make it to disk. Is there anything else? The problem with calling fsync() is that you have to wait for it to finish. There are many scenarios where the extra data integrity guarantees you get from calling fsync() aren't important.
close() will fail to report a wide variety of failures. But Cesar is right, you can't re-try it. And fsync() can be very slow on most commonly-used file systems. We are fortunate that now SSDs are fast.
Re: Comparative unsafety
#83Earlier quoted context omitted.
> Even if one in ten lines are marked as "unsafe", that's already many times less "unsafe" than what they are used to in their C or C++ code. As a Rust programmer who's written safe code and some unsafe abstractions, one in ten lines being unsafe means that the remaining 90% of your lines need to be written with the same care as your unsafe code, to avoid feeding invalid arguments into unsafe operations which cause U…
I'm baffled by why this answer is downvoted. It matches my experience precisely, and articulates the proper approach for isolating `unsafe` code so that the safe code around isn't so tricky to write .
On a related note, looking at the comments of a semi-"fluff" blog post commenting on an unsafe-Rust data race (https://news.ycombinator.com/item?id=26713037), I'm the first person across all of the Mozilla bug-tracker, Mozilla blog, and HN comments to point out that Firefox had "data races in safe code" because an unsafe block in a (module-private) "safe" function was unsound, allowing other safe code in the module to cause data races. (Maybe not the first, https://news.ycombinator.com/item?id=26714209 pointed out the 'bad pattern of "sprinkle atomics it until it works"' (though not researching it as deeply as I did) and got downvoted even though they were right in this instance.)
Re: Comparative unsafety
#84Fun fact: I hit the exact same bug when working on FamiTracker in C++, with a MFC type also called CString... "construct a CString, acquire a pointer into the internals, destroy the CString". The only reason it doesn't make FamiTracker crash is because MFC's CString is COW/refcounted, and the refcount never reached zero because it was constructed from a long-lasting string literal, so the underlying buffer was still…
Re: Comparative unsafety
#85Earlier quoted context omitted.
It's meant as satire on the needlessly script heavy websites that many people create nowadays. The blog post itself isn't entirely serious either.
Well, unfortunately for me it resulted into an early page close. I thought someone who uses that much javascript for a page that could have been 100% static can't have anything interesting to say.
Re: Comparative unsafety
#86> Why am I using my own ffi version of chown instead of the libc crate? The libc crate prototypes chown with unsigned uid_t and gid_t types, and I want to pass -1 because I'm not interested in changing the group. I'll spare you the long rant about how one should never redeclare system interfaces if you can't take the time to do so properly, because it turns out if you dig into it, uid_t boils down to uint32_t , but e…
If your reaction to Rust actually following the prototype of chmod but not accepting conversions signed/unsigned silently is to redefine chmod so you can do it like you’d do in C… that seems a little bullheaded to me. Wrapping a C function is dangerous in a literal and real sense, doing “-1 as u32” is not at all.
Eh... as the article points out, the chown documentation specifically says that you are expected to provide negative numbers. The spec is obviously bugged.
This limits the amount of righteousness you can claim over "but we followed the spec (that we knew was wrong)!"
Re: Comparative unsafety
#87> If there's an error which is a clear cut bug, I think it should be reported by an error detecting tool, not a linter Relevant rustc (merged) PR: https://github.com/rust-lang/rust/pull/75671 - "Uplift temporary-cstring-as-ptr lint from clippy into rustc"
This seems like a positive development, but there are other `as_ptr` and `as_mut_ptr` functions. The one that I tripped up with was actually from Vec, not CString. Zooming out, there are innumerable ways to create a dangling pointer. This is really a vexing problem.
Keep in mind that even something like borrowing a RefCell creates a temporary, so once you cast to a pointer and end the lifetime it came from it's very hard for the type system to track back the pointer you got to any particular deallocated temporary in an intelligent way. It pretty much has to be done on a case by case basis, I suspect (but maybe that could be improved--it is definitely the case, from a study someone did recently, that a large percentage of UB in unsafe Rust is due to destructors running early unexpectedly!).
Re: Comparative unsafety
#88Earlier quoted context omitted.
> No one checks close()'s result because it lies. And since nobody checks the result of close and very few check the result of every single write operation, many "disk full" errors go unnoticed.
If you want to know whether your writes are getting out, you will get a much more reliable indication from fsync(). So, instead of exhorting people to check close()'s result, you should exhort them to fsync() first and check that result. A very old programming principle says, "Never check for any failure you are not equipped to act on." It is sometimes used as a reminder to ensure you are always so equipped.
This sounds like a great principle for allowing dangerous bugs to linger in a codebase for years... one can always act upon a failure by aborting.
Re: Comparative unsafety
#89Earlier quoted context omitted.
So shouldn’t .as_ptr() itself be marked unsafe? That way only the correct version of this code, with the .as_ptr() inside the unsafe block, would compile, right? (I assume there’s a good reason why this isn’t the case, but I don’t know Rust well enough to know the answer. I’d be interested to learn, if anyone can explain it for me!) Edit to clarify: what seems very strange to me is that a function that not only does…
I don't see anything unsafe here. Merely storing a pointer, whatever it may be, doesn't violate memory-safety. Dereferencing a pointer in some cases does. The article contains one of those cases: use-after-free. If the pointer wasn't dereferenced, all code would be fine, including the line with ".as_ptr()".
It points to invalid memory as soon as the underlying object is freed. It’s hard to think of a legitimate usage at that point. You’d hope that’s exactly the kind of thing the borrow checker would be able to warn you about.
One situation where you might conceivably want to do something with that dangling pointer is if you were writing an allocator. But in this particular example, we’re not writing an allocator; and if we were, we wouldn’t call .as_ptr() on one of the allocated objects — that would be working at the wrong level of abstraction.
If you really do just need to store the value and not dereference it, shouldn’t it be stored as some integer type? Then to dereference it, you’d first need to cast it to a pointer, and that operation could be marked unsafe.
Re: Comparative unsafety
#90Fun fact: I hit the exact same bug when working on FamiTracker in C++, with a MFC type also called CString... "construct a CString, acquire a pointer into the internals, destroy the CString". The only reason it doesn't make FamiTracker crash is because MFC's CString is COW/refcounted, and the refcount never reached zero because it was constructed from a long-lasting string literal, so the underlying buffer was still…
I'm a big fan of this kind of improved RAII. We implemented it in https://vale.dev/blog/raii-next-steps , you might find it interesting!
Bidirectional pointers is definitely something it does better than Rust. Constraint references are an interesting idea. Clasps remind me of some Qt objects automatically detaching other objects listening to them, when destroyed (eg. QSortFilterProxyModel's source model, referenced by QSortFilterProxyModel, referenced by QAbstractItemView), but it feels ad-hoc for every individual type, and I don't know if there's underlying principles that all Qt types follow.
The descriptions of the language and others feel a bit crank-ish at times, I got lost a web of hyperlinks to various pages on the site and didn't read all of them, and apparently the language is not ready yet. I might check it out again when it's more complete.