>>>no security issues have ever been found in my code, and I test a lot. Therefore no bugs will ever exist in my code and we're all safe<<<
That’s not what I have said. 35 issues (mostly minor, but a couple of remote denial of service attacks) have been found with my code in the last 25 years; of those, none have come from the PRNG code I used. Here in the age of AI, I get multiple security reports a year, so the code is being looked at.
With crypto, you can never know for sure the code doesn’t have weaknesses, but one can have confidence in code and algorithms which have been around for years without any weaknesses discovered in them.
My question is: If code being around for years doesn’t build confidence in it being secure, what would it take to build confidence in the code.
What you’re seeing here is two schools of thought: One is the issue with using uninitialized memory, which yes does result in undefined behavior as per the C99 spec—but, back two decades ago when I made that decision, GCC was the only compiler of significance (clang was just released but was not widely used until years later) and its behavior was to put randomish data in undefined allocated memory.
The other is the notion that only Linux Kernel developers can develop a secure PRNG, and obviously I find that attitude very condescending and arrogant.
> My question is: If code being around for years doesn’t build confidence in it being secure, what would it take to build confidence in the code.
One of my experiences with programmers is that we (and I do not exclude myself from this category) are extraordinarily bad at sufficiently imagining the failure paths that our code might take and making code work handle failure cases correctly. It's these erroneous failure paths that are the real issue with code, and age doesn't really indicate how much testing of those failure paths actually exist.
To build confidence in code, what we need is proactive testing of potential failure paths that don't rely on humans to think of them in the first place--that means investment in various exhaustive testing techniques. (And I'd also like to see formal verification be more of a thing, but the tech just isn't there.) A stepping stone in that regard is also heavy use of static and dynamic analyzers to catch things that at known to be Obviously Bad™. The gold standard here really is whitebox concolic execution that's specifically trying to get something akin to 100% path coverage by trying to synthesize inputs to test the unhit paths.
Saying that it's okay to seed an entropy pool with uninitialized memory in 2005 is maybe defensible. There is a shift in compiler design around that time from thinking of it as compiling to a set of instructions and then optimizing them (so that the basic 'structure' of the code is something that's inherent to the program) towards looking at program semantics as abstract things where the only thing you need to preserve are the observable semantics [1]. One of the side effects of that shift is that undefined behavior stops being something that is fairly reliable so you assume you get the 'equivalent' assembly effects for that machine and starts being something that really screws over code.
But it's not 2005; it's 2026, and this change in compilers has been heavily advertised, discussed, complained about for well over a decade. And if you're using the kind of tools that give me confidence in code, those tools would have been bitching about that behavior for decades. If this is a surprise to you in this time and age, then it suggests to me that you've not really been proactive in trying to test your code in the manner I suggest, or worse, you have been proactive and decided to ignore everything telling you your practices are wrong because you know better than the tools and your code isn't obviously wrong.
(I say obviously wrong because your code example does demonstrate, when I tried it in the latest version of clang on godbolt, that it is eliminating the seeding of the entropy pool, in a way that is actually pretty clear if you read the assembly.)
[1] One of the most concrete examples to really observe the difference is the concept of control flow. Compilers nowadays are really happy to turn control flow (if statements) into dataflow (conditional moves or funky bit manipulations) and vice versa, because the only thing that needs to be preserved is the final value. Of course, cryptographers keep complaining that we broke their code by turning their obfuscated dataflow-based if statement into an actual if statement and so it's no longer constant-time, no matter how many times we keep telling them that we do not make any pretense of guaranteeing constant-time execution of code.