Earlier quoted context omitted.
safe Rust doesn't have any Undefined Behaviour. Your unsafe Rust is supposed to provide suitable constraint/ guarantees that you, the programmer, conclude it does not have any Undefined Behaviour. The language can't force you to do this, and at some point it becomes a social contract not a programming language feature. I wrote the misfortunate crate to explore Rust's promise here. The crate provides legal but obvious…
Not "you, the programmer", any programmer. The Rust standard library can and sometimes does have UB, and that's even more true for other libraries.
Failing to Learn Zig via Advent of Code
291–300 of 338 posts
Re: Failing to Learn Zig via Advent of Code
#292I don't think it is that hard to learn I'm not a professional programmer, this is all a hobby for me and i managed to pick and write an entire game with it maybe you are just bad as a programmer (nothing wrong with that) you have to learn how to learn, not everybody can do that (and it's fine) that being said, zig is a language in the making, some areas are rough, but that's to be expected
> maybe you are just bad as a programmer (nothing wrong with that) This was actually my impression after reading the post. A bad programmer making a lot of ill-informed complaints. Zig is an unfinished low-level language. Not suitable for bad programmers.
Also it's a log of personal experience and not titled "an objective criticism of Zig". I've been interested in Zig a little for a while and this was awesome to read. It hasn't made my interest any smaller or bigger, it's simply a description of one beginner's journey, and if the Zig people are smart they will analyze it and then decide which points are valid and which ones can be ignored. Neither ignoring everything nor accepting everything would probably be useful.
Re: Failing to Learn Zig via Advent of Code
#293Earlier quoted context omitted.
You're conflating undefined behavior with spatial/temporal memory safety, the latter of which is what is 100% prevented by Rust's borrow checker, provided you're not interfacing with hardware, in which case I believe that things change more in binary fashion. However, Zig treats memory safety not as an extreme-at-all-costs but as a spectrum (there are reasons for wanting to think like this, at least when writing low-…
If dealing with potentially hostile data, Zig certainly isn't more appropriate than Rust in my opinion, try maybe WUFFS. Suppose we have been given a 32KB data structure with some "step" bytes - in a conforming input these should always sum to less then 32768 and thus the total will easily fit in a 16-bit unsigned integer, so that's what our naive program does. Unfortunately attackers provided a structure whose step…
Thanks! Great recommendation on WUFFS! And completely agreed, it's also easy to turn on checked arithmetic for Rust (if you know about it, but Rust definitely has an unsafe default there for those that don't, which is surprising to me).
At the same time, WUFFS is not always applicable, for example to writing something like a distributed system where you do still want safety, often the flip side of security. I'm sure you'll also agree it's good to balance out that security is more nuanced than just a rant about memory safety to the extreme. It's great to have positive discussions about languages, to evaluate trade-offs positively.
Counter-intuitively, I do feel also that Zig's explicitness as a language as a whole fits a security mindset well. For example, in `std/mem.zig` there's a very careful divExact assertion around underflow when calling `bytesAsSlice()`. This is just a fantastic way to prevent buffer bleeds, i.e. HeartBleed or CloudBleed, but it's probably uncommon to see in many libraries, and something like a borrow checker wouldn't provide this aspect of memory safety automatically. You can easily get lulled into a false sense of security.
From a security angle, I also like Zig's philosophy around very simple control flow and avoiding unnecessary abstractions, no matter if they're zero-cost. I think this is going to lead to a healthier package ecosystem when it arrives, compared to say NPM, where you get these dependency explosions that are a real headache for supply chain attacks. Attackers always go one level deeper, they attack through the basement, and there's often more low-hanging fruit at hand than a UAF (especially considering that many embedded systems that Zig targets probably do static allocation anyway, so bleeds might often be the worst that can happen). It will be interesting to see how Zig's philosophy around explicitness and avoiding bloat makes a difference here.
> Zig will panic here if using default arithmetic with default release builds. If the attacker wanted to cause a Denial of Service, job done already.
In the security world, a DoS is usually not treated as a P1. Perhaps a P3 at best (if you're lucky as a researcher!). For example, I've submitted one or two DoS MIME bomb samples that can shutdown Gmail servers and got very much an "okay, we'll just not bother about it because we're Gmail and our fleet is so massive". The DoS is probably still out in the wild for Gmail. Even ProtonMail, which has experienced numerous outages, didn't classify it as a P1, although they awarded it.
However, for a read/write exploit (running with the email example, perhaps a directory traversal in Apple Mail), having checked arithmetic convert what could have been a P1 into a P3 is actually exactly what you want because it prevents the exploit from going further (these things are almost always chained).
It also surfaces the bug visibly, you get a crash, you investigate, you fix. So from an attacker's perspective, they're actually less likely in fact to try and trigger it, because then they reveal they're in your system.
Re: Failing to Learn Zig via Advent of Code
#294Earlier quoted context omitted.
Aside from `NaN`, how is floating point addition non-commutative? It's not associative, but `a+b` will have the same value as `b+a`.
i believe there are strange corner cases around x87, but that may have changed since IEE754 got revised last year
Re: Failing to Learn Zig via Advent of Code
#295> Lack of zig-analyzer makes learning hard.
> zig fmt src/main.zig is nice. Wish it automatically ran on all files.
I also did (well, "am doing", can only work a bit each day and am plugging through day 7 right now) AdventOfCode in Zig this year.
These points here didn't resonate with me at all. I wonder if the author knew about or tried ZLS[0]. I had it on and integrated with my VSCode and it would check a lot of things as I went and format on save. I think I followed something like this[1] to set it up.
[0] https://github.com/zigtools/zls [1] https://zig.news/jarredsumner/setting-up-visual-studio-code-...
Re: Failing to Learn Zig via Advent of Code
#296Earlier quoted context omitted.
From a programming language design space, it's much more like C++. However it can occupy some niches that C can but C++ does poorly because of zero cost abstractions, I think. (Very handwavy)
There are no niches where Rust can do better than C++. In many places Rust can, uniquely, match C++.
Re: Failing to Learn Zig via Advent of Code
#297Earlier quoted context omitted.
Here is an example with a keyboard firmware why you might not always want all that complexity. https://kevinlynagh.com/rust-zig/ https://zig.news/aransentin/analysis-of-the-overhead-of-a-mi... The point of languages like C and Zig is that they are only a bit higher level than assembly for portability, but otherwise they don't hinder you to do whatever. It's up to you to solve problems like memory safety. You might no…
I read the thread about the keyboard at the time. The author literally said it was a hobby project and they weren't concerned about safety, which is why they weren't interested in all of the solutions people offered for their problems with Rust. Zig's fine if you don't care about safety. But that's not really how I've heard it advertised. > but otherwise they don't hinder you to do whatever Neither does Rust! You can…
Re: Failing to Learn Zig via Advent of Code
#298Nice to see a "brain dump" as someone who learned many languages and can easily relate with most of the issues the author faced. But I take issue with this: // Obviously good and easy to read return a*(1.0-t) + b*t; // Obviously bad and hard to read return add(mul(a, 1.0 - t), mul(b, t)); Sorry, but the first one is not obviously good, it's just what you're used to (the second one is indeed bad). Here's what I would…
The LISP version can be more readable with (e.g. Clojure’s) threading macros: (-> 1 (- t) (* a) (+ (* t b))) Obviously use more or less whitespace to taste.
Re: Failing to Learn Zig via Advent of Code
#299Earlier quoted context omitted.
> they don't want language releases dependent on unicode updates. I'm sorry, what do you mean by this?
The "rules" of unicode change over time with updates to the unicode standard(s). One big one is the grapheme breaking algorithm, which has been updated over time to support things like the family emoji and other compositions.
Re: Failing to Learn Zig via Advent of Code
#300Earlier quoted context omitted.
> No, as IEEE754 doesn't even guarantee that `a + b` == `a + b` What? I'm pretty sure that is plain incorrect. Can you back that claim up with references?
The rounding can depend 'where' (e.g. the width of the register) the float is stored in the CPU ('destination' in IEEE 754 speak). So, if you compare the result stored in two different 'destinations' (because one has been computed in another register or at a GPU or ....), they can differ even in the same program with the same optimizations. See for example: int main() { double q; q = 3.0/7.0; if (q == 3.0/7.0) printf…
> Implementations shall provide the following formatOf general-computational operations, for destinations of
> all supported arithmetic formats, and, for each destination format, for operands of all supported arithmetic
> formats with the same radix as the destination format
Which to my interpretation sounds like providing a `division(double, double) -> double` operation is required. I suppose the argument could be that in C the way of invoking that specific operation would be to add an explicit cast, i.e.
(double)(a op b)
But I do think that this is more a quirk on how operators are done specifically in C and not a general matter; the actual IEEE 758 operations are consistent and don't have such surprises.So I guess you were technically correct that IEEE 758 does not guarantee `a + b == a + b`, because IEEE 758 does not specify `+` (or `==` for that matter) operators at all. What IEEE 758 does guarantee is that you get the same result for the same operation.
In terms of C language, it is maybe interesting question if `FP_CONTRACT` pragma influences the result here at all:
> A floating expression may be contracted, that is, evaluated as though it were a single opera-
> tion, thereby omitting rounding errors implied by the source code and the expression evalua-
> tion method. The FP_CONTRACT pragma in provides a way to disallow contracted
> expressions. Otherwise, whether and how expressions are contracted is implementation-defined.
Are the comparison and arithmetic operations considered to be contracted in these sort of situations?