HNHacker News
TopNewBestAskShowJobs

MaulingMonkey

4,363 karma · joined February 16, 2013

Engine Programmer.

http://maulingmonkey.com/

submissionscomments
MaulingMonkey··on Why are we still using Markdown?
I use a horrific mix of:

• Markdown (most of my notes these days, supplanting my previous use of plaintext.)

• Single-file HTML (when my use case for fancy documents exceeds markdown's limits. While you can embed HTML into markdown, renderers vary in what they allow or sanitize, and vary in how you can (ab)use style tags. I've even taken to looking up CSS rules for printed documents, since my intended target is often pdfs or actual print at that point. Occasionally, JavaScript!)

• Google docs (Android phone nonsense!)

I'd mutter something about "using the right tool for the right job", but that's probably giving myself too much credit.

MaulingMonkey··on A single-file C allocator with explicit heaps and tuning knobs
> One explaination for that would be stripping "out of scope" macros that the sublibrary depends on but wishes to avoid including.

Another explaination would be the original source being multi-file, with the single-file variant being generated. E.g. duktape ( https://github.com/svaarala/duktape ) generates src-custom/duktape.c from src-input/*/*.c ( https://github.com/svaarala/duktape/tree/master/src-input ) via python script, as documented in the Readme:

https://github.com/svaarala/duktape/tree/master?tab=readme-o...

MaulingMonkey··on A single-file C allocator with explicit heaps and tuning knobs
> no commit history, 10k+ lines of complicated code

This kind of pattern is incredibly common when e.g. a sublibrary of a closed source project is extracted from a monorepository. Search for "_LICENSE" in the source code and you'll see leftover signs that this was indeed at one point limited to "single-process-package hardware" for rent extraction purpouses.

Now, for me, my bread and butter monorepos are Perforce based, contain 100GB+ of binaries (gamedev - so high-resolution textures, meshes, animation data, voxely nonsense, etc.) which take an hour+ to check out the latest commit, and frequently have mishandled bulk file moves (copied and deleted, instead of explicitly moved through p4/p4v) which might mean terrabytes of bandwidth would be used over days if trying to create a git equivalent of the full history... all to mostly throw it away and then give yourself the added task of scrubbing said history to ensure it contains no code signing keys, trade secrets, unprofessional easter eggs, or other such nonsense.

There are times when such attention to detail and extra work make sense, but I have no reason to suspect this is one of them. And I've seen monocommits of much worse - typically injested from .zip or similar dumps of "golden master" copies, archived for the purpouses of contract fulfillment, without full VCS history.

Even Linux, the titular git project, has some of these shenannigans going on. You need to resort to git grafts to go earlier than the Linux-2.6.12-rc2 dump, which is significantly girthier.

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/lin...

https://github.com/torvalds/linux/commit/1da177e4c3f41524e88...

0 parents.

> It looks to be generated from another code base as a sorta amalgamation (either through code generation, ai, or another means).

I'm only skimming the code, but other posters point out some C macros may have been expanded. The repeated pattern of `(chunk)->...` reminds me of a C-ism where you defensively parenthesize macro args in case they're something complex like `a + b`, so it expands to `(a + b)->...` instead of `a + b->...`.

One explaination for that would be stripping "out of scope" macros that the sublibrary depends on but wishes to avoid including.

> We're supposed to implicitly trust this person

Not necessairly, but cleaner code, git history, and a more previously active account aren't necessairly meant to suggest trust either.

MaulingMonkey··on My “grand vision” for Rust
(Rust has a similar fn: https://doc.rust-lang.org/std/primitive.isize.html#method.ch... )
MaulingMonkey··on Best performance of a C++ singleton
In fact, Windows 10+ now uses a thread pool during process init well before main is reached.

https://web.archive.org/web/20200920132133/https://blogs.bla...

MaulingMonkey··on macOS code injection for fun and no profit (2024)
> video games

Often use dynamic/scripting languages to improve iteration on gameplay code, even if a lot of the fundamental underlying code is native. And add dev-time hot reloading wherever we can so when you change a texture, it reloads ≈immediately without needing to so much as restart the level. We exile as much as we can to tables and other structured data formats which can easily be tweaked and verified by non-coders so we're not a bottleneck for the game designers and artists who want to tweak things, and make that stuff hot-reloadable if possible as well.

We also often have in-house build server farms full of testing code, because it's such a pain in the ass to iterate with anything dynamic. After all, games are huge, and sufficient testing to make sure all your uncompiled unanalyzed typecheckless code works is basically impossible - things are constantly breaking as committed during active development, and a decent amount of engineering work is frequently dedicated to such simple tasks as triaging , collecting, and assigning bugs and crash reports such that whomever broke it knows they need to fix it, as well as allowing devs and designers to work from previous "known good" commits and builds so they aren't blocked/unable to work on their work - which means internal QA helping identify what's actually "known good", hosting and distributing multiple build versions internally such that people don't have to rebuild the universe themselves (because that's several hours of build time), etc.

Some crazy people invest in hot-reloadable native code. There's all kinds of limits on what kinds of changes you can make in such a scenario, but it's entirely possible to build a toolchain where you save a .cpp file, and your build tooling automatically kicks off a rebuild of the affected module(s), triggering a hot reload of the appropriate .dll, causing your new behavior to be picked up without restarting your game process. Which probably means it'll immediately crash due to a null pointer dereference or somesuch because some new initialization code was never triggered by the hot reloading, but hey, at least it theoretically works!

And, of course, nothing is stopping you from creating isolated sandboxes/examples/test cases where you skip all the menuing, compiling unrelated modules, etc. and iterating in that faster context instead of the cumbersome monolith for most of your work.

MaulingMonkey··on NASA announces overhaul of Artemis program amid safety concerns, delays
Record low launch temperatures are exactly the kind of boundary pushing conditions that would warrant unmanned testing in a way that not all of those previous 25 would have been. Then again, so was the first launch, and that was manned.

> I don't see your alternative scenario as plausible

Valid.

MaulingMonkey··on NASA announces overhaul of Artemis program amid safety concerns, delays
> They didn't need more unmanned testing to find the issue; they needed to stop ignoring it.

Should such testing have been needed? No.

Was such testing needed, given NASA's political pressures and management? Maybe. Unmanned testing in similar conditions before putting humans on it might've resulted in a nice explosion without loss of life that would've been much harder to ignore than "the hypothesizing of those worrywart engineers," and might've provided the necessary ammunition to resist said political pressures.

MaulingMonkey··on Bus stop balancing is fast, cheap, and effective
I'll note another fun pattern I've seen:

• Bus crawls along behind traffic during rush hour traffic, or a long line of traffic bottlenecked by a busy stop sign

• Bus stops to load/unload, blocking traffic for a bit, with a gap opening up in front of it as a result of cars not being able to get around (e.g. the stop is just directly on the typical curb/sidewalk with one lane in that direction.)

• Bus continues, and quickly catches up to the car it was behind before, since traffic was going slower than the speed limit as a result of bottlenecks

The stop was free, in these cases.

MaulingMonkey··on Bus stop balancing is fast, cheap, and effective
Skeptical notes based on my own experiences in Seattle (≈1148ft average per article - which might be considered high enough that the article already considers the mission for fewer bus stops a success?):

Some of the routes I've taken had "express" variants that skipped many stops, yet still stopped at my usual start and exit. I never bothered waiting for them - the savings were marginal, and taking the first bus was typically fastest, express or not. Time variation due to traffic etc. meant you couldn't really plan around which one you wanted to take either.

The buses already skip stops where they don't see anyone waiting for the bus, and nobody pulls the coord to request an exit, and said skipping tends to happen even during the dense rush hour. Additionally, stop time seems to be dominated by passenger load/unload. Clustering at fewer bus stops doesn't significantly change how much time that takes much, it just bunches it together in longer chunks. The routes where this happens a lot also tend to be the routes where they're going to be starting and stopping frequently for traffic lights anyways - often stopping before a light for shorter than the red, or after a light and then catching up to the next red.

What makes a significant difference in bus speed is the route.

If the bus takes a route where a highway is taken - up/down I-5 or I-405, or crossing Lake Washington, there are significant time savings. This isn't "having less/fewer bus stops", this is "having some long distance routes that bypass entire metro areas".

Alternatively, buses that manage to take low density routes - not highways per se, but places where there are still few if any traffic lights, and minimal traffic - tend to manage a lot better speed, compared to routes going through city centers. They may have plenty of bus stops, but again skip many of them due to lower density also resulting in lower passenger numbers, and when they do stop it's for less time than a typical traffic light cycle. A passenger might pull the coord, get up to exit, stand while the bus comes to a stop, hop off, and watch the bus pull off, delaying the bus by what... 10 seconds pessimistically for the stop itself, and another 10 seconds for deacceleration and then acceleration back to the speed limit?

Finally, there's also grade separated light rail, grade seperated bus lanes, and bus tunnels through downtown Seattle, that significantly help mass transit flow smoothly even in rush hour, for when you do have to go through a dense metro area. While these are far from fast or cheap to implement, axing a few bus stops isn't going to make other routes competitive when these are an option.

MaulingMonkey··on Show HN: Iron-Wolf – Wolfenstein 3D source port in Rust
(equivalent C file: https://github.com/id-Software/wolf3d/blob/master/WOLFSRC/WL... )

> Was this translated automatically from C?

I'll note that when I convert code between languages, I often go out of my way to minimize on-the-fly refactoring, instead relying on a much more mechanical, 1:1 style. The result might not be idiomatic in the target language, but the bugs tend to be a bit fewer and shallower, and it assists with debugging the unfamiliar code when there are bugs - careful side-by-side comparison will make the mistakes clear even when I don't actually yet grok what the code is doing.

That's not to say that the code should be left in such a state permanently, but I'll note there's significantly more changes in function structure than I'd personally put into an initial C-to-Rust rewrite.

The author of this rewrite appears to be taking a different approach, understanding the codebase in detail and porting it bit by bit, refactoring at least some along the way. Here's the commit that introduced that fn, doesn't look like automatic translation to me: https://github.com/Ragnaroek/iron-wolf/commit/9014fcd6eb7b10...

MaulingMonkey··on Parse, Don't Validate and Type-Driven Design in Rust
> Would have to be F32, no?

Generally yes. `NonZeroU32::saturating_add(self, other: u32)` is able to return `NonZeroU32` though! ( https://doc.rust-lang.org/std/num/type.NonZeroU32.html#metho... )

> I cannot think of any way to enforce "non-zero-ness" of the result without making it return an optional Result<NonZeroF32>, and at that point we are basically back to square one...

`NonZeroU32::checked_add(self, other: u32)` basically does this, although I'll note it returns an `Option` instead of a `Result` ( https://doc.rust-lang.org/std/num/type.NonZeroU32.html#metho... ), leaving you to `.map_err(...)` or otherwise handle the edge case to your heart's content. Niche, but occasionally what you want.

MaulingMonkey··on Understanding Std:Shared_mutex from C++17
One thing I appreciate about Rust's stdlib is that it exposes enough platform details to allow writing the missing knobs without reimplementing the entire wrapper (e.g. File, TcpStream, etc. allows access to raw file descriptors, OpenOptionsExt allows me to use FILE_FLAG_DELETE_ON_CLOSE on windows, etc.)
MaulingMonkey··on Lessons you will learn living in a snowy place
Where I live (pacific northwest), it's not snow that's the problem, but windstorms. Presumably knocking over trees, which in turn takes down power lines - which of course implies said trees are tall, in proximity to the power lines, and not cut down. I maybe average 24 hours of outage per year (frequently less, but occasionally spiking to a multi-day outage.)

I don't think that's something that can be solved with just "build quality"... but it presumably could be solved through "maintainence" (cutting down or trimming trees, although that requires identifying the problem, permissions, a willingness to have decreased tree coverage, etc.)

MaulingMonkey··on GOG: Linux "the next major frontier" for gaming as it works on a native client
> It'll mean GOG has to do less work

[citation needed]

GOG's launcher team is presumably already familiar with their codebase, already has a checkout, already has a codebase that's missing 0 features, has a user interface that already matches their customer's muscle memory, and presumably already has semi-decent platform abstraction layer, considering they have binaries for both Windows and OS X. Unless they've utterly botched their PAL and buried it under several mountains of technical debt, porting is probably going to be relatively straightforward.

I'm not giving Linux gaming a second shot merely because of a bunch of ancedata about proton and wine improvements - I'm giving it a second shot because Steam themselves have staked enough of their brand and reputation on the experience, and put enough skin in the game with official linux support in their launcher. While I don't have enough of a GOG library for GOG's launcher to move the needle on that front for me personally, what it might do is get me looking at the GOG storefront again - in a way that some third party launcher simply wouldn't. Epic? I do have Satisfactory there, Heroic Launcher might be enough to avoid repurchasing it on Steam just for Linux, but it's not enough to make me want to stop avoiding Epic for future purchases on account of poor Linux support.

MaulingMonkey··on Threat actors expand abuse of Microsoft Visual Studio Code
You can specify:

    "runOptions": { "runOn": "folderOpen" }
In tasks.json, which I use for automatically `git fetch`ing on a few projects. While I don't recall it's interaction with first run / untrusted folder dialogs, it's entirely automatic on second run / trusted folders.
MaulingMonkey··on Threat actors expand abuse of Microsoft Visual Studio Code
> Wanting to be able to use anybody's machine is very strange, agreed.

Very useful if people are struggling to create reliable repro steps that work for me - I can simply debug in situ on their machine. Also useful if a coworker is struggling to figure something out, and wants a second set of eyes on something that's driving them batty - I can simply do that without needing to ramp up on an unfamiliar toolset. Ever debugged a codegen issue that you couldn't repro, that turned out to be a compiler bug, that you didn't see because you (and the build servers) were on a different version? I have. There are ways to e.g. configure Visual Studio's updater to install the same version for the entire studio, which would've eliminated some of the "works on my machine" dance, but it's a headache. When a coworker shows me a cool non-default thing they've added a key binding for? I'll ask what key(s) they've bound it to if they didn't share it, so we share the same muscle memory.

MaulingMonkey··on Threat actors expand abuse of Microsoft Visual Studio Code
I bucket Eclipse under "heavyweight IDE". I used to use it, plus the CDT plugin, for my C++ nonsense.

Then Visual Studio's Express and later Community SKUs made Visual Studio free for ≈home/hobby use in the same bucket. And they're better at that bucket for my needs. Less mucking with makefiles, the mixed ability to debug mixed C# and C++ callstacks, the fact that it's the same base as my work tools (game consoles have stuff integrating with Visual Studio, GPU vendors have stuff integrating with Visual Studio, the cool 3rd party intellisense game studios like integrates with Visual Studio...)

Eclipse, at least for me, quickly became relegated to increasingly rare moments of Linux development.

But I don't always want a heavyweight IDE and it's plugins and load times and project files. For a long time I just used notepad for quick edits to text files. But that's not great if you're, say, editing a many-file script repository. You still don't want all the dead weight of a heavy weight IDE, but there's a plethora of text editors that give you tabs, and maybe some basic syntax highlighting, and that's all you were going to get anyways. Notepad++, Sublime Text, Kate, ...and Visual Studio Code.

Well, VSC grew some tricks - an extension API for debuggers, spearheading the language server protocol... heck, I eventually even stopped hating the integrated VCS tab! It grew a "lightweight IDE" bucket, and it serves that niche for me well, and that's a useful niche for me.

In doing so, it's admittedly grown away from the "simple text editor" bucket. If you're routinely doing the careful work of auditing possibly malicious repositories before touching a single build task, VSC feels like the wrong tool to me, despite measures such as introducing the concept of untrusted repositories. I've somewhat attempted to shove a round peg into a square hole by using VSC's profiles feature - I now have a "Default" profile for my coding adventures and a "Notes" profile with all the extensions gone for editing my large piles of markdown, and for inspecting code I trust enough to allow on disk, but not enough to autorun anything... but switching editors entirely might be a better use of my time for this niche.

MaulingMonkey··on Fixing a Buffer Overflow in Unix v4 Like It's 1973
> perhaps the downvoters can tell me why they are downvoting?

Not one of the actual downvoters, but:

Lack of proper indenting means your code as posted doesn't even compile. e.g. I presume there was a `char* p;` that had `*` removed as markdown.

Untested AI slop code is gross. You've got two snippets doing more or less the same thing in two different styles...

First one hand-copies strings character by character, has an incoherent explaination about what `pwbuf` actually is (comment says "root::", code actually has "root:k.:\n", but neither empty nor "k." are likely to be the hash that actually matches a password of 100 spaces plus `pwbuf` itself, which is presumably what `crypt(password)` would try to hash.)

Second one is a little less gross, but the hardcoded `known_hash` is again almost certainly incorrect... and if by some miracle it was accurate, the random unicode embedded would cause source file encoding to suddenly become critical to compiling as intended, plus the `\0`s written to `*p` mean su.c would hit the `return;` here before even attempting to check the hash, assuming you're piping the output of these programs to su:

        while((*q = getchar()) != '\n')
                if(*q++ == '\0')
                        return;
A preferrable alternative to random nonsensical system specific hardcoded hashes would be to simply call `crypt` yourself, although you might need a brute force loop as e.g. `crypt(password);` in the original would presumably overflow and need to self-referentially include the `pwbuf` and thus the hash. That gets messy...
MaulingMonkey··on The Algebra of Loans in Rust
> Is the juice worth the squeeze to introduce two new function colors?

Typically no... which is another way of saying occasionally yes.

> What would you do if you needed to call `unreachable!()`?

Probably one of e.g.:

    unsafe { core::hint::unreachable_unchecked() }
    loop {}
Which are of course the wrong habits to form! (More seriously: in the contexts where such no-panic colors become useful, it's because you need to not call `unreachable!()`.)

> It's a shame that you can't quite do this with a lint, because they can't recurse to check the definitions of functions you call. That would seem to me to be ideal, maintain it as an application-level discipline so as not to complicate the base language, but automate it.

Indeed. You can mark a crate e.g. #![deny(clippy::panic)] and isolate that way, but it's not quite the rock solid guarantees Rust typically spoils us with.

MaulingMonkey··on The Algebra of Loans in Rust
This is something I do wish Rust could better support. A `#![no_std]` library crate can at least discourage allocation (although it can always `extern crate alloc;` in lib.rs or invoke malloc via FFI...)
MaulingMonkey··on Archiving Git branches as tags
FWIW, this is what I do, although typically with the prefix `dead/`, unto which I abandon ideas and misdirected refactoring with reckless abandon.
MaulingMonkey··on Precise geolocation via Wi-Fi Positioning System
GPS started as a U.S. Department of Defense project, and they had qualms about freely giving the high accuracy positioning information they found so very useful for e.g. targeting bombs and missiles, to every unverified third party in the world. Depending on your preferred flavor of jadedness, one could say it was because of security concerns... or one could say it was because said third parties hadn't paid off the military industrial complex enough!
MaulingMonkey··on Garbage collection is useful
> Is it?

Yes.

> What happens if you remove that one last reference to a long chain of objects?

A mass free sometime vaguely in future based on the GC's whims and knobs and tuning, when doing non-refcounting garbage collection.

A mass free there and then, when refcounting. Which might still cause problems - but they are at least deterministic problems. Problems that will show up in ≈any profiler exactly where the last reference was lost, which you can then choose to e.g. ameliorate (at least when you have source access) by choosing a more appropriate allocator. Or deferring cleanup over several frames, if that's what you're into. Or eating the pause for less cache thrashing and higher throughput. Or mixing strategies depending on application context (game (un)loading screen probably prioritizes throughput, streaming mid-gameplay probably prioritizes framerate...)

> You might unexpectedly be doing a ton of freeing and have a long pause. And free itself can be expensive.

Much more rarely than GC pauses cause problems IME.

MaulingMonkey··on Heartbeats in Distributed Systems
> File descriptors are a limited resource, but the limits are huge.

Maybe in the linuxy servery context we're talking about, but I'll note I've encountered EMFILE and ENFILE errors attempting to open a mere couple hundred files on iOS simultaniously. And while my own experience is over a decade old, here's someone hitting those limits this year: https://github.com/bevyengine/bevy/pull/17377

(Context for my own encounter: gamedev, with massively parallel asset streaming and multiple layers of direct blocking dependencies in deserialization. One of my hackarounds involved temporarily closing the least recently read files, and then reopening them on demand in our VFS abstraction. Of course, for non-dev builds, you can just use a pack file and `pread` a single fd from multiple threads, but loose files were handy for incremental dev updates...)

MaulingMonkey··on Error ABI
Rust already has exceptions (when panic=unwind)
MaulingMonkey··on Sodium-ion batteries have started to appear in cars and home storage
My understanding is that it's a poor form factor for lithium ion - which operates at higher voltages, and thus needs an extra voltage regulator to step them down to 1.5V if you're packing them into the AA format (adding cost, reducing capacity, & introducing conversion losses.)

https://www.youtube.com/watch?v=uKYF1CXZPng

MaulingMonkey··on Just let me select text
Ahh, that would make sense.
MaulingMonkey··on Wild performance tricks
> That's my point; I think after a while you instinctly repeat a command with sudo tacked on (see XKCD), and I wonder if I'm any safer from myself like that?

We agree that this is a dangerous / security-defeating habit to develop.

If someone realizes they're developing a pattern of such commands, it might be worth considering if there's an alternative. Some configuration or other suid binary which, being more specialized or tailor-purpouse, might be able to accomplish the same task with lower risk than a generalized sudo command.

This is often a difficult task.

Some orgs introduce additional hurdles to sudo/admin access (especially to e.g. production machines) in part to break such habits and encourage developing such alternatives.

> unsafe

There are usually safe alternatives.

If you use linters which require you to write safety documentation every time you break out an `unsafe { ... }` block, and require documentation of preconditions every time you write a new `unsafe fn`, and you have coworkers who will insist on a proper soliloquy of justification every time you touch either?

The difficult task won't be writing the safe alternative, it will be writing the unsafe one. And perhaps that difficulty will sometimes be justified, but it's not nearly so habit forming.

MaulingMonkey··on Just let me select text
Ya'll gaslighting me? I tried to do that, and found it didn't work, which was just wonderfully ironic. I ended up verifying there's a `user-select: none;` in the actual `select-text.html` styling that is indeed disabling text selection. Was it added later for shits and/or giggles?
← PreviousPage 2 of 34Next →