
Boringcc: Proposal for a C compiler for secure software - DCKing
https://groups.google.com/forum/m/#!msg/boring-crypto/48qa1kWignU/o8GGp2K1DAAJ
======
tacostakohashi
I've always thought that there would be more value in exactly the opposite - a
pathological C compiler (or C++ compiler, POSIX operating system, etc.). The
pathological compiler would always implement undefined behavior in the most
surprising, unpredictable manner - e.g., uninitialized memory would have a
properly randomized value that changes from one run to the next, overflows
would result in random values, etc.

That way, any programs that are made to work on the pathological
implementation are largely guaranteed to rely only on standardized behavior,
and work on any other standards compliant implementation.

~~~
qb45
I don't know if it's guaranteed to bark on _all_ possible cases of UB, but
there we go:

    
    
      $ cat test.c
      int main() {
              return *(int*)0;
      }
      $ gcc test.c -fsanitize=undefined -o test
      $ ./test
      test.c:2:9: runtime error: load of null pointer of type 'int'
      Segmentation fault
    

I'm pretty sure I've seen similar tool based on clang as well.

And there is valgrind.

~~~
an_d_rew
Just for the hardware-minded: dereferencing null is perfectly fine on Cortex-M
processors and is well-defined.

Yes, that's hardware, but a nice place where hardware ain't C.

I'm just sayin'...

~~~
klodolph
Dereferencing NULL, in a C program, is ALWAYS undefined behavior. The fact
that you are using a Cortex-M processor does not change this fact. It is
spelled out very clearly in the C standard.

~~~
silon7
I've used at times it to crash the program (core dump), producing a cleaner
stack than abort().

~~~
astrange
You should use __builtin_trap(). Invoking undefined behavior lets the compiler
justifiably delete the entire code path leading up to it.

------
petke
> I'd like to see a free C compiler that clearly defines, and permanently
> commits to, carefully designed semantics for everything that's labelled
> "undefined" or "unspecified" or "implementation-defined" in the C
> "standard".

That wouldn't just be a new compiler. That would be a new language. I dont
think there are any short cuts to fix C.

C++ is doing something somewhat similar with the "C++ Core Guideline" rules,
which are designed to be checkable by static analysis tool. The long term goal
is that eventually C++ will become a safe subset, when all the error-prone
parts of the language have replacements.

> "Following the rules will lead to code that is statically type safe, has no
> resource leaks, and catches many more programming logic errors than is
> common in code today. And it will run fast - you can afford to do things
> right."

[https://github.com/isocpp/CppCoreGuidelines/blob/master/CppC...](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md)

~~~
geocar
> That would be a new language

I don't see why it wouldn't be a valid implementation of C by simply defining
things that C doesn't fully define.

There's nothing about the definition of "undefined behaviour" that _prevents_
you from defining it in your implementation.

~~~
steveklabnik
Because then you are relying on a specification that's not in the spec. A
different interpretation means that your code no longer works. Therefore,
you've effectively created a new language.

~~~
quotemstr
Sixth grader students know all the words third grader students know, but third
grade students do not know all the words that sixth grade students know. Are
the third and sixth grade students speaking different languages?

~~~
steveklabnik
In a certain sense, yes. Sixth graders can say things that third graders
cannot understand.

The trick is to try to bring together all of these dialects in a way that
everyone can in fact understand. This is why writing language specifications
is _hard_.

And even afterwards, you can still choose a dialect over the standard. You'll
just lose a certain segment of your audience. That may or may not matter for
your purposes.

------
xorblurb
At this point you pretty much want an alternative language more than a
compiler: one that looks like C, but is completely defined. And this makes
kinda sense, yet is IMO still quite dangerous (less than the actual situation
but still too much)

1/ There are tons of people who will say: "this project is written in C"
instead of the reality that is that this project is written in boringC,
(actually probably even most of the projects authors will) and will for ex.
compile with a regular C compiler instead of a boringC one, maybe for
performance improvement...

2/ You just can't take C, even with a completely defined semantics, and call
it a day for secure programming. It would still be filled with crazy features
that are intrinsically impossible to render secure (everything about C
"arrays" comes to mind)

So let's take this idea to its real destination and rewrite secure projects
using a really secure programming language, instead of just extending the
current mess for 30 more years.

~~~
fbbbbb
So what do you do when an index into an array is out of bounds at run-time.
You can't perform a check every time because that would go against the C's
principle, and at the same time it would degrade performance, making it less
useful compared to newer languages.

How would you implement defined behavior without a significant (which is what
an if check is at that level) overhead in this case?

~~~
xorblurb
Compared to the economic cost of bugs, bound checks everywhere are (very very)
cheap. Even more so with the CPU and compilers we have today, which are more
than sufficiently smart from the point of view of when C was created. Intel is
even adding some new instructions in their CPU to make that even less costly
than you could imagine in even some crazy C based situation you would not
think to be possible in the first place, because of C. But the cost here is
extra complexity, for something that should have been built-in in the first
place.

More technically to address fears of slowdowns even with simpler
architectures, the additional checks will likely be factored most of the time
(for example before a loop with linear accesses). When they are not, to have a
real impact 1/ it has to be in a really hot code path (like 1% or maybe even
0.1% or even less of a real system) 2/ the cpu should not be able to use empty
OOO slots and execution units to execute it without any extra penality 3/ this
is quite a deduction from the two preceding points, but if we are talking
about a big array being accessed in random order this will be slow because of
RAM access anyway, an extra check won't induce any meaningful slowdown maybe
even if it were mispredicted (which it will not be - in regard to
performance).

Like always if you have any performance issue, first profile. And actually I
can't remember having ever heard a single person complaining that some bound
checking in a program was the cause of their slowdowns. It often far more
macroscopic, and easy to fix anyway when it is that much micro. Considering
usual modern systems, they are sometimes so slow that the problem is certainly
NOT native bound checking, but very probably architectural madness.

~~~
Symmetry
If you were frequently catching out of bounds accesses your CPU's branch
predictor would be making mistakes and you'd be frequently eating the branch
mispredict penalty. Any extra instruction or check that alters the control
flow is often much more expensive than just another addition. However, in this
case if you're taking the branch something is seriously broken so that you
should not be facing this. Pre-Haswell Intel CPUs only had one branch slot so
you still might have a penalty but as you say this isn't the end of the world.

------
dikaiosune
I'm someone currently in the process of drinking the Rust kool-aid, in part
because the goals of the language are very closely aligned with what Bernstein
proposes here. Further, because of the memory model, the compiler can produce
quite competitive performance while still preventing the execution of any
undefined behavior (related to his last strawman in the bullet list).

I get that even if Rust offers a panacea to the issues he mentions (which it
may or may not, I'm no expert), there's still an awful lot of C code that
would need to be deprecated and rewritten. But surely there'd be value in
efforts to get away from a language that has such a loose standard?

~~~
wspeirs
I wonder how hard it would be to create a C -> Rust transpiler. The output
would probably be God-awful, but it could be a start to moving away from C
towards Rust.

~~~
mcguire
A guess: very, very difficult. Writing code to satisfy Rust's checking is not
much harder than writing C[1], but converting arbitrary C to satisfy Rust is
something completely different.

[1] An' I say it as shouldn't. C is my natural language.

------
pcwalton
Required reading here is Chris Lattner's "What Every C/C++ Programmer Should
Know About Undefined Behavior", which goes into good detail as to why
undefined behavior is important for performance, sometimes very important:
[http://blog.llvm.org/2011/05/what-every-c-programmer-
should-...](http://blog.llvm.org/2011/05/what-every-c-programmer-should-
know.html?m=1)

Could you make a new language that doesn't depend on UB for performance? Sure,
quite possibly. Is C that language? Probably not.

------
jbandela1
This is actually something the ISO C++ committee is looking at.

See [https://isocpp.org/std/the-committee](https://isocpp.org/std/the-
committee) \- SG12

An example of this is P0145R0 which specifies the previously unspecified order
of evaluation.

See [https://isocpp.org/blog/2015/11/kona-standards-meeting-
trip-...](https://isocpp.org/blog/2015/11/kona-standards-meeting-trip-report)

Apparently, the performance difference is expected to be zero on currently
popular architectures and around 1% on older architectures.

------
pool
How far are we from having the will and ability for it to be common to use
safer languages than C/C++/Java/etc.?

A long time ago, it didn't seem pragmatic to write in, say, ocaml, because no
one was going to feel like building or even installing the compiler in order
to try your dumb software, but now that everything is about packages from
distributions...

Today it feels strange to apply security updates for necessary software where
the announcements list "Multiple memory safety errors, integer overflows, use-
after-frees..."

------
eliteraspberrie
It exists. It's called CompCert.

[https://github.com/AbsInt/CompCert](https://github.com/AbsInt/CompCert)

It's free for non-commercial use. I've used it for several months now to build
things like Tor. I haven't noticed any disadvantage compared to GCC or Clang.

~~~
ufo
I don't think compcert avoids undefined behavior pitfalls. Its more of a way
to protect yourself from compiler bugs.

~~~
nickpsecurity
It's a verified subset of the C standard rather than all behaviors of all
compilers. There's some semantics and work covering a lot of that already that
just needs to be integrated into CompCert or static analyzers. Likewise,
there's static analyzers that already cover it too but not formally verified.

Here's an example of investigating that with Compcert:

[http://robbertkrebbers.nl/research/articles/compcert_formali...](http://robbertkrebbers.nl/research/articles/compcert_formalin.pdf)

Here's a semantics that looks for flaws and undefined behavior:

[https://www.ideals.illinois.edu/bitstream/handle/2142/34297/...](https://www.ideals.illinois.edu/bitstream/handle/2142/34297/Ellison_Charles.pdf?sequence=1)

------
tmalsburg2
It sounds as if the root of the problem is the C standard. Wouldn't it be
better to fix that instead of creating a shadow standard defined by the
implementation of this boring compiler?

I also object to the presupposition that there is secure software and non-
secure software. In most practical cases, it is impossibly hard to tell in
which class an application falls, so it would be better not to make that
distinction at all.

~~~
beefhash
>It sounds as if the root of the problem is the C standard. Wouldn't it be
better to fix that

Isn't the reason for a lot of undefined behavior either in the name of
performance through optimization and assumptions, portability because the
implementation can just do whatever the underlying platform natively does or
the committee just couldn't agree on it?

All three of those scenarios appear inherently unfixable to me without a
separate sub-standard that intentionally clamps down on performance/ease of
portability and actually gets the committee to agree.

~~~
tmalsburg2
I don't know the reasons for why so many things are undefined in C. However,
if a program does one thing when compiled with compiler A and another thing
when compiled with compiler B, how does that help portability? To my perhaps
naive mind this makes portability harder to achieve not easier.

~~~
pjc50
A classic example of trying to define behaviour regardless of what all the
different hardware does is Java choosing IEEE754 floating point. Which isn't
natively supported on x86.

[https://www.cs.berkeley.edu/~wkahan/JAVAhurt.pdf](https://www.cs.berkeley.edu/~wkahan/JAVAhurt.pdf)

If C had standardised to the idiosyncracies of the PDP-11, it might have held
back its development.

~~~
jey
Are you referring to 80-bit floats used by the (long obsolete) x87 FPUs?

~~~
pjc50
The 80-bit floats were still in use right through the 2000s; I know because I
had to work out what option to use to get reproducible fp rounding on 64-bit
doubles in 32-bit C. I've not had occasion to look at the details of amd64 fp.

------
atemerev
Writing secure software in C is just next to impossible. Memory corruption,
arbitrary pointers, deep magic. Even pure assembly is more secure, as
everything is explicit and well-defined there. There are lots of safer
languages than C, and performance is not everything.

~~~
rosser
Then how do you explain the fact that some of the most secure pieces of
software ever written were written in C? (I'm thinking of, e.g., Qmail — and
pretty much everything else DJB has ever written — and OpenBSD, just to name a
couple off the top of my head.)

I would also qualify your statement that "performance is not everything" to
say that performance isn't _always_ everything. Writing a kernel in an
interpreted language probably isn't the best idea, for example.

~~~
gherkin0
> Then how do you explain the fact that some of the most secure pieces of
> software ever written were written in C? (I'm thinking of, e.g., Qmail — and
> pretty much everything else DJB has ever written — and OpenBSD, just to name
> a couple off the top of my head.)

Unusual amounts of manual effort by unusually skilled people, probably using
unusually security-focused development processes?

~~~
nickpsecurity
Exactly. Freak occurrences never disprove the rule. Most were simple, too, to
the point that it's easier to get right. Large one's like OpenBSD had plenty
of bugs during the development process. Many problems in small and large are
prevented with a language that doesn't introduce them.

Rest has to be caught with other methods. A good language can still help,
though, if it's easier to analyze.

------
sz4kerto
" Claim that all we need is for some particular "undefined"-catching tool to
be widely used. In fact, these tools are full of false positives and false
negatives; at best they catch a few limited types of "undefined" behavior, not
changing the big picture."

Question: why can't existing C compilers clearly indicate when they encounter
undefined behavior?

~~~
MereInterest
Undefined behavior is primarily something that that has effects, rather than
at compile time. For example, taking the value of an uninitialized local
variable.

    
    
        int main() {
            int i;
            if(some_big_complicated_function()){
                i = 0;
            }
            printf("%d\n",i);
        }
    

Is this undefined behavior? The compiler can't be sure, because it can't know
whether `some_big_complicated_function()` returns true or not.

Therefore, it would need to be a runtime check, rather than a compile time
check. But runtime checks are expensive, and so it typically isn't done. It
would be entirely allowed by the standard to give such a warning at runtime,
but the resulting program would go much, much slower due to all the checks.

~~~
bmm6o
What you say is true, but this case could easily trigger a warning about
_possible_ use before assignment. The compiler doesn't have (and can't) to
prove that either branch will always be taken at runtime. And there's no
benefit to code like this anyway, just write it so it's obviously to be
assigned. Your coworkers will thank you.

~~~
bmm6o
And really, the main benefit to not assigning a value in the declaration is to
get the compiler to tell you if there is a code path that misses an
assignment.

    
    
        int i;
        if (foo || bar)
            i = 1;
        else if (baz) {
            if (!quux)
                goto fail;
            i = 2;
        }
    
        printf("%d", i); // not all code paths assign a value

------
joshka
Non mobile link: [https://groups.google.com/forum/#!msg/boring-
crypto/48qa1kWi...](https://groups.google.com/forum/#!msg/boring-
crypto/48qa1kWignU/o8GGp2K1DAAJ)

------
tikums
OpenBSD (+LibreSSL) folks have been uncomfortable with unpredictable compiler
optimizations for quite a while too. Here's a previous discussion on compilers
in OpenBSD:
[https://news.ycombinator.com/item?id=9322259](https://news.ycombinator.com/item?id=9322259)

------
lisper
It has always seemed to me that the C community (and to an ever greater extent
the C++ community) takes particular pride in making it as difficult as
possible to write correct code. It provides bragging rights and job security
for those select few who have taken the time to master all of the arcana of
the language.

Personally, I tend to think that life is too short for that sort of thing.
That's why I choose Lisp, at least when it's up to me.

~~~
nickpsecurity
Surprised being a LISPer you haven't read Gabriel's Worse is Better essays on
the topic. Convincingly argue the reason behind the uptake of certain tech is
they do just enough of a good job to work and for a lot of people. Then they
get extended gradually in direction of what they should've been. C and UNIX
were perfect examples of this on crappy hardware of 70's-80's. By 90's, it was
legacy effect in play for various reasons. Still is.

Throw in organizations competing for money or ideology to get a bunch of
implementations of a language that was shit to begin with. So, it was more the
opposite of what you claim: too many groups trying to make things convenient
for themselves in the short-run. LISPers did something similar with their
individual messes getting merged into Common LISP. Those doing it clean and
sensible on the right hardware were always the outliers.

~~~
lisper
I have read "Worse is better." The point I was trying to make was different:

> Then they get extended gradually in direction of what they should've been.

Yes, this is the part I'm disputing. It seems to me that C and C++ are _not_
being extended in "the direction they should have been" but rather in a
direction that is beneficial mainly to a small incumbent minority. Everyone
agrees that security is important, and yet it is virtually impossible to write
secure code in C or C++, not because it would violate the laws of physics or
some mathematical theorem, but because both the standards and the
implementations are hopelessly brain-damaged.

~~~
nickpsecurity
"but rather in a direction that is beneficial mainly to a small incumbent
minority."

The majority of C programmers seem to fight changes to the permissive way of
doing things in name of efficiency and compatibility. I don't know what the
interplay between them, compiler writers, and standards bodies is. Yet, it
seems C programmers react pretty negatively to anything changing their
language even here. Just imagine how much of UNIX or GCC might break if we did
pre-fixed strings, a reversed stack, compiler-only pointer arithmetic, auto-
bounds checks, and so on. It would all just... COLLAPSE.

"yet it is virtually impossible to write secure code in C or C++, not because
it would violate the laws of physics or some mathematical theorem, but because
both the standards and the implementations are hopelessly brain-damaged."

Totally agree there that this is what resulted. Recently, on a new platform, I
needed to code up something that C programmers can read and I can't remember C
worth crap. So, I decided to re-learn FreeBASIC cuz even it's easier to get
right than C & I straight up can't stand C. Coding style wasn't... modern...
but worked, was type-safe, iterated fast, ran in milliseconds, and was very
readable. Stuff I can never say collectively about C without state-of-the-art
tooling on 4-8 core machine with RAM disks. ;)

------
Arnt
I don't understand this.

He's not asking for a -wundefined or -ansi -pedantic, he's asking for
definitions for everything -ansi -pedantic rejects, and a new compiler. Hard
work. Which of those cases are _that_ desirable?

------
gdwatson
I think the biggest problem with undefined behavior in C is that it is taken
to justify violation of C's customary semantics[1] on platforms where it isn't
necessary.

Many types of undefined behavior in the C standard are essentially
dispensations for Lisp machines or one's complement CPUs. It's very surprising
to see them invoked by the optimizer on more conventional platforms. It might
not satisfy djb, but a standard for these behaviors alone would be great
progress.[2]

[1] [http://arcanesentiment.blogspot.com/2014/12/customary-
semant...](http://arcanesentiment.blogspot.com/2014/12/customary-
semantics.html)

[2] Posix doesn't really address this, sadly. The committee seems to have
avoided standardizing byte size until an unforeseen interaction with a later C
standard pushed it into a corner.

------
aplorbust
Actual URL, accessible without Javascript:
[https://groups.google.com/forum/message/raw?msg=boring-
crypt...](https://groups.google.com/forum/message/raw?msg=boring-
crypto/48qa1KWignU/o8GGp2K1DAAJ)

------
Too
I think the problem is not the language standard per se, it's the education
and historically sloppy compilers. It's a bit like W3Schools for javascript
teaching everybody all the worst practices, that's not a problem with the
javascript language itself.

I mean really, what are the most common cases of undefined behavior that cause
real problems in the world? (Reading past array bounds or trying to
dereference uninitialized variables are such obvious _errors_ that i don't
categorize them as 'unexpected undefined behavior', the later is caught by
most compilers and static analyzers today anyway. Though i agree having the
length known in arrays would greatly help.)

Any time i see some raging blog post about how undefined behavior ruined
someones day it's 99% of the time because they one way or another were trying
to cast a pointer of one type to a pointer of another type, like thinking they
could read the first 16 bits of an int* by casting it to a short* first. The
root cause of this is because people think that pointers are addresses to a
sequential grid of NAND-gates on your DDR4-stick, when they in fact are
_abstract_ references to a variable that can carry a value. This comes from
school, where the way teachers show you how pointers work is exactly like
that. Tutorials on the internet also say that you can do smart tricks with
pointers just to teach you and then people think that's how you should do it.
When compiling in debug-mode this is how the memory is usually aligned so
things still work anyway.

Historically compilers didn't warn about this either and things still worked
so many people got used to writing things this way and today those people are
the "experienced C gurus" in companies that pass down this misbehavior to
their younger peers.

Overflow on signed arithmetic is another of the common pitfalls but that's
life if you code for embedded, the alternative solution that "just works"
would be to do all arithmetic in a BigInt type as python but that clearly
isn't viable on embedded, or to do everything in floating point but that has
its own pitfalls.

------
raverbashing
I don't think this can be done with C. Really

\- Remove all possibilities of memory aliasing. Only exception might be when
reading from devices/network (some kind of boxing, unboxing)

\- All array accesses are bounds checked.

\- Checked conversion between int/unsigned int and different sized items.
Converting a char into an unsigned int? Be explicit in what you want to do

\- No pointers "flying around", unbound to types. Have reference-counted
objects at least. Allow a way of passing a sub-array without copying/with read
only permissions.

\- Remove "gotchas", like ordering of statements, assignment on comparison
(unless it's obviously correct), no "compiler dependent" behaviour, no
"undefined behaviour" (unless it's machine specific)

~~~
sleepydog
You are confusing unsafe behavior with undefined behavior. He is not
suggesting that a C compiler should prevent the above mistakes. He's
suggesting that it should document what code the compiler will emit in such
cases. For example,

\- reading past the end of an array will always segfault the program
immediately. or reading past the end of an array will return (arrayType)0

\- signed integer types must overflow according to two's complement. A
compiler may not assume that, for instance, (int)x < (int)x + 1 is always
true.

\- uninitialized variables are zeroed out. That is, `int *x;` always produces
a null pointer, `char y` always produces '0'

\- A compiler may not remove any statements where it determines such an
optimization would not change the behavior of the program. See
[http://www.daemonology.net/blog/2014-09-04-how-to-zero-a-
buf...](http://www.daemonology.net/blog/2014-09-04-how-to-zero-a-buffer.html)

Such a compiler would accept and compile any C program, and the programmer
(and any static analysis tools) would have a better idea of the behavior of
the output program.

~~~
timmytokyo
> reading past the end of an array will always segfault the program
> immediately. or reading past the end of an array will return (arrayType)0

How would this work when you pass the array (i.e., the pointer) to a function?
In order to do what you describe, every pointer would need to include bounds
information. This would break the C ABI, so your code would no longer link
with existing C libraries.

~~~
sanxiyn
OP answered this on the thread. Pointer bounds are stored in a lookup table.
Pointers are passed to functions according to C ABI, and bounds are retrieved
by querying the lookup table by the pointer.

------
kazinator
Some small steps could have been made _years_ ago.

For instance, getting rid of unspecified order of evaluation. Or defining a
dialect of ISO C in which evaluation is strictly left to right, and making
support for that optional (so then your local GCC or whatever can have
-fstrict-iso-eval to turn it on).

Another example of "small stuff": catching negative values being passed into
the <ctype.h> functions. Also, all the instances in the standard library where
a null pointer invokes undefined behavior could be required to abort the
program.

Some undefined behaviors cannot be made defined without a lot of overhead
(like catching all out of bounds pointers).

However, there is a lot of "low hanging fruit" undefined behavior where things
can be improved.

------
makecheck
One of the bases for security is the age of a program. All other things being
equal, the implementation that has been around the longest is expected to have
fewer issues than the shiny, new thing (because the old program is well-
understood, has been patched to death, considers a thousand corner cases, ran
on more hardware, more time passed without any issues, etc.).

As such, changing away from well-known compilers and language behaviors may
not be the wisest thing for security.

On the other hand, extending existing compilers to restrict behavior seems
reasonable. Also, by all means document the hell out of the things that are
not well-defined.

------
e28eta
My understanding was that with optimizations off, clang/gcc were pretty
"boring". Is a whole new compiler really required?

Personally, to fix these problems I'd lean toward finding a new language
instead of a new compiler.

~~~
sanxiyn
For example, OP suggests zeroing uninitialized variables. Neither clang nor
gcc with optimizations off do that.

------
ape4
In the past initializing variables to zero might have been too slow. But not
now.

------
sbierwagen
CompCert?

~~~
rfw
I believe Compcert still translates programs with undefined behavior and
doesn't really do anything about it; or rather, the behavior is defined but
based on whatever the Compcert authors define the behavior to be.

------
chris_wot
Is there any list of undefined behaviours in C? Other than the standard.

------
cbd1984
He says this:

> Claim that a boring C compiler can't possibly support the desired system
> _performance_. Even if this were true (which I very much doubt), why would
> it be more important than system _correctness_?

If correctness is more important than performance, C is the wrong language.
Consider a language with, at the very least, garbage-collection built into the
core, as memory allocation and usage errors are the base of a lot of what goes
badly wrong with C programs.

In short, his notion of "Boring C" seems to be Haskell or Common Lisp.

~~~
nickpsecurity
Those languages are incredibly complicated. I'd go with Modula-2 or Pascal as
a boring C candidate.

~~~
cbd1984
I'm not sure that either of those languages are usually GC'd, but they'd be
good choices, too, if they were.

(I just don't like Wirth languages. I don't like their type systems and I
don't like the definition-before-use requirement. They're better than C, in
some respects, but worse in others, and the net isn't always an improvement.)

~~~
nickpsecurity
All of Wirth's after Modula-2 were GC'd. C programmers would reject a GC'd
language, though. So, I stayed with originals that enhanced safety,
predictability, readability, and so on while capable of low-level, fast stuff.
Wirth's stuff and industrial variants of it often let you do unsafe stuff in
dedicated modules for that so you could turn off GC or checks.

Plus they wrote OS's in Modula-2 and Pascal on ancient hardware. Whole
platforms. So, they're proven for the use case C programmers often say you
need their language for.

~~~
paliderek
For anyone interested in Modula-2 as a potential replacement for C as a
systems language, there is a small but hopefully growing revival of the
language occurring on the Gnu Modula-2 mailing list and (especially) on
comp.lang.modula2 . Right now there is a call on the newsgroup for testers of
the Modula-2 to C (M2C) compiler. This is part of a larger effort for the
Modula-2 Revision 2010 (M2 R10) language definition and implementation by
Benjamin Kowarsch and Rick Sutcliffe.

~~~
nickpsecurity
Appreciate the tip: that's exciting. Also an ideal time to extend it with
improvements learned from experience since Modula-2 and avoid problems learned
similarly. I actually downloaded the old Modula2-to-C compiler, Lilith
technical paper, and A2 Oberon sources in case any of that ended up being
useful. Maybe it will. :)

------
throwaway999888
Clearly what you want is something _other than C_.

~~~
tormeh
Ada, and recently Rust, for example. People trying to improve C are sad to
watch. People use C because they have an irrational belief in their own
faultlessness. Same reason people are afraid of flying but not driving.
Selling a correctness-enhancing tool to these people is an impossible task.

~~~
nraynaud
I recently tried to use Ada, that ended in sadness. I couldn't try Rust,
because it doesn't (didn't?) run on arm-none-eabi.

~~~
steveklabnik
Rust should work on `arm-none-eabi` to my knowledge. We don't provide packages
out of the box, but people have done it. You need to set up the right target
specification, and then it should work.

~~~
nraynaud
Possible, I don't remember the details. It might also be that setting up a
cross compiling toolchain by hand was not exactly how I intended my first
contact with a new language be (I had set up a cross compiling GCC, then a
cross compiling Ada that ended up in a linux simulator, I might have lazied on
the rust test).

~~~
steveklabnik
Yeah, it's not ideal. We are actively working on making it easier to do these
kinds of things; it's not well documented, to be honest.

------
rwmj

        gcc -O0

Would that do?

~~~
sanxiyn
gcc -O0 does not zero uninitialized variables, which is among things
explicitly suggested by OP.

------
cornholio
Event the greatest brains can fart, this proposal can be safely ignored.

------
imron
Surely this is where things like __attribute__ ((optnone)) and #pragma
optimize("", off) come in useful.

------
theseoafs
The compiler for this language will be too slow to be useful. Contrary to this
author's belief, crypto people really do care about performance.

Anyway, what the author wants isn't a "boring C" compiler, it's a compiler for
a new language that doesn't actually have undefined behavior.

~~~
guelo
From the article:

> * Claim that a boring C compiler can't possibly support the desired system
> _performance_. Even if this were true (which I very much doubt), why would
> it be more important than system _correctness_?

~~~
0xcde4c3db
It can't be taken for granted that performance and correctness are separate
concerns. Even leaving aside the obvious category of realtime applications,
performance issues can create DoS vulnerabilities.

edit: That being said, a boringcc might end up being _less_ susceptible to
these vulnerabilities in practice, since the performance of the emitted code
might be more predictable. I'm sure djb has considered this. But in general I
think it's often a mistake to think of performance as an implementation detail
rather than as a deliberate feature.

------
AndyMcConachie
Programmers always want new and more clever constructs in their code, and
there is always the next feature that will optimize inner loops 10% better.
This is human nature apparently, so don't put too much faith in a boring
anything gaining traction.

And for those of you courting Rust, remember there are two kinds of
programming languages in the world: those that no one uses, and those that are
known to be terrible.

