3 Answers
3

The first C++ compiler (Cfront) was written in C++. To build that, I
first used C to write a "C with Classes"-to-C preprocessor. "C with
Classes" was a C dialect that became the immediate ancestor to C++.
That preprocessor translated "C with Classes" constructs (such as
classes and constructors) into C. It was a traditional preprocessor
that didn't understand all of the language, left most of the type
checking for the C compiler to do, and translated individual
constructs without complete knowledge. I then wrote the first version
of Cfront in "C with Classes".

So the first version of Cfront wasn't written in C++, rather in the intermediate language. The ability to create C compilers and preprocessors directly in C led to many of the innovations (and massive security holes) in C. So you write your new preprosessor that turns your "C with Classes" code into straight C (because straight C can do anything) and then you use "C with Classes" to write a C++ compiler (not that you couldn't do it in C, just it would take awhile) and then you use that C++ compiler to write a more effecient/complete compiler in C++. Got it?

+1 for including a link to one of my favorite tales of things that can be done (and shouldn't).
–
jwernernySep 1 '11 at 16:58

1

The compiler was written in valid C++ code, but only used a few of the full C++ features, those which were supported by the "C with Classes" preprocessor. It used a subset of the full language, so it also compiled on the result (the first working version of Cfront). After performing this "bootstrap" step, he probably never needed to use the preprocessor again.
–
joeytwiddleJan 2 '13 at 2:30

2

@jwernerny - I've always found that article unsatisfying. He glosses over the most difficult and non-trivial part: "The bug would match code in the UNIX 'login' command. The replacement code would miscompile the login command so that it would accept either the intended encrypted password or a particular known password." But how would this be done? Has it ever actually been demonstrated?
–
detlyFeb 12 '13 at 5:07

2

"led to many of the innovations (and massive security holes) in C": As far as I know these tricks can be used in any language, not just in C. So any other language can have the same security holes.
–
GiorgioFeb 12 '13 at 8:13

2

@detly: It sounds trivial now, but in 1983 this was a novel attack made viable by a lack of implementation diversity. We were more trusting of binaries back then, partially because compiling everything from source was a much bigger ordeal than it is now.
–
BlrflFeb 13 '13 at 22:45

It was bootstrapped. As soon as a C++ feature was added to cfront, then cfront could also use that feature from that point on (but not to implement that very feature). This worked because cfront had the ability to convert C++ code to C code. So if some new platform came out, you could use cfront on another platform to convert cfront from C++ to C, and then use the new platform's C compiler to finish the compilation from C to object code.

The first C++ compiler (Cfront) was written in C++. To build that, I
first used C to write a "C with Classes"-to-C preprocessor. "C with
Classes" was a C dialect that became the immediate ancestor to C++.
That preprocessor translated "C with Classes" constructs (such as
classes and constructors) into C. It was a traditional preprocessor
that didn't understand all of the language, left most of the type
checking for the C compiler to do, and translated individual
constructs without complete knowledge.

I then wrote the first version
of Cfront in "C with Classes". Cfront was a traditional compiler that
did complete syntax and semantic checking of the C++ source. For that,
it had a complete parser, built symbol tables, and built a complete
internal tree representation of each class, function, etc. It also did
some source level optimization on its internal tree representation of
C++ constructs before outputting C. The version that generated C, did
not rely on C for any type checking. It simply used C as an assembler.
The resulting code was uncompromisingly fast.

First he created something he called "C with Classes" implemented by a simple preprocessor into C. It was basically C++, but the preprocessor did little or no checking. He then used that to write Cfront, the more powerful version of the translator of C++ into C, complete with type checking, symbol tables, etc.

so basically when we compile a C++ program, it gets converted into C, then after it's converted into C, it gets compiled again to machine code?
–
PacerierSep 2 '11 at 7:06

@Pacerier: Originally, yes, but not now I think.
–
Mike DunlaveySep 2 '11 at 13:24

i don't quite understand your comment. do you mean now there are compilers that skip the second step and simply take the C++ source and compile to machine code?
–
PacerierSep 3 '11 at 4:00

5

@Pacerier: Well, they don't go directly to assembly language or machine code. Usually they first go to a machine-independent intermediate representation (triples or quads) and analyze that for optimization. From that they generate assembly or machine code. If you pick up a book on compiler design (Aho & Ullman) I'm sure you'll find it interesting.
–
Mike DunlaveySep 3 '11 at 14:06

1

It is important to note that the C++ he was building was also a fraction of the language that now exists. It had no templates, no new libraries, used C casting only and if I recall correctly, had no exceptions.
–
Steven BurnapAug 21 '13 at 20:17