Discussion Thread: DIP 1035-- at system Variables--Final Review
Stanislav Blinov
stanislav.blinov at gmail.com
Wed Feb 23 23:07:02 UTC 2022
On Wednesday, 23 February 2022 at 18:16:17 UTC, Paul Backus wrote:
> Having spent some more time scratching my head over this, I now
> realize what I was missing: it is indeed possible to open a
> file descriptor that can corrupt *arbitrary* memory in a
> process's address space, using something like `/proc/self/mem`.
Yes, or you may use e.g. `memfd_create`. And you can inherit such
an fd from a parent process. Or receive a shared memory
descriptor from another process.
> Maybe I'm an idiot for missing this the first time around; I
> can only ask that you take pity on me. :)
Never! How dare you make me question myself!!! :)
> This means that calling `write` on a fd is only memory safe if
> you have previously verified that the file the fd refers to is
> "well behaved" (i.e., satisfies a particular invariant). It
> follows that the fd itself must be stored in a `@system`
> variable in order to ensure that the invariant is maintained in
> `@safe` code.
Yup.
> I don't think adding `scope` checking to the fd makes any
> difference here, though. *Reading* from `/proc/self/mem` in
> `@safe` code is perfectly fine, even if you are reading from
> uninitialized or deallocated memory. The reason such reads are
> UB when done through pointers is that *dereferencing an invalid
> pointer* is UB, not because reading from the memory is UB.
Well, results of `read`ing from some types of fds are also not
specified. So, if I'm not mistaken, performing such a read *and*
then using the resulting "data" would be undefined behavior
(provided the program even gets there).
As for `scope` checks themselves - as Dennis mentions, double
`close` looks dissimilar to double free. Yet it *is* subject to a
superset of that - use after free, as are `read` and `write`. You
may well safely "dangle" an fd and not invoke UB by calling those
functions with it, but only up to the point when the program
opens another descriptor. Calling `close` on a dangled fd, which
would then succeed, would be a mere bug and not invoke UB, but
attempting to `write` or `read`+use may.
So I do think that fds could still be a good example material for
the DIP.
> (I'm also not sure if it's possible in practice to tell whether
> a file is "well behaved". If not, that means we have to either
> accept that `write` is *always* `@system`, or allow a permanent
> loophole in `@safe`. But that's a separate issue.)
I don't think that should be necessary in concrete cases, as the
onus of ensuring the implicit invariant would lie on the
implementation of, in this case, `File` - e.g. making it
non-copyable (or reference-counted), ensuring that the
constructor opens an appropriate kind of file, etc. etc. That way
the only way to make it unsafe would be to corrupt the given
instance of `File` itself, which means there's a memory safety
issue somewhere else in the program (for example, that same
void-initialization).
More information about the Digitalmars-d
mailing list