Rendered at 20:04:05 GMT+0000 (Coordinated Universal Time) with Cloudflare Workers.
bananamogul 2 days ago [-]
Raymend Chen has probably forgotten more about programming than I'll ever know, but aren't the first two blah() function examples either missing a } or have a superfluous { after the else?
billforsternz 2 days ago [-]
Yes. And in the second one he has return c; when he meant return b;
Homer nods.
Onavo 2 days ago [-]
[flagged]
camkego 2 days ago [-]
Why? Because of LLM vibe coding?
dataflow 2 days ago [-]
Yeah. The next generation of software engineers is coming. Brace yourself.
tdeck 2 days ago [-]
Eternal sloptember?
smcin 2 days ago [-]
Heavens forfend
burner420042 2 days ago [-]
Instantly finding a missing semicolon or unbalanced parentheses on a screen of text.
Kids these days!
CodeArtisan 2 days ago [-]
Until C23, you could declare a pointer to a procedure that takes an unspecified amount of any type arguments like this
If you compile with -std=c23, both gcc and clang will throw an error ( (*f)() is now the same as (*f)(void) )
AshamedCaptain 2 days ago [-]
You do not need the pointer at all. f() not specifying the arguments has been the case since forever. "Prototypes" (90s) are newer than C.
anitil 2 days ago [-]
I had never considered the idea of passing too few register params so I didn't immediately think of the reuse problem. And I had no idea about Itanium's Not-a-thing bit! Always a good read from Raymond Chen.
charleslmunger 2 days ago [-]
I had fun exploiting this to detect the falling convention used by some code at runtime - there were two different options depending on OS version; one passed a jnienv* as the first param, the other did not. So if I called it with 0, I could tell which was being used based on whether the first argument was NULL or not. Only used for specific architectures with a defined ABI that behaved this way, of course.
LelouBil 2 days ago [-]
Interesting that some CPUs have a calling convention "built-in"
_kst_ 2 days ago [-]
It's not even possible to pass too few arguments to a function in C unless you go out of your way to write bad code.
You can write a function declaration that's inconsistent with its definition in another translation unit. Declaring the function in a shared header file avoids this.
You can use an old-style declaration that doesn't specify what parameters a function expects. Don't do that. Use prototypes.
You can use a cast to convert a function pointer to an incompatible type, and call through the resulting pointer. Don't do that.
You can call a function with no visible declaration if your compiler overly permissive or is operating in pre-C99 mode. Don't do that.
FartyMcFarter 1 days ago [-]
> It's not even possible to pass too few arguments to a function in C unless you go out of your way to write bad code.
This article is exclusively about undefined behaviour. "Bad code" is already baked into the assumptions of the article.
userbinator 2 days ago [-]
This is a site for intellectual curiosity, not pedantic dissmisal.
themafia 24 hours ago [-]
Wait. Isn't the thing you're doing right here _exactly_ "pedantic dismissal?"
Looking at your comment history that seems to be _your_ mode.
_kst_ 1 days ago [-]
Seriously?
I discussed some of the technical issues behind the article. If you disagree with anything I wrote, please say so.
I'm not even saying that the issues discussed in the article aren't useful, just going into how likely they're likely to be encountered in practice.
themafia 24 hours ago [-]
Hacker News does not like actual hackers.
themafia 2 days ago [-]
You could also use inline assembly.
hyperhello 2 days ago [-]
Do you really not ‘pass’ register parameters? How can anyone tell if you didn’t?
Polizeiposaune 2 days ago [-]
Read the post - not all architectures behave the same!
Itanic had variable-sized register windows, plus extra tag bits for NaT ("not a thing") placeholder values. If you didn't set one of the argument registers the callee might trap in unexpected ways when it touches the register garbage.
hyperhello 2 days ago [-]
Heh, it had rotating register files too. VLIW was so weird.
ithkuil 1 days ago [-]
Sparc (not a VLIW ISA) also had rotating register windows. But ia64 had a twist on it: the register window size was dynamic and "allocated" by the callee with an alloc instruction
The only other ISA I know of that did something similar was the Am29000
The Am29000 modeled it in an interesting way though:
The register file consisted of 128 global registers but the instruction encoding allowed to specify an "indirect register index" mode where the operand register was computed from the content of gr1 plus an offset. Thus gr1 acted as a "register window stack pointer". I _think_ such a computed register index would then be used to index into a separate register file for locals (and arguments etc) but I'm not sure.
Anybody here is familiar with this quite old ISA?
(I'm really interested in the richness of the CPU design space, the history of which is fascinating)
inkyoto 1 days ago [-]
Rotating register windows are a distinguishing feature of the Berkeley RISC design, which predates VLIW by at least a decade.
9fwfj9r 2 days ago [-]
I regard this yet another unintuitive Itanium quirk that makes it failed.
marlburrow 2 days ago [-]
[flagged]
rurban 2 days ago [-]
Of which decade is this post? I cannot think of any modern architecture which still passes args on the stack.
Itanium? Stone age
jcranmer 2 days ago [-]
If you have 29 arguments, I assure that you some of them are on the stack in nearly every architecture in use. Also, certain types as parameters also get passed on the stack (usually types larger than a register, or in C++ code, objects with nontrivial constructors or destructors).
rurban 2 days ago [-]
Sure, but he still came up with a 2005 blog post, and attached a 2026 to it. No optimizing C compiler cares for the 2nd arg, when it's a register anyway. And if the 1st is constant, the dead branch is folded away. So the 2nd arg is dead
inkyoto 1 days ago [-]
The vast majority of virtual machines, including JVM and .NET, are stack based.
And, whilst compiling C and C++ the JVM / .NET CLR byte codes is very uncommon, both VM's have become very popular compilation targets for other programming languages.
Homer nods.
Kids these days!
If you compile with -std=c23, both gcc and clang will throw an error ( (*f)() is now the same as (*f)(void) )
You can write a function declaration that's inconsistent with its definition in another translation unit. Declaring the function in a shared header file avoids this.
You can use an old-style declaration that doesn't specify what parameters a function expects. Don't do that. Use prototypes.
You can use a cast to convert a function pointer to an incompatible type, and call through the resulting pointer. Don't do that.
You can call a function with no visible declaration if your compiler overly permissive or is operating in pre-C99 mode. Don't do that.
This article is exclusively about undefined behaviour. "Bad code" is already baked into the assumptions of the article.
Looking at your comment history that seems to be _your_ mode.
I discussed some of the technical issues behind the article. If you disagree with anything I wrote, please say so.
I'm not even saying that the issues discussed in the article aren't useful, just going into how likely they're likely to be encountered in practice.
Itanic had variable-sized register windows, plus extra tag bits for NaT ("not a thing") placeholder values. If you didn't set one of the argument registers the callee might trap in unexpected ways when it touches the register garbage.
The only other ISA I know of that did something similar was the Am29000
The Am29000 modeled it in an interesting way though:
The register file consisted of 128 global registers but the instruction encoding allowed to specify an "indirect register index" mode where the operand register was computed from the content of gr1 plus an offset. Thus gr1 acted as a "register window stack pointer". I _think_ such a computed register index would then be used to index into a separate register file for locals (and arguments etc) but I'm not sure.
Anybody here is familiar with this quite old ISA?
(I'm really interested in the richness of the CPU design space, the history of which is fascinating)
Itanium? Stone age
And, whilst compiling C and C++ the JVM / .NET CLR byte codes is very uncommon, both VM's have become very popular compilation targets for other programming languages.