Many large distributed systems are built around pushing data through web requests, and human readable request/response formats (JSON, XML) are the most popular, and require integer to string conversions for serialization.
I remember a coworker having to fight with an old platform's build not working because our user/group IDs were bigger than 2^16. I can't remember which utility was causing the problem, I'd have to guess tar. This is when we learned to play the archive a VM game.
I can't imagine theres much overlap between "we will need to update this firmware for the next decade." and "Let's bet the farm on the documentation being perfect, and all the downloads still available."
I know a defence company that has a bunch of vaxes stored in low oxygen environments because they legally have to be able to provide software updates to firmware they’ve written for the next 20 or so years and it was written on a vax.
They had some great stories trying to get something or other running again where they had to fly one of the original designers over to hand solder a board back into action.
How we do that today is a bit of an interesting problem I don’t think they’ve convincingly solved; basically maintaining nightly builds forever — a couple 1U’s of kubernetes in deep storage ain’t gonna do it, you’re not gonna be able to solder a xeon back to life..
I know I’d rather be trying get a load of c99 rebuilt for some mips or other after 20 years that some random version of rust.
> I know I’d rather be trying get a load of c99 rebuilt for some mips or other after 20 years that some random version of rust.
Rust 1.0 is 11 years old and it's still trivial to compile Rust code from then. I doubt that will change in the next 9 years.
C is an absolute nightmare in comparison. I tried to compile some old C code I had for Nordic nRF51 chips, only a few years after the chips became available. I gave up. Broken links, missing documentation, etc. etc. I can see why other people here are saying it's standard practice to archive a VM. Not really necessary for Rust.
> Rust 1.0 is 11 years old and it's still trivial to compile Rust code from then. I doubt that will change in the next 9 years.
Maybe it's trivial to compile Rust code but it's not trivial to build a project with dependencies. I'm trying to get my feet wet with an official USB example project from Embassy on my RP2040. It doesn't work in the latest git repo for some unknown reason (might be my fault, probably is, but it's not obvious to me).
I'm assuming it worked at some point, maybe something changed and someone forgot to update something somewhere (there are lots of example projects). So I thought I'd "git bisect" until I find a working version and go from there. Well, I cannot get it to build against anything older than a year ago and that version also isn't working for me. It's dependency and Rust edition hell.
My guess is that when Rust code gets 30 years old, the problem would more likely be that you can't find an already compiled compiler that will work for that old code, and that the compilers themselves need bootstrapping. So you'll just fast-forward the code to work on a new compiler instead.
Yes, they are immutable. It's only possible to "yank" a specific version, which will prevent new dependencies, but it will still be available for download for existing dependencies.
> I know a defence company that has a bunch of vaxes stored in low oxygen environments because they legally have to be able to provide software updates to firmware they’ve written for the next 20 or so years and it was written on a vax.
So uh, will these ever make it to an auction site you think?
I have an Acer Chromebook with Celeron N3060 CPU and it runs the SIMH VAX emulator with 64MB for the VAX at the same speed as a Vaxstation 4000/60 and likely the disk is much faster.
I like OpenVMS and am slowly learning more about it; no reason to wait until you see those hit eBay :-)
I'm curious what the concern is with the rust editions mechanics in place. Each crate gets to define the language edition it is compiled with. Even if dependencies up convert to later editions they can still be linked against by crates that are an older edition.
As for the broader crate ecosystem, if crates you depend on drop support for APIs you depend on, that could cause you to get stuck on older unsupported releases. Though that is no different of a problem than any other language.
Something I've noticed that I never really see called out is how easy it is to review rust code diffs. I spent a lot of my career maintaining company internal forks of large open source C programs, but recently have been working in rust. The things I spent a lot of time chasing down while reviewing C code diffs, particularly of newer team members, is if they paid attention to all the memory assumptions that were non-local to the change they made. Eg. I'd ask them "the way you called this function implies it _always_ frees the memory behind that char*. Is that the case?" If they didn't know the answer immediately I'd be worried and spend a lot more time investigating the change before approving.
With rust, what I see is generally what I get. I'm not worried about heisenbug gotchas lurking in innocent looking changes. If someone is going to be vibe coding, and truly doesn't care about the language the product ends up in, they might as well do it in a language that has rigid guardrails.
How do LLMs deal with Rust (compared to other languages)? I think this might actually be the time to finally give the language a try. LLMs really lowered the barrier for staying productive while learning.
This is extremely limited scope annecdata, but I've spent a few tens of hours each testing LLM coding agents in Rust for personal projects and in Python at work. My impression is that LLMs are far more productive in Rust. I attribute this to the far more structured nature of Rust compared to Python, and possibly the excellent compiler error messages as well.
The LLM gets stuck in unproductive loops all the time in Python. In Rust, it generally converges to a result that compiles and passes unit tests. Of course the code quality is still variable. My experience is that it works best when prompts are restricted to a very small unit of work. Asking an LLM to write an entire library/module/application from scratch virtually never results in usable code.
sometimes they randomly choose the ugliest possible way to do pattern matching, eg multiple blocks of nested "if let" instead of a "match", or a "match" instead of a single "if let"
otherwise, works great; much easier to un-vibe the code compared to eg python
Long time back I'd play PS2 games in a chat window in EverQuest while waiting for mobs to spawn. I had a capture card that would overlay over a particular shade of purple that I discovered while trying to screen shot something from a game. I made an empty chat window in EQ that color and where it overlapped the card's application window behind the video would render. Was super jank picture in picture, but it worked.
CF had their route covered by RPKI, which at a high level uses certs to formalize delegation of IP address space.
What caused this specific behavior is the dilemma of backwards comparability when it comes to BGP security. We area long ways off from all routes being covered by rpki, (just 56% of v4 routes according to https://rpki-monitor.antd.nist.gov/ROV ) so invalid routes tend to be treated as less preferred, not rejected by BGP speakers that support RPKI.
PMTU just doesn't feel reliable to me because of poorly behaved boxes in the middle. The worst offender I've had to deal with was AWS Transit Gateway, which just doesn't bother sending ICMP too big messages. The second worst offender is, IMO (data center and ISP) routers that generate ICMP replies in their CPU, meaning large packets hit a rate limited exception punt path out of the switch ASIC over to the cheapest CPU they could find to put in the box. If too many people are hitting that path at the same time, (maybe) no reply for you.
More rare cases, but really frustrating to debug was when we had an L2 switch in the path with lower MTU than the routers it was joining together. Without an IP level stack, there is no generation of ICMP messages and that thing just ate larger packets. The even stranger case was when there was a Linux box doing forwarding that had segment offload left on. It was taking in several 1500 byte TCP packets from one side, smashing them into ~9000 byte monsters, and then tried to send those over a VPNish network interface that absolutely couldn't handle that. Even if the network in the middle bothered to generate the ICMP too big message, the source would have been thoroughly confused because it never sent anything over 1500.
> The even stranger case was when there was a Linux box doing forwarding that had segment offload left on. It was taking in several 1500 byte TCP packets from one side, smashing them into ~9000 byte monsters, and then tried to send those over a VPNish network interface that absolutely couldn't handle that. Even if the network in the middle bothered to generate the ICMP too big message, the source would have been thoroughly confused because it never sent anything over 1500.
This is an old Linux tcp offloading bug; large receive offload smooshes the inbound packet, then it's too big to forward.
I had to track down the other side of this. FreeBSD used to resend the whole send queue if it got a too big message, even if the size did not change. Sending all at once made it pretty likely for the broken forwarder to get packets close enough to do LRO, which resulted in large enough packet sending to show up as network problems.
I don't remember where the forwarder seemed to be, somewhere far away, IIRC.
> PMTU just doesn't feel reliable to me because of poorly behaved boxes in the middle. The worst offender I've had to deal with was AWS Transit Gateway, which just doesn't bother sending ICMP too big messages.
This made me think of a series of "war room" meetings I had been part of early in my career. Strangely enough, also a defect revealed when the platform was low on memory. This was also the issue where I learned the value of documenting experiments and results once an investigation has taken a non-trivial amount of time. Not just to show management what you are doing, but to keep track of all the things you have already tried rather than spinning in circles.
The war room meetings were full of managers and QA engineers reporting on how many times they reproduced the bug. Their repro was related to triggering a super slow memory leak in the main user UI. I had the utmost respect for the senior QA engineer who actually listened to us when we said we could repro the issue way faster, and didn't need the twice daily reports on manual repro attempts. He took the meetings from his desk, 20 feet away, visible through the glass wall of the room we were all crammed into. I unfortunately didn't have the seniority to do the same.
Since I can't resist telling a good bug story:
The symptom we were seeing is that when the system was low on memory, a process (usually the main user UI, but not always) would get either a SIGILL at a memory location containing a valid CPU instruction, or a floating point divide by zero exception at a code location that didn't contain a floating point instruction. I built a memory pressure tool that would frequently read how much memory was free and would mmap (and dirty) or munmap pages as necessary to hold the system just short of the oom kill threshold. I could repro what the slow memory leak was doing to the system in seconds, rather than wait an hour for the memory leak to do it.
I wanted to learn more about what was going on between code being loaded into memory and then being executed, which lead me to look into the page fault path. I added some tracing that would dump out info about recent page faults after a sigill was sent out. It turns out all of the code that was having these mysterious errors was always _very_ recently loaded into memory. I realized when Linux is low on memory, one of the ways it can get some memory back is to throw out unmodified memory mapped file pages, like the executable pages of libraries and binaries. In the extreme case, the system makes almost no forward progress and spends almost all of its time loading code, briefly executing it, and then throwing it out for another process's code.
I realized there was a useful looking code path in the page fault logic we would never seem to hit. This code path would check if the page was marked as having been modified (and if I recall correctly, also if it was mapped as executable.) If it passed the check, this code would instruct the CPU to flush the data cache in the address range back to the shared L2 cache, and then clear the instruction cache for the range. (The arm processor we were using didn't have any synchronization between the L1 instruction and L1 data cache, so writing out executable content requires extra synchronization, both for the kernel loading code off disk, as well as JIT compilers.) With a little more digging around. I found the kernel's implementation of scatter gather copy would set that bit. However, our SOC vendor, in their infinite wisdom, made a copy of that function that was exactly the same, except that it didn't set the bit in the page table. Of course they used it in their SDIO driver.
bitbake -e <recipe> is super useful for that game. It dumps out a complete history of where all variables were set/changed, and their values along the way. I also use it to do what I call "variable shopping," where I roughly know what path/name content I need, but not what the variable it is in is called.
I spent a lot of time debugging an internal fork of an open source BGP implementation (really old quagga.) The confederation code always struck me as being nothing but weird exceptions to how BGP normally worked. I was happy to never hear a network engineer suggest confederations with a straight face.
reply