Hacker Newsnew | past | comments | ask | show | jobs | submit | nickcw's commentslogin

> And so, because I don’t want to hold Fn every time I want to press an F-key for its intended purpose, I used the arcane shortcut Fn+Caps to “lock” the keyboard into “standard” mode, where multipurpose F-keys remain multipurpose F-keys unless I hold down the special magic button that transforms them into rarely-used single-purpose special function keys.

> But here’s where the problem occurs. If the batteries get changed, or if the keyboard gets turned-off for an extended period, or sometimes – seemingly – just randomly… that function-lock gets switched off.

I have this problem with my Microsoft Natural keyboard; my favourite ever Microsoft product which helps me keep my RSI at bay.

Every now and again the Fn lock key gets pressed by accident. I then look very confused for some time as to why none of the Fn keys are working before I remember the dratted Fn lock key.

The Fn lock key is next to F12 so well in the range of accidental presses.

Maybe not many people drive their setup with function keys any more, I don't know.


I encounter that from time to time on my old Microsoft ergonomic too, you're not alone and its always confusing!

After I made the emulator I trawled GitHub to try to find games it could play within the 32K limit. I found yours - thank you :-) - and the ./try.sh script has an option to download it from GitHub for the user to test.

It's after the fact now, but I maintain a list of 32K Game Boy games on itch.io here: https://itch.io/c/3521183/game-boy-32k-roms

Great project btw


I pointed Claude Opus 4.7 at my Forth entry ( https://github.com/ioccc-src/winner/blob/master/2025/ncw3/pr... ) and it absolutely refused to have anything to do with it citing security violations and accusing me of creating malware :-)

Claude seems OK with it now, so I don't know whether that was a glitch but it was quite funny.


I was talking to a Claude Opus 4.7 chatbot about low-discrepancy sequences and made the mistake of framing a thought experiment as "deceiving" a vendor who owns a scrambler by making a hard to scramble low-discrepancy sequence generator. Admittedly that sounds sketchy but the conversation up to that point--without the explicit framing--was about the same subject just shorn of metaphor. With the framing I got a refusal message that likened my request to Dual_EC_DRBG!

Glad you enjoyed it :-)

If you want to see how the sausage was made, here is the source:

https://github.com/ncw/ioccc-gameboy

You'll find an unobfuscated version (kind-of) there too. This the the one I actually worked on then I had a program squash all the variable names and squeeze it into the gameboy shape

The size limit for the entry was the killer. You are allowed 2503 non white space characters (a simplification - the rules are complicated) in IOCCC entries and 4K total code size. This isn't a lot to fit a Z80 processor and a GameBoy hardware emulator in!

I first wrote a full Gameboy emulator in C. It started out at about 6000 non white space characters. I then spent about about 100 hours work trying to get it to fit into the 2503 limit. For a long time I wasn't sure it was going to fit.

I decided making the emulator play Tetris (which is a fairly simple game) was the target so I stripped out features like the half carry flag in the Z80 emulator and the windowing system in the Gameboy emulation which Tetris didn't need. I also abused the C code terribly doing things with implicit int I can never un-see. I also got creative with the IOCCC rules which are implemented in a C program which checks your source and I spent some time reverse engineering that looking for loopholes! I discovered that the operators defined in <iso646.h> only count for one token which was very useful.

Once I had it small enough I had to supply some games to run with it. I created 4, a test program written in z80 assembler, a pi calculator (written in assembler), a 3d tic tac toe game (written in C with gbdk-2020) and a chess program also written in C. I discovered that quite a few open source games ran on the emulator too so I added a downloader for those where I could. Apparently not many games use BCD arithmetic - who would have thought!

It was a fun project.


Very cool! Clearly I had a long way to go with mine to get it under the IOCCC requirements :) Though my goal was specifically Pokémon... curious how much more you would need to be able to run that.

Uh... is this supposed to be valid standalone C?

GCC says there are a bunch of undefined symbols, first one being "R" right in the beginning:

  typedef  unsigned  char u;
  u w,X,T,D[1<<16],t[]=R,U=255;

That's defined in Makefile

That is correct. It is cheating, but the judges let a small amount of it slide, especially if you come up with an amusing enough justification. I could not get it to fit otherwise!

I'm not a judge or a competitor, but I feel like a little bit of cheating on the rules is within the spirit of the game. Especially if it a) it makes it more obfuscated and b) it wouldn't have fit otherwise.

"The best kind of correct." -No. 1.0, How Hermes Got his Groove Back, Futurama

Considering that one historical entry (winner maybe?) consisted of a source file that simply contained the character ‘c’, plus a makefile, I’d say it’s in the ball park.

Link local addresses are exactly that. They don't route and they are for low level stuff like adding stuff to the routing table or BGP.

If you want to do this properly then you configure a Unique Local Addresses (ULA) out of the range fc00::/7. These are the equivalent of 192.168 or 172.16 or 10. and they can be routed.

Trying to run services on fe80: addresses is a mistake IMHO


So then shouldn't the link-local address be either MAC-derived or random, especially if you have multiple ifaces? The article's fe80::4 example seems weird. Mine is fe80::18cf:85a3:bc97:d117.

It usually is, but I don't think it has to be. You can definitely manually assign link-local addresses.

Note that even a MAC-derived link-local may not be unique, since the same MAC can be on both networks (e.g. with VLANs, or if you assign MACs to hosts instead of NICs).

That brings back fond memories of my first employer in the early 90s.

They used to rent a single scan line (VBI) of the TV broadcast to use as a data transmission method encoded the same way Teletext was. IIRC you could fit 45 bytes in a single scan line, with 50 per second that gives you a nationwide data broadcast capability of something like 18 kbit/s. We had a 19,200 bits/second leased line to send the data.

That scan line was really really expensive I seem to remember! If your TV wasn't quite adjusted properly you could see the data scan lines at the top of the screen as flickering white dots and lines which was fun.

The data got sent to financial institutions for real time stock feeds and nationwide networks of shops.

I never worked on the code for that part of the business though - I worked on the replacement system which ran via satellite with much more bandwidth at much lower cost.

Eventually the internet killed that too :-)


I love learning about pre-internet ways of transferring data on the back of other things. Another cool example is that the UK is only shutting down its longwave AM radio service this month (as opposed to decades ago) because the carrier is phase-modulated with data telling older electric meters to switch over. For years this was the only reason such an antiquated radio system stayed alive.

In Munich (Germany), a lot of the displays at bus and tram stations get their data via a side leg on the FM radio broadcast of local station B5 aktuell [1]. More details are here [2], apparently it's called "Axentia iBus FM/DARC".

[1] https://www.mikrocontroller.net/topic/232846

[2] https://apollo.open-resource.org/mission:log:2014:08:08:darc...


I love learning about pre-internet ways of transferring data on the back of other things.

I once worked for a radio station that made 90% of its revenue from carrying data feeds on subcarriers, and not from main music programs.

Because of the geographic location and size of the signal, it was a vital link between two major cities before planting fiber optic lines became cheap.


I’m looking forward to cell phones un-shackling themselves from telecom oligopolies through a mix of repurposed satellite uplink and where available: some FM spectrum downlink utilization.

Just stream me the weather, traffic, text msgs & some news stories that a TTS can read out to me.

Won’t work well for streaming a video but for most of us generally on wifi except out-of-doors, I can live with it.


Just stream me the weather, traffic, text msgs & some news stories that a TTS can read out to me.

SiriusXM is half way there. It supplies weather and traffic as a data service.

I knew about traffic from way back when the service was new, and found out Sirius Marine Weather a few years ago, but recently rented a car that also had Sirius-delivered weather and traffic alerts.

It was very useful as I was deeply off the grid (no radio stations at all during the day and AM skywave only at night), and the car alerted me to nearby lightning and thunderstorms that I couldn't see because of the terrain.


Up here in the north of Scotland the various council water and drainage departments often had to send data from remote data loggers (high tech stuff in the early 80s). Some of them would transmit a little ping of data every few seconds and if it heard a reply it would send several bursts of data quickly, using meteor scatter[1] to get it back to the receiving station hundreds of miles away.

All gone now, it's all 4G.

A few hours drive north of me is Mormond Hill, formerly the site of one part of the North Atlantic Radio System[2]. This used tropospheric scattering and huge dish aerials to communicate radar data down to RAF Fylingdales. There's not much up there now. There were various BT microwave links for offshore oil installations and assorted UHF and VHF links up, but the masts are pretty bare now.

[1] https://en.wikipedia.org/wiki/Meteor_burst_communications

[2] https://en.wikipedia.org/wiki/North_Atlantic_Radio_System


You should check out the Media Archeology Lab, they are very interested in alternate networks of all types! https://www.mediaarchaeologylab.com/

> I love learning about pre-internet ways of transferring data on the back of other things

See Minitel from France and Telidon from Canada as other examples of data systems riding on analogue TV and/or POTS telephone systems.


> If your TV wasn't quite adjusted properly you could see the data scan lines at the top of the screen as flickering white dots and lines which was fun.

There was a stock fault on BRC 1400 series valve TVs where a resistor in the brightness network would drift high in value and cause uncontrollable bright flyback lines in the upper half of the screen, and you could see those wriggly dotty crawlies ;-) I can't remember the component number - I think I last replaced one when I was 15 or 16, they were the teenage bedroom hand-me-down set of choice in the 80s, absolutely scads of them about in all sizes - but I can still picture in my mind's eye exactly where on the board it is, 220kΩ, red red yellow.

All long gone now, I expect.

If you find one do not re-cap it - the capacitors will be fine. They always are, there aren't any tantalums in it. Instead pay attention to everything above about 200kΩ and find out which ones are now closer to 1 meg!


They used to rent a single scan line (VBI) of the TV broadcast to use as a data transmission method

In the days before cable TV was widespread, there were over-the-air devices to give you a "TV Guide" page, like your cable/satellite service does now.

It was a tiny gray box about the size of a VHS tape, with a cute antenna sticking out of the top.

It constantly received program listing data through scan line data services, and filtered the listing by your ZIP Code. It displayed its TV Guide page on channel 3 or 4, and passed through the rest of the spectrum from your antenna. Because of this, it could even switch channels for you.

It cost something like $40, and after that was a totally free service, with no advertisements.

I'm pretty sure I got mine at Radio Shack, so it's probably listed in the catalogs around 1994 or so.


I found a similar vulnerability in the Zeus Web Server ( https://en.wikipedia.org/wiki/Zeus_Web_Server ) in January 2000.

Zeus had a great feature where you could set up virtual servers just by creating directories. So if you wanted to host www.example.com and www.anotherexample.com you just created two directories of those names like that and away you went.

I discovered that the if you sent `Host:` headers which started with `/` then you could use it to traverse the file system and read any file you wanted.

Plus ça change, plus c'est la même chose!


If you read the advisory and are wondering what starlette is, from it's web page: starlette is a lightweight ASGI framework/toolkit, which is ideal for building async web services in Python.

It's used a lot in the data heavy AI world for it's efficiency shipping large files. This includes lots and lots of production servers.

From the advisory: this includes LLM inference servers like vLLM, LLM proxy servers like LiteLLM, AI agent frameworks, MCP gateways, and custom APIs. MCP servers are especially at risk because the MCP spec mandates unauthenticated OAuth discovery endpoints, providing a reliable path for exploitation.


Notably, Starlette powers FastAPI, an extremely popular Python framework for building HTTP services.


Is this still true?


You may be thinking of Litestar (previously named Starlite) that was based on Starlette akin to FastAPI but then went their own direction implementing a framework rather than relying on an upstream for their core product.



..And?


FastAPI depends on "starlette>=0.46.0"


And? It's a non-sequitur to my comment.


Yes, it's literally the first bullet point on the project's website.


Ironically typing ‘make sure my server is secure’ into an LLM either wasn’t done, or missed it until now.


The posted page has an entire section titled "Why didn't Mythos find this?"

tl;dr: the bug spans three components in different code bases that when looked at in isolation each do reasonable things. The bug is in the interaction, in the assumed properties of the value that eventually gets exposed as request.url.path. That was apparently too subtle for current Anthropic models to spot


So an LLM was unable to reason about a codebase to find cross-library vulnerabilities.

Your response was a weak excuse, it’s a clear demonstration of the shortcomings of LLMs which will inevitably cause headlines in the future.


If you point an LLM at a middleware and ask it to find vulnerabilities, then not finding this is a shortcoming.

Whether "LLM failed to spot vulnerability that took humans 8 years to find" is a great headline about shortcomings of LLMs is questionable, but it is a good example of a category of bug that is particularly hard to spot for humans and LLMs alike


When the past month has been full of headlines claiming that Mythos et al. will be the end of secure software as well know it, it's fair game to emphasize the places we know already are not going to be covered by them.


The posted page said that finding logic bugs of this kind requires ‘understanding’ which LLM cannot.


Go doesn't have colored functions due to its nice fat runtime hiding all the async magic away for us.

That makes it a pleasure to code concurrent stuff for IMHO.

It does have its own similar problems though - does a function return an error? If so you are going to need to plumb the error return through all the callers. Does a function need a context.Context? Ditto.

I guess you can't win them all :-)


And Haskell is an ensemble of rainbows. It's very fun and pretty to look at.

Type classes can smooth over some of it but it's not unusual to have to do some plumbing.


Same with the BEAM languages like Erlang, Elixir, and Gleam. Though it still bothers me that they call their green threads "processes".


That's mostly because BEAM uses an actor-style approach while predating the concept of actors, isn't it? Interesting artefact of history if so

Edit: upon rechecking, apparently that's not exactly right, and Erlang designers learned of actors after designing the language, which makes it all the more interesting


I've spent the last decade in erlang / elixir / OTP. I think a lot of the naming comes from the early use of erlang as effectively an "OS" for telecom switches.

I always joke that BEAM wants to be the operating system.


> I've spent the last decade in erlang / elixir / OTP.

Do you have a blog? I would love a peek into your unique experience.


Actors predate both Erlang and BEAM by significant factor


They are (lightweight) processes since they have no shared memory. Each process has its own stack and heap.


I've never thought about it that way, but that makes sense!


The terminology in Erlang predates green threads by a decade or so.


This is a subtle point that I've seen missed repeatedly, but: The reason that "color" is important is that if you have a function ten layers down in your stack that is the wrong "color", you now have to change that top-level function. There is no other option.

Propagating errors up the stack is not the same, because the top-level function is not developing an error return because of the 10-level-nested function. It is developing one because the function it called has one, and apparently, it needs to return it to its local caller. It's a local consideration. It is true that it may be a recursive local consideration where this was true 10 times, but the reason it is different is that it doesn't have to be that way. It could have been the case that the function 7 layers down handled the error somehow and it stopped propagating up the stack. But at each point, the consideration was local, and as such, amenable to local solutions other than just tossing the error up. If you choose to "correctly" plumb the error through all your functions, well, good on you for apparently being willing to apply good software engineering practices even when it's annoying, but this is just normal day-to-day function activity stuff.

By contrast, in a function coloring situation, if the color is wrong 10 layers down, you must change the calling function. It's a non-local consideration. You don't get to decide not to change it. You can't encapsulate it. You don't get a choice. It pollutes the entire stack, forcibly.

Another way to look at it is, if the function 10 levels down developed what you think is a color, but there is a way for the function 9 levels down to hide the color from the rest of the stack, even via a hack like simply dropping an error you really need or hackily constructing an object of some type to pass in, then it is by definition not a color. A color change can't be stopped by any way of writing an intermediate function. It must be propagated all the way up the stack.

If you don't have this, you don't have "color". Like, some people will say that in their language that maybe there is some way to encapsulate "async". If you can, then you don't have an async color. Although I will say that if your "encapsulation" is basically to run it in a non-concurrent environment, that's really not encapsulation. It isn't really "encapsulation" if you're giving up an entire major feature of the language, because that is something very visible to the rest of the program.

Go's context.Context is similarly not a color. You can always just create a context.Background() and pass that down. If you didn't have any context already in hand, which means you must not care about any of the features context offers, then that is usually a fine thing to do. Context is trivially bypassed if you don't want it. It can be encapsulated within a portion of the stack without "polluting" the rest of the stack like any other function parameter.

The key aspect of color is that it is not optional. It isn't something that you can just decide to ignore and stop passing up, or trivially create a value for passing down to other functions. You have to change the "color". Async is a color in many environments. There aren't really that many colors in programming languages because they are very, very quickly inconvenient and we tend to squeeze them out. (Haskell really sticks out here as a language that is not only capable of creating arbitrary colors, but where this is an explicit tool used by the community rather than a limitation, and they even have ways of combining colors together deliberately.) Statement versus expression distinctions are another one, where a "statement" may not be usable in an "expression", and you'll note how languages have in general erased that one over time because it's really just a cost without much benefit.


That's just not true. Let's say you have a form validation library with a public api that supports custom validators Validate(name string, value string) bool. Then you decide that your validator now needs to make an HTTP request. This request needs context so that tracing is propagated and needs to return (bool, error) so that error is propagated up instead of silently ignoring it or logging it and returning false. This is coloring. You can use context.Background the same way you can use blocking in other languages. It just doesn't feel right and it breaks things.


If "caring about arguments" is "color" then the concept is useless and who cares? If everything is a "color", nothing is.

The color concept is interesting precisely because it isn't just "arguments to functions". The difference I describe is a real one that has real effects at scale. Trying to collapse it down to "it's just function arguments" doesn't make it go away, it just makes it so anyone who refuses to draw the distinction loses the ability to see it. It's not a good idea and it's not a good argument. You're just smearing vaseline on your eyes.


With (unchecked) exceptions the custom validator can abort the whole stack non locally and transport the error to the original call stack, the validation library being none the wiser.

With stackful coroutines, the custom validator can transport the error to the original call site, handle it and resume back into the validation library if the error was recovered, or abandon the validation (as with exceptions) if unrecoverable.

With HKTs, the validation library can be agnostic on the specific return type of the custom validator.


> Propagating errors up the stack is not the same, because the top-level function is not developing an error return because of the 10-level-nested function. It is developing one because the function it called has one, and apparently, it needs to return it to its local caller. It's a local consideration ...

> By contrast, in a function coloring situation, if the color is wrong 10 layers down, you must change the calling function. It's a non-local consideration. You don't get to decide not to change it. You can't encapsulate it. You don't get a choice. It pollutes the entire stack, forcibly.

I think this is an interesting perspective, where I would raise a counterpoint. Both result types and async/await are instances of monads (the abstraction which approximates the article's idea of a function color, since you mentioned Haskell, I assume you know this). Just as you can "eliminate" the result type by explicitly handling the success and error cases, you could, theoretically, "eliminate" the async function by blocking on it. Doing so would treat the entire async subprogram, at the top-level function boundary, as synchronous IO, while the async subprogram would still benefit from concurrency internal to the function.

Compare Example #1:

    int topLevel() {
      return match fallibleSubprogram() {
        Ok(()) => 0,
        Err(_) => 255,
      };
    }

    Result<(), Err> fallibleSubprogram() {
      let x = f()?;
      let y = g()?;
      return h(x, y);
    }
Compare Example #2:

    int topLevel() {
      block_on(asyncSubprogram);
      return 0;
    }

    async void asyncSubprogram() {
      let promiseX = f();
      let promiseY = g();
      let [x, y] = await Promise.all([promiseX, promiseY]);
      return await h(x, y);
    }
In the above pseudo-code, you have the same program "structure," but the first uses results and the second uses promises. In the latter example, asyncSubprogram() gets called as if it were synchronous, but you still benefit from asynchronicity because f() and g() can execute concurrently within its body.

The main difference is that compared to pattern matching on Result types, programming languages typically make it unidiomatic to block on a promise. There are various reasons why this is the case, but my point is that Result types and async/await are more similar than they may initially appear.


"Just as you can "eliminate" the result type by explicitly handling the success and error cases, you could, theoretically, "eliminate" the async function by blocking on it"

You really can't. Shutting down the async loop doesn't just do damage to the performance of the program, it can actually affect correctness. It doesn't fix the color problem. That's why I said 'Although I will say that if your "encapsulation" is basically to run it in a non-concurrent environment, that's really not encapsulation. It isn't really "encapsulation" if you're giving up an entire major feature of the language, because that is something very visible to the rest of the program.'

Monads actually aren't really relevant, either. A monad can express something you can't escape from, but it isn't required; "Option" isn't a color because you can still deconstruct it any time you like. It's specifically IO, which traps you not because it is a "monad" but because it has no escape hatches at all. (Modulo "unsafe", which is always something we have to say, but we also always tend to ignore unsafe in these discussions because otherwise everything collapses to one big unsafe pile in all languages of note.)


I'd argue that Go and all other implicit async approaches do have function colours. You're much less likely to notice the colour, but in the edge cases where it can be noticed such systems are harder to work with.


LLMs are very prone to priming in my experience. That is the human psychology name for what you are describing; whether it should be applied to LLMs I don't know, but it describes the phenomenon perfectly.


Makes sense as priming is at the core of how an LLM is trained.

“Given these words, predict the next word.”


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: