Live data from Hacker News

Comparative unsafety

flak.tedunangst.com

51–60 of 99 posts

Re: Comparative unsafety

#51
post #31

> 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.

Re: Comparative unsafety

#52
post #48
post #37

In Rust, dereferencing a pointer is unsafe and so must be isolated within an `unsafe` block — but creating a dangling pointer is not unsafe. What this means is that as soon as you add `unsafe` code which accepts a pointer argument, all the supposedly "safe" code which can affect this pointer argument becomes a potential source of memory errors. To me, this was unintuitive — I expected the `unsafe` block to require an…

In general unsafe should be viral: you can't call unsafe without yourself being unsafe. But it hits the same "snag", then nothing works anymore.

This is not true. Rust is based around the idea of encapsulating unsafety within interfaces that are safe to use.

Re: Comparative unsafety

#53
post #48
post #37

In Rust, dereferencing a pointer is unsafe and so must be isolated within an `unsafe` block — but creating a dangling pointer is not unsafe. What this means is that as soon as you add `unsafe` code which accepts a pointer argument, all the supposedly "safe" code which can affect this pointer argument becomes a potential source of memory errors. To me, this was unintuitive — I expected the `unsafe` block to require an…

In general unsafe should be viral: you can't call unsafe without yourself being unsafe. But it hits the same "snag", then nothing works anymore.

If `unsafe` were viral it would be useless. Syntactically ill-typed code can still be proven semantically well-typed, and `unsafe` is intended as a marker that the proof of semantic soundness lies outside of Rust's type system. If there is no proof (at least an informal one), you shouldn't be using unsafe, generally speaking.

Re: Comparative unsafety

#54

> 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.

Re: Comparative unsafety

#56
post #45
post #35

Earlier quoted context omitted.

No one checks close()'s result because it lies. What should you write, while (close(fd) != 0) {} ? Or does it risk getting an infinite loop if, e.g., some network connection disappears? Maybe if (fsync(fd) == 0) while (close(fd) != 0) {} else abort(); But maybe fsync is interruptible too. Ultimately there is nothing strictly correct to write, and you should just not really count on files being closed before process t…

> 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.

Re: Comparative unsafety

#57
post #40
post #35

Earlier quoted context omitted.

No one checks close()'s result because it lies. What should you write, while (close(fd) != 0) {} ? Or does it risk getting an infinite loop if, e.g., some network connection disappears? Maybe if (fsync(fd) == 0) while (close(fd) != 0) {} else abort(); But maybe fsync is interruptible too. Ultimately there is nothing strictly correct to write, and you should just not really count on files being closed before process t…

You cannot retry close(). Quoting from https://man7.org/linux/man-pages/man2/close.2.html#NOTES Retrying the close() after a failure return is the wrong thing to do, since this may cause a reused file descriptor from another thread to be closed. This can occur because the Linux kernel always releases the file descriptor early in the close operation, freeing it for reuse; the steps that may return an error, such as fl…

So what is the point of it having a return value at all then?

Re: Comparative unsafety

#58
post #56
post #45

Earlier 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.

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.

Re: Comparative unsafety

#59
post #37

In Rust, dereferencing a pointer is unsafe and so must be isolated within an `unsafe` block — but creating a dangling pointer is not unsafe. What this means is that as soon as you add `unsafe` code which accepts a pointer argument, all the supposedly "safe" code which can affect this pointer argument becomes a potential source of memory errors. To me, this was unintuitive — I expected the `unsafe` block to require an…

I wonder what a good approach to safe pointer arithmetic would be.

Re: Comparative unsafety

#60

> 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 you read the POSIX specification for chown you'll see that the "leave unchanged" sentinel value is, for UIDs, defined to be (uid_t) -1.

I can't be bothered to try it myself but I'm fairly sure the author could just have written (-1i32) as uid_t and gotten some of their life back.

Post reply on HN