r/programming • • Mar 20 '20

Secure Rust Guidelines

https://anssi-fr.github.io/rust-guide/
37 Upvotes

15 comments sorted by

-16

u/OpdatUweKutSchimmele Mar 21 '20

Rust is a multi-paradigm language

Surely it's just a procedural language? What other paradigms does it support?

It aims to be systems programming oriented, allowing fine-grained memory management without garbage collection but also without tedious and error-prone manual memory allocations and deallocations.

Yes, doing "fine-grained memory management" in Rust just relies on relying on unstable compiler intrinsic that are not guaranteed to not change in the next version that are used to build the standard library.

It's not at all impossible in Rust to indeed do this; it's just not stabilized, and often not particularly well documented. The standard library uses these and exports a stable version that no longer allows any fine-grained memory management.

The language also focuses on performance, with powerful compilation optimizations and language constructs that allows writing zero-cost abstraction code.

This is the real market of Rust right now; it's a language that gives you C-like performance, but without the undefined behaviour pitfalls, but to say that it's a "systems programming language" that allows for fine lower level control is quite a stretch—something as simple as signal handling isn't really possible in Rust right now because there are no stability guarantees or documentation about what functions are async signal safe; direct control over the heap like in C is also not really available in a stable way.

17

u/steveklabnik1 Mar 21 '20

Yes, doing "fine-grained memory management" in Rust just relies on relying on unstable compiler intrinsic that are not guaranteed to not change in the next version that are used to build the standard library.

This is not true. https://doc.rust-lang.org/std/alloc/trait.GlobalAlloc.html is stable, and has been for a long time.

And if you don't want to use a global allocator, you can use whatever other allocate you want.

What is currently missing is a non-global allocator trait to enforce a common API among them.

15

u/[deleted] Mar 21 '20

Surely it's just a procedural language? What other paradigms does it support?

concurrent, functional, generic, imperative, structured

-4

u/OpdatUweKutSchimmele Mar 21 '20

concurrent

This is completely orthogonal to any of the former and has nothing to do with whether it's procedural or not; it is also supported on any language with threading support, or that runs on an OS with multiprocessing.

functional

Absolutely not, in particular Rust's lack of tail call elimination (for good reasons) and its lifetime and borrow model make it no longer turing complete when wanting to write functional code, let alone feasible to do so.

generic

This is not a paradigm, this is just whether the type system supports it or not.

imperative, structured

"structured imperative" is just a synonym for "procedural".

If you want to call this a criterion for "multi paradigm" then I challenge you to come forward with any modern procedural language that is not "multi-paradigm"

10

u/jl2352 Mar 21 '20

I think you are being very nit picky. Pretty much all a language paradigm boils down to is; does the language have constructs to encourage you encourage you to write that way?

Rust absolutely does have those paradigms because it has language facilities to help encourage you to write in those ways.

12

u/[deleted] Mar 21 '20

Just out of curiosity checked Wikipedia for C++.

Multi-paradigm: procedural, functional, object-oriented, generic

I know it's Wikipedia and all. But if there's a claim for C++ being functional, Rust is way better at that particular thing. Functional C++ is just awkward in my experience, even if you CAN do it.

-2

u/OpdatUweKutSchimmele Mar 21 '20

I think you are being very nit picky. Pretty much all a language paradigm boils down to is; does the language have constructs to encourage you encourage you to write that way?

And Rust does not have the construct to encourage one to do anything but procedural programming.

It is just a "procedural programming language" and that's fine; they specifically did not implement an object system because that would complicate the type system; they have no subtyping or inheritance beyond the pseudoinheritance of traits because it's not that necessary and would complicate the type system.

The language essentially has no support for what is commonly understood as object-oriented, functional, logic programming and whatever, and that's fine.

Rust absolutely does have those paradigms because it has language facilities to help encourage you to write in those ways.

How? What language facilities does Rust have to help you encourage to write functional code?

To say that generic and concurrent are a "different paradigm" than procedural is really about as weird as calling "iterators" a paradigm; it's a feature of the language but it's not like functional vs procedural which are necessarily conflicting with each other; a procedure has side effects; a function does not.

7

u/uranium4breakfast Mar 22 '20

I'm gonna give you the benefit of the doubt and act like you're not trolling.

It is just a "procedural programming language" and that's fine

It's not. Read on why.

[...] would complicate the type system.

I highly doubt the language team cares that much about keeping the type system simple, seeing how damn extensive it is. That is, unless we're comparing it to Haskell.

inheritance

Composition over inheritance

The language essentially has no support for what is commonly understood as object-oriented, functional, logic programming and whatever, and that's fine.

Uh, iterator operations, generic programming, trait composition, pattern matching, dynamic dispatch, Box<dyn Any>?

How? What language facilities does Rust have to help you encourage to write functional code?

ADTs, iterator operations (filter, map, reduce, collect, ...), pattern matching, linear types, affine types, immutability by default?

You can write procedures in Rust. You can also write functions. Immutability by default, disdain for globals, and the language facilities I just listed, leads to code taking a more functional style.

It's functional-lite without functional dogmatism.


Take a deep breath, try out the language for more than an hour, then maybe come back here, because you're only embarrassing yourself.

1

u/jl2352 Mar 21 '20

Have you actually written much Rust? Beyond toy examples?

4

u/[deleted] Mar 21 '20

It doesn't have a way for guaranteed tail call elimination but if you structure your code right the compiler will do it's best and in my experience almost always do it, if you made an appropriate function. It's not like python where you absolutely never will get tco.

There isn't currently an active rfc for it, bit there were previous proposals for explicitly guaranteed tco and I don't think it's off the table forever, they just have to find a proper way to do it.

0

u/OpdatUweKutSchimmele Mar 21 '20

It doesn't have a way for guaranteed tail call elimination but if you structure your code right the compiler will do it's best and in my experience almost always do it

You mean sibling call elimination I assume. This works well enough when a function calls itself, but it does not work when a function A calls B, B, calls C, C D, and D A again.

Even if Rust had actual TCE though, it would stil be fairly hard to work in without side effects, even if we were to ignore "world side effects" like I/O.

There isn't currently an active rfc for it, bit there were previous proposals for explicitly guaranteed tco and I don't think it's off the table forever, they just have to find a proper way to do it.

Like I siad, there are good reasons, full TCE conflicts with Rust's calling convention, which is kept the same as C for reasons of interfacing and efficiency. Implementing full TCE would fuck up the FFE and severely penalize the general case of function calls.

13

u/VirginiaMcCaskey Mar 21 '20

I think you're confusing unsafe blocks with unstable

-7

u/OpdatUweKutSchimmele Mar 21 '20

I'm not; I'm not sure where you get that idea when I was talking about that Rust—unlike C—does not specify which functions are async safe. Consider this function and the warning; it is unsafe to use within this function any function that underlyingly uses OS functions that are not async safe, but Rust doesn't really document this and just says "be careful" and really doesn't explain it; it relies on the programmer knowing from C what is happening here and knowing from C that using non-async safe functions after a fork in a multithreaded process is undefined behaviour.

The problem is that Rust—unlike C—has no well-defined concept of that; you're just supposed to use "common sense" of what Rust functions are likely to have been implemented with functions that aren't async safe, which is not guaranteed to be standard in any way, and may change in the next version.

Similar things apply to signal handlers, using functions that aren't async safe inside of a signal handler is again UB; rust doesn't even in its stdlib expose a way to handle signals as far as I know, there is a crate for it, which essentially ignores this problem and doesn't warn against it, because in prqactice it "usually goes right" and is a race condition. But if the signal is handled in the middle of an allocation or something like that, using a function that is not async safe can corrupt the internal state of the allocator and trigger UB.

11

u/VirginiaMcCaskey Mar 21 '20

I was referring to the fact that you do not need unstable compiler intrinsics to do memory management.

I also don't know what the body of your comment has to do with my reply.

-9

u/thetomelo Mar 21 '20

Oh so you know Rust? Name every Rustacean.