TrapC: A C Extension For The Memory Safety Boogeyman

In the world of programming languages it often feels like being stuck in a Groundhog Day-esque loop through purgatory, as effectively the same problems are being solved over and over, with previous solutions forgotten and there’s always that one jubilant inventor stumbling out of a darkened basement with the One True Solution™ to everything that plagues this world beset by the Unspeakable Horror that is the C programming language.

As the latest entry to pledge its fealty at the altar of the Church of the Holy Memory Safety, TrapC promises to fix C, while also lambasting Rust for allowing that terrible unsafe keyword. Of course, since this is yet another loop through purgatory, the entire idea that the problem is C and some perceived issue with this nebulous ‘memory safety’ is still a red herring, as pointed out previously.

In other words, it’s time for a fun trip back to the 1970s when many of the same arguments were being rehashed already, before the early 1980s saw the Steelman language requirements condensed by renowned experts into the Ada programming language. As it turns out, memory safety is a miniscule part of a well-written program.

It’s A Trap

Pretty much the entire raison d’être for new programming languages like TrapC, Rust, Zig, and kin is this fixation on ‘memory safety’, with the idea being that the problem with C is that it doesn’t check memory boundaries and allows usage of memory addresses in ways that can lead to Bad Things. Which is not to say that such events aren’t bad, but because they are so obvious, they are also very easy to detect both using static and dynamic analysis tools.

As a ‘proposed C-language extension’, TrapC would add:

  • memory-safe pointers.
  • constructors & destructors.
  • the trap and alias keywords.
  • Run-Time Type Information.

It would also remove:

  • the goto and union keywords.

The author, Robin Rowe, freely admits to this extension being ‘C++ like’, which takes us right back to 1979 when a then young Danish computer scientist (Bjarne Stroustrup) created a C-language extension cheekily called ‘C++’ to denote it as enhanced C. C++ adds many Simula features, a language which is considered the first Object-Oriented (OO) programming language and is an indirect descendant of ALGOL. These OO features include constructors and destructors. Together with (optional) smart pointers and the bounds-checked strings and containers from the Standard Template Library (STL) C++ is thus memory safe.

So what is the point of removing keywords like goto and union? The former is pretty much the most controversial keyword in the history of programming languages, even though it derives essentially directly from jumps in assembly language. In the Ada programming language you also have the goto keyword, with it often used to provide more flexibility where restrictive language choices would lead to e.g. convoluted loop constructs to the point where some C-isms do not exist in Ada, like the continue keyword.

The union keyword is similarly removed in TrapC, with the justification that both keywords are ‘unsafe’ and ‘widely deprecated’. Which makes one wonder how much real-life C & C++ code has been analyzed to come to this conclusion. In particular in the field of embedded- and driver programming with low-level memory (and register) access the use of union is widely used for the flexibility it offers.

Of course, if you’re doing low-level memory access you’re also free to use whatever pointer offset and type casting you require, together with very unsafe, but efficient, memcpy() and similar operations. There is a reason why C++ doesn’t forbid low-level access without guardrails, as sometimes it’s necessary and you’re expected to know what you’re doing. This freedom in choosing between strict memory safety and the untamed wilds of C is a deliberate design choice in C++. In embedded programming you tend to compile C++ with both RTTI & exceptions disabled as well due to the overhead from them.

Don’t Call It C++

Effectively, TrapC adds RTTI, exceptions (or ‘traps’), OO classes, safe pointers, and similar C++ features to C, which raises the question of why it’s any different, especially since the whitepaper describes TrapC and C++ code usually looking the same as a feature. Here the language seems to regard itself as being a ‘better C++’, mostly in terms of exception handling and templates, using ‘traps’ and ‘castplates’. Curiously there’s not much focus on “resource allocation is initialization” (RAII) that is such a cornerstone of C++.

Meanwhile castplates are advertised as a way to make C containers ‘typesafe’, but unlike C++ templates they are created implicitly using RTTI and one might argue somewhat opaque (C++ template-like) syntax. There are few people who would argue that C++ template code is easy to read. Of note here is that in embedded programming you tend to compile C++ with both RTTI & exceptions disabled due to the overhead from them. The extensive reliance on RTTI in TrapC would seem to preclude such an option.

Circling back on the other added keyword, alias, this is TrapC’s way to providing function overloading, and it works like a C preprocessor #define:

void puts(void* x) alias printf("{}n",x);

Then there is the new trap keyword that’s apparently important enough to be captured in the extension’s name. These are offered as an alternative to C++ exceptions, but the description is rather confusing, other than that it’s supposedly less complicated and does not support cascading exceptions up the stack. Here I do not personally see much value either way, as like so many C++ developers I loathe C++ exceptions with the fire of a thousand Suns and do my utmost to avoid them.

My favorite approach here is found in Ada, which not only cleanly separates functions and procedures, but also requires, during compile time, that any return value from a function is handled, and implements exceptions in a way that is both light-weight and very informative, as I found for example while extensively using the Ada array type in the context of a lock-free ring buffer. During testing there were zero crashes, just the program bailing out with an exception due to a faulty offset into the array and listing the exact location and cause, as in Ada everything is bound-checked by default.

Memory Safety

Much of the safety in TrapC would come from managed pointers, with its author describing TrapC’s memory management as ‘automatic’ in a recent presentation at an ISO C meeting. Pointers are lifetime-managed, but as the whitepaper states, the exact method used is ‘implementation defined’, instead of reference counting as in the C++ specification.

Yet none of this matters in the context of actual security issues. As I noted in 2024, the ‘red herring’ part refers to the real-life security issues that are captured in CVEs and their exploitation. Virtually all of the worst CVEs involve a lack of input validation, which allows users to access data in ‘restricted’ folders and gain access to databases and other resources. None of which involve memory safety in any way or form, and thus the onus lies on preventing logic errors, solid input validation and preventing lazy or inattentive programmers from introducing the next world-famous CVE.

As a long-time C & C++ programmer, I have come to ‘love’ the warts in these languages as well as the lack of guardrails for the freedom they provide. Meanwhile I have learned to write test cases and harnesses to strap my code into for QA sessions, because the best way to validate code is by stressing it. Along the way I have found myself incredibly fond of Ada, as its focus on preventing ambiguity and logic errors is self-evident and regularly keeps me from making inattentive mistakes. Mistakes that in C++ would show up in the next test and/or Valgrind cycle followed by a facepalm moment and recompile, yet somehow programming in Ada doesn’t feel more restrictive than writing in C++.

Thus I’ll keep postulating that the issues with C were already solved in 1983 with the introduction of Ada, and accepting this fact is the only way out of this endless Groundhog Day purgatory.

24 thoughts on “TrapC: A C Extension For The Memory Safety Boogeyman

  1. because they [unsafe memory accesses] are so obvious, they are also very easy to detect both using static and dynamic analysis tools

    Um… what? No. Not really. Some cases are easy to detect with some analysis tools. This becomes painfully obvious on any non-trivial C(++) project.

    Chromium’s “memory safety” webpage claims:

    70% of our serious security bugs are memory safety problems

    Maybe someone should tell them that these are so obvious to detect…

    1. JuSt ReWrItE iT In RuSt, iT’s MeMoRy SaFe Br0 🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡🤡

  2. I certainly don’t see why they don’t leave the language alone. Goto and Union have been useful over the years in some specific scenarios (why the commands are there). Just leave it alone for backward compatibility. Of course, adding functionality is fine.

  3. Ah yes, another of the “I like stone axes, so instead of using bronze axes all we need to do teach other users to use stone axes more safely” contentions. Expect more to surface over the next few years.

    Good luck analysing typical large C/C++ programs containing multiple arbitrary libraries to determine the absence of pointer aliasing. I invite those who believe it practical to hold their breath while it is being done.

  4. Unions are really useful in embedded systems when you want to overlap different structures on say a a protocol stream.

    Goto correctly used allows you to concentrate the exit code where you want to release resources in a consistent manner. The alternative is deeply nested code with multiple exit points and deeply illegible code (Don’t get me started on single return MISRA rules either)

    All languages syntax can be misused. But just because someone has used Goto to write spaghetti in the past, does not mean that it is bad for everyone, or they don’t have a use

    If you are going to fix C, look at all the variations generated by various compiler pragmas and standardize them, such as structure packing

  5. Neither Rust or C can be totally secure. Anyone who can crash or stop a program while its running can steal information or cause damage. No amount of development can mitigate glitches, hardware crashes, cosmic ray cpu issues, etc. Fringe cases, but lambasting C over memory safety misses the point. Does the US gov really want me to not learn C by writing a hello world? Is that possibly dangerous? I promise I wont write drivers or OS components.

  6. Sometimes I wonder if any of these “C is fine” folks actually work with other software engineers?

    I mean like REAL software engineers, dealing with the dirty, ugly reality of software; Not academics arguing about perfect world scenarios on Reddit.

    Have they met the idiots with CS degrees coming out of Uni these days? It’s fine that an expert programmer can use C/C++ without creating exploitable bugs using tooling and other clever tricks, but being real, most programmers cannot be bothered to put in that kind of effort. So much code is written by half-assed and/or overworked coders. The agile methodology that everyone is so on about rewards function and delivery over quality of form. No one cares if there’s a hidden memory safety violation. No one is looking for it. Bake it into the damn languages already.

    That’s my take at least. All this academic BS on the topic fails to address human laziness, ineptitude and the unending pressure from above to “just make it work” from stakeholders.

    1. You forgot to mention those AI-copy-paste-coding solutions. “Just use some code that a hallucinating AI found for you without understanding what it does.”

      As usual: to make it good it needs time, experience, reviews, reviews, tests, time and repeats.

      1. Speaking of that … Today it is nice to ‘search’ for some howto use a function or some such as it is usually on-line. Before if it wasn’t in a book, we had to figure it out ourselves. Now the up-to-date information is at our finger tips. In that sense, we live in a better world for speeding up programming. I don’t mind finding code snippets/tutorial that someone has written (don’t/won’t use AI) to help a project. You know what you want, and seeing the code (or write-up) you can tell if it will do what you are looking for or not. Yes understanding is key. No free lunch here (in my pea brain anyway).

    2. I did. C was fine. The cat’s meow so to speak. We had a fine team back in the 80s, 90s, 2000s. We programmed our SCADA control systems (masters and RTUs) in C, Assembly (real-time kernel applications) and on the desktop side (database, UI stuff) it was C and Pascal (Delphi later). I headed up a group of 8 people. Got along good. They were CS professionals with good backgrounds in physics/math/electrical and of course data structures and knew C. Yes we did mentor the newbies of course. But the hiring process weeded out a lot of would be programmers (as did just looking at school transcripts before getting them in for interviews. By that time we were doing code reviews, and the full documentation on new features (specification, design, and testing) before coding began (for the most part as we were flexible depending) which slowed things down, but was necessary. All had to be signed off my me and management directly above me before project was complete. Also all programmers were ‘in the office’ working as a team… None of this work from home garbage of today.

    3. “Have they met the idiots with CS degrees coming out of Uni these days?”

      Yeah, and the one thing I can say with confidence is there ain’t no magic programming language making their stuff safe, anyway.

  7. This will be DoA bc of the union removal. That’s a key feature for C. It’s not “widely deprecated,” it’s used ALL OVER C projects, from utilities to OSs to embedded.

    It has so many use cases from APIs to performance improvements , e.g. casting a struct that fits into 64-bits to an integer to perform certain operations quickly on it.

    It won’t take off for that reason alone. Article puts it clearly:

    Which makes one wonder how much real-life C & C++ code has been analyzed… [since for] embedded- and driver programming… the use of union is widely used for the flexibility it offers.

    This could’ve been neat, but they made one extremely stupid decision.

  8. It’s not just memory safety. It’s a very C-brained way to look at things if you only consider “am I accessing outside this array?” Rust is no magic bullet, but they at least learned that lifetimes are more important. There is a temporal element here, where accesses to bits of memory are valid or invalid at different times.

    Not just whether something has been created/freed yet either. The reason rust tackles thread safety as well is threads can own bits of memory at different times and that ownership can change. Having two (or more) threads share memory read-only is fine but if one of them switches to writing that’s a problem, and the rules change on the fly as threads enter or exit different parts of a program. Rust works hard to formally prove that there is no window of time when invalid accesses are possible.

Leave a Reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.