back to article To kill memory safety bugs in C code, try the TrapC fork

C and C++ programmers may not need to learn Rust after all to participate in the push for memory safety. Speaking remotely at the W2140 conference in Bangkok, Thailand, on Tuesday, Robin Rowe, a former computer science professor, product designer, and graphics expert, plans to announce a fork of the memory safe fork of C …

  1. Chris Gray 1
    Meh

    Wait and see

    Poor formatting inside that box - can El Reg make the box wider to get rid of the line wrapping?

    All 3 examples are pointer incrementing. In all 3 the compiler can know what chunk of memory the pointer is pointing at. And it still has to add run-time checks on the incrementing. What happens if you pass a pointer to a function and increment it inside the function? How does the runtime know when the increment is bad? The typical solution there is to add more information to pointers, so that their upper and lower bounds are known. Lots of extra cost there.

    If you want to use a pointer to scan along a known-size chunk of memory, then require the use of a "for" loop where the iterator variable cannot be changed by user code. Then you can avoid all runtime cost in that fairly common case.

    I'll wait to see what comes out, but so far I don't see much of interest.

    1. Jason Bloomberg Silver badge

      Re: Wait and see

      I presume the answer to adjusting a passed pointer within a function is to ensure what's passed in always points to something with the same bounds, or transparently passes in what those bounds should be.

      If it can be determined at compile time there's likely little overhead and, if it can't, it adds cost, then don't do it that way, accept there will be overhead, or just stick to using C. Ideally Trap-C for the most part, linked to C code when you really do want to play with dragons.

      Trap-C looks like a good idea to me and seems like the advantages outweigh any downsides.

    2. O'Reg Inalsin

      Re: Wait and see

      The article is fairly clean that run-time checking is NOT part of the scheme. The scheme is

      "And I was like, 'Well, since the compiler knows where the end is, what if when it goes off the end, the pointer just went to zero?' And that's much easier to deal with than a wild pointer because you can easily check if the pointer is zero. And so that's the essence of what we're working on with TrapC ..."

      How can the compiler know? I can only guess that means every "new" is passed an explicit constant length, and there is no conditional logic in the incrementing loop except for a early exit. Outside of the loop the memory can no longer be incremented. Changing the constant requires re-compiling.

      The compiler must not allow pointers to passed to subroutines - unless there is something like "this is an array of 10K" that can be passed as an argument - no passing naked mystery pointers.

      It is stated that this is only for safety critical coding, so the lack of freedom (and the compile errors that entails) are acceptable.

      1. Dan 55 Silver badge

        Re: Wait and see

        I can only guess that means every "new" is passed an explicit constant length

        Both malloc and new know the size of the memory/object they're creating to be able to allocate it in the memory pool.

  2. Dostoevsky Bronze badge

    It's a TRAAAAAP!

    This quote...

    > And this is a big difference from Rust where you have the unsafe keyword saying, 'Well, you know, I give up, I'm not going to be safe here.'

    ...shows exactly how poorly this guy understands Rust.

    1. Matt Collins

      Re: It's a TRAAAAAP!

      And he's a professor of computer science... says something about Rust then, doesn't it?

      1. O'Reg Inalsin

        Re: It's a TRAAAAAP!

        Absolutely. Nowadays all computer science professors are one with the great Dharpa Wheel. "What the Dharpa Wheel Represents · The circle, the round shape of the wheel, represents the perfection of the dharpa, the Buddha's teaching." Not like the old heathen ways, where they used to have to scramble for funding.

      2. gweedo
        Thumb Down

        Re: It's a TRAAAAAP!

        Rust is quite clear on what expectations are for code marked as 'unsafe'. From the Rust language reference: "the intent is that as the programmer, you’ll ensure the code inside an unsafe block will access memory in a valid way." https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html

        Says more about this profs reading comprehension.

        1. Matt Collins

          Re: It's a TRAAAAAP!

          Just like C then.. the intent is that as the programmer you'll access memory in a valid way.

          1. Nabushika

            Re: It's a TRAAAAAP!

            Hey, you're not wrong. C is similar to having an unsafe block around the whole program... Let me know when you find a team that's capable of writing a large project without any memory bugs, apparently even Google struggles so you could probably make a killing contracting them out!

            1. Matt Collins

              Re: It's a TRAAAAAP!

              My post was pointing out the irony, not the bugs

      3. Nabushika

        Re: It's a TRAAAAAP!

        Yeah, because we all know that C programmers always care to learn about the details of other languages before jumping to conclusions, right?

        Don't just appeal to authority. He's wrong, and it's something that's easy to check. That's not a good look when he's saying "it's going to make Rust obsolete!!1!". I don't generally put down languages but I sure as heck wouldn't disparage one I didn't even know, it's ignorant and aggravating. New paradigms aren't built by ignoring the old ones, even if they're bad!

        1. Matt Collins

          Re: It's a TRAAAAAP!

          "but I sure as heck wouldn't disparage one I didn't even know, it's ignorant and aggravating"

          Bully for you. I learned Rust to investigate the feasibility of porting a very large high-performance server written in pure C to it, like I did with Java and C# back when they were starting to look promising. The interesting thing here is that we aren't interested in memory safety, we've had literally a handful of issues in the past 10/15 years, maybe longer, on that front. That's entirely down to having a very small team of developers with very long experience, not a language that constrains.

  3. This post has been deleted by its author

  4. SammyB

    Variable Names : Case Sensitivity

    One thing that I think would greatly help in making any language memory safe is to make variable names case insensitive. That is always a potential bug in any language where variable names are case sensitive.

    1. Alan Mackenzie

      Re: Variable Names : Case Sensitivity

      Having lots and lots of ways to spell a single variable is worse.

      1. theblackhand

        Re: Variable Names : Case Sensitivity

        Avoid spelling mistakes by using single letter variable names.

        26 variables is more than I could ever conceivably need.

        1. David 132 Silver badge

          Re: Variable Names : Case Sensitivity

          26? You only need 1.

          Obligatory XKCD :)

          1. The Man Who Fell To Earth Silver badge
            Alien

            Re: Variable Names : Case Sensitivity

            That guy in the KXCD cartoon must be Elon Musk.

        2. ForthIsNotDead
          Thumb Up

          Re: Variable Names : Case Sensitivity

          Variables shmariables. Just use a stack, then you don't need any variables at all - they're on the stack, baby!

          Okay, you might need to do a bit of stack juggling to access the variables you're looking for - but that's easy.... TWO STACKS!

          Just pop from one, and push to the other until you get to the variable that you need.

          You're all very welcome :-)

          1. CowHorseFrog Silver badge

            Re: Variable Names : Case Sensitivity

            x87 all the way!

          2. Dostoevsky Bronze badge

            Re: Variable Names : Case Sensitivity

            Yay PostScript!

  5. Matt Collins

    I, for one...

    ...welcome anything that means I don't have to re-learn and re-write everything. I tried Rust, it was distractingly awkward. I'll be trying TrapC, it looks like it needn't be.

  6. Doctor Syntax Silver badge

    How many memory-safe versions of C are we going to have? All different, all nearly compatible...

    1. MiguelC Silver badge
      Joke

      That's right, we have too many versions. Therefore, I'll create the unifying version of them all, the only C you'll ever need and I'll call MiguelC

    2. Someone Else Silver badge
    3. Roland6 Silver badge

      Interesting and relevant article here:

      https://devclass.com/2024/11/12/iso-c-chair-herb-sutter-leaves-microsoft-declares-forthcoming-c-26-most-impactful-release-since-c11/

      Whilst it is about C++, I wonder whether TrapC is an equivalent for C and thus a candidate for the next edition of ISO C.

  7. Howard Sway Silver badge

    I've taken out union and some other things that I rarely use

    And that's going to be your problem : nobody's going to move all their code to your new thing if they have to rewrite it all. Oh, they might zoom along happily enough for a while, but then the 400000 line project lands on their desk written by that one guy who used union everywhere because he thought it was neat.

    And what's with the no delete idea? This isn't just for end of program cleanup. Sometimes you really need to zap big chunks of memory immediately in the middle of normal operations, simply because it's no longer needed and you need to reallocate another big chunk for something new. This choice definitely needs much more examination before I'd try it.

    No, what sounded like good thinking at the beginning of reading this didn't sound so good by the end.

    1. Anonymous Coward
      Anonymous Coward

      Re: I've taken out union and some other things that I rarely use

      [I have NO skin in this game, just trying to be fair to all]

      I see your point(er) [Pun not intended :) ] but I would say try it and see if it is as bad as you think.

      It is a generally good idea that is an alternative to re-written libc that is mem-safe or similar addons to libc.

      There is NOT going to be a mem-safe C this side of the heat-death of the universe, so these types of ideas are going to appear.

      If they are dismissed out of hand what is the solution ???

      Yes, there will be huge amounts of code that will NOT simply compile & go BUT what is a reasonable solution that does not require a TOTAL rewrite ???

      RUST is not gaining popularity with the C & C++ devs because it requires some effort to learn and even bigger effort to then translate C code to RUST.

      Automagic C to RUST is very very difficult !!!

      If ALL these attempts are considered BAD please suggest something positive rather than just shooting down ALL ideas with NO/Negative feedback.

      :)

      1. Anonymous Coward
        Anonymous Coward

        Re: I've taken out union and some other things that I rarely use

        "If they are dismissed out of hand what is the solution ???"

        Maybe folks who write important (crucial) programs need to be properly competent (and paid accordingly) ... For example, such folks should understand the difference between (3rd example in TFA):

        #include "stdio.h"

        #include "limits.h"

        void main() { for(int i = INT_MAX-10;i <= INT_MAX;i++) printf("%i\n",i); } // infinite loop?

        and:

        #include "stdio.h"

        #include "limits.h"

        void main() { for(unsigned int i = INT_MAX-10;i <= INT_MAX;i++) printf("%i\n",i); } // honky dory

        No?

        1. Anonymous Coward
          Anonymous Coward

          Re: I've taken out union and some other things that I rarely use

          Or, frankly:

          void main() { for(int i = INT_MAX-10;i < INT_MAX;i++) printf("%i\n",i); } // victory!

          (add separate line to print INT_MAX if desired ...)

          1. Ian Bush

            Re: I've taken out union and some other things that I rarely use

            void main() { ....

            Sigh. I wonder if comp.lang.c still lives

            1. ForthIsNotDead
              Coat

              Re: I've taken out union and some other things that I rarely use

              :-(

              I use union quite a lot. In my code, I have a bunch of persistent data stored in I2C based FRAM. I define the 8K FRAM as a simple uint_8 array, and union the variable names that represent those bytes over the top of it. Use it all the time. Works a treat.

              union

              {

              uint8_t fram[8192];

              struct {

              uint16_t variable1;

              uint16_t variable2;

              etc...

              } variables;

              } framMemory;

              It's also useful when decoding serial data over a serial or network link. Depending on the protocol, the serial data can be placed into an array that has the various fields of the packet extracted into variables superimposed over the array using a union.

              Not to mention serialising, de-serialising etc...

              So yeah, I'll be writing to him and fighting for Union's right to exist.

              Perhaps I should... start a union?

              Okay, I'll get my coat (icon)...

              1. ChrisC Silver badge

                Re: I've taken out union and some other things that I rarely use

                Yup, use it in the same way here for array <-> structure mapping, and it works beautifully.

                That said, IF the edict came down from on high that all our products had to start being written in safe languages, then compromises like this which are easy enough to handle whilst still allowing the project to remain firmly wedded to the world of embedded C, would be infinitely preferable to having to teach myself a whole new language (and the paradigms that go with it) like Rust, and THEN have to port the project over to it, redo all the validation testing, certification testing...

                Though given the rate of change here and the fact that I don't work in a sector which mandates any particular level of reliability for embedded code, I suspect I'll be safely retired before embedded C becomes verboten for all but legacy maintenance work.

      2. Proton_badger

        Re: I've taken out union and some other things that I rarely use

        > RUST is not gaining popularity with the C & C++ devs because it requires some effort to learn and even bigger effort to then translate C code to RUST.

        I don't know, most Rust devs I know have decades of C and/or C++ under their belt. It's a minority that are loudly sceptical, most enjoy the vastly reduced attack surface of memory issues But this is anecdotal, I'm not sure any real stats on this exists. Ofcourse from a businesses perspective, if a large code base is based on C or C++ they will be reluctant to change due to the cost. Though some places I know keep their C code, maybe rewrite indentified risky core libraries (e.g. Microsoft and Google take this approach), and write select new code in Rust because Rust’s FFI is based on the C Application Binary Interface so it's trivial to mix.

        I've got some 25 years and I'm fed up with hunting these bugs as well as the increasingly messy look of C++, I enjoy Rust.

    2. Alan Mackenzie

      Re: I've taken out union and some other things that I rarely use

      I think union is little used, and will continue to be little used. MISRA frowns on it, for one.

      In that (rare) 400,000 line project with lots of unions, you'll just have to go through it getting rid of them, one by one. Or stick with C. So what? The developer of this language has experience in embedded systems, where there are indeed some legitimate uses of union. There will surely be some adequate replacement for it.

      As for that big chunk of memory you need to zap, if you declare it in a function (I'm guessing here), it will be freed as part of leaving that function. What's the big deal?

      It sounds good to me. I think we should wait for the language to become available before anybody condemns it.

    3. O'Reg Inalsin

      Re: I've taken out union and some other things that I rarely use

      I am guess it means that memory is auto deleted at end of scope. The talk about C++ destructors implies that may be the case. C++ destructors free memory when the constructed object goes out of scope, and that's a compile time calculation. I used to program in C++ and that was exactly how I avoided memory leaks. However, it also presumes the memory will never be passed out of the scope within which it is created. But passing memory out of its birth scope is exactly the kind of behavior that is safely allowed enabling far more freedom and faster coding in GC languages.

      The author did caveat that TrapC is only for meant for safety critical systems. That's just the kind of sedate code where auto-deleting at scope end is suitable. I guess TrapC borrows that one feature from C++ without the other baggage.

      Does the compiler disallow making copies of pointer? I guess it must, but that should be stated.

    4. Someone Else Silver badge

      Re: I've taken out union and some other things that I rarely use

      I've taken out union and some other things that I rarely use

      Spoken like a true nsBDFL.

      (ns == "not so")

      1. Bebu sa Ware
        Windows

        Re: I've taken out union and some other things that I rarely use

        Spoken like a true nsBDFL.

        Had to look that up.

        Most languages, at least among the algol descendants, have some sort of variant record type which C's union is the minimal version (no required tag.)

        Anonymous unions are scattered amongst the socket header files to represent the variety of socket types but arguably this is to implement the socket ABI with some type safety but without function overloading.

        Variant records are the data counterpart of the code case (switch) statement in the same way arrays (vectors) are to for statements. (Enumerated types and subrange types for the tags and array indices also feature.) Completely safe if the record's tag is used in the case selection and the correpondence between the tag and the variant is enforced by the compiler.

        Another "safe C" compiler that surfaced yonks ago, Cyclone had similar aims but never seem to go anywhere.

        I am curious to learn how TrapC handles error conditions like bounds errors - the name hints at some exception (~trap) system.

        The example of zeroing an out-of-bounds pointer isn't exactly the best error indication mechanism.

        Likewise not writing beyond the end of a buffer and blithely continuing on, could have quite serious ramifications were the truncated contents of the buffer to be used in a critical or sensitive context.

        What is unexpectedly missing can be far more dangerous than that which is unexpectedly present. (Think the pin of a hand grenade. ;)

    5. DS999 Silver badge

      Re: I've taken out union and some other things that I rarely use

      This isn't going to be for "moving all your code".

      It would be for writing new code, or for writing limited sections of existing code that are security critical due to running with elevated privileges or futzing around with stuff with security implications like private keys.

      Outside of I/O drivers, it is hard to find good cases where union is necessary. Like needless pointer casting, unions are often used as a crutch by poor programmers who don't see the right way to do things.

    6. find users who cut cat tail

      Re: I've taken out union and some other things that I rarely use

      There is a bigger problem. You can absolutely do things like this in C:

      return (char*)malloc(42) + 123456;

      Or XOR the pointer with something, or whatever.

      And then in a galaxy far far away a different piece of code undoes the transformation, gets a valid pointer, does something with the memory and frees it. No code analysis can figure out whether the memory block is still use or not, or whether the pointers are valid. The allocation and use may be even compiled completely separately. So the basic premise is false.

      You may consider it contrived, but there are use cases for keeping around different pointers than what malloc() gave you. Or if you know the alignment (for instance to multiple of 16) you can use the lowest bits of the pointer to encode some extra information and clear the bits when you are actually using it as a pointer. Etc. It is exactly the ability do such low-level stuff why you use C in the first place.

    7. ForthIsNotDead
      Stop

      Re: I've taken out union and some other things that I rarely use

      >This choice definitely needs much more examination before I'd try it.

      Being a bit negative there. I mean, your argument about needing to free up large chunks of memory sounds perfectly reasonable. Why not engage with the guy and suggest it rather than ignore what could be a good solution to memory safety in C?

    8. empedocles

      Re: I've taken out union and some other things that I rarely use -> Union are useful

      Howard:

      1) I do like the idea of TrapC, overall it makes lots of sense !

      2) Unions (like varian records in Pascal) are very useful for typecasting, especially in system low level, protocols, and more : please consider implementing it for this reason, and also to make compatibilty easy.

      3) "New" instead of "malloc" as described here seems fine to me.

      4) One feature to consider is to drastically reduce the need for C macros, by creating compilers objects (like in assembly) so debuggers will always work !

      "Keep is as simple a possible, but not simpler"

      Albert Einstein

  8. heyrick Silver badge

    "if you try to open a file and don't code an error condition to handle what happens when the file doesn't open, the program will probably crash"

    I can't help but think that the problem here isn't the language...

  9. tiggity Silver badge

    calloc?

    "Where you see a big difference is TrapC doesn't have malloc. TrapC has new, like C++ does. And so you need to change all your malloc calls."

    A bit of a stumbling block, as would certainly mean porting old code would likely need work as calloc / malloc usage can be very common, especially in quite old codebases.

    Though (in my experience) calloc far more often used than malloc ( unless speed was absolutely critical, & the miniscule overhead of clearing the data was just too much then do not use malloc) , in C would use typically calloc as always safer having "cleared" data than retaining preexisting value that happened to be in that area of memory e.g. there's a small but non zero chance* that if you are testing your pointer data to see if it matches a value, that might just be a match with the "junk" that was present in the memory to begin with.

    *Yes, I have seen that erroneous match on value X**. It should not be a surprise, especially if your software that creates value X one or more times in its normal usage is frequently run on that machine, quite likely to be getting memory via malloc that your code has populated on a previous run..

    ** and where X is a non trivial value, i.e. not just a few bytes

    1. DS999 Silver badge

      Re: calloc?

      #define malloc new

      #define calloc new

      #define free(P) ;

    2. ibmalone

      Re: calloc?

      Though (in my experience) calloc far more often used than malloc ( unless speed was absolutely critical, & the miniscule overhead of clearing the data was just too much then do not use malloc) , in C would use typically calloc as always safer having "cleared" data than retaining preexisting value that happened to be in that area of memory e.g. there's a small but non zero chance* that if you are testing your pointer data to see if it matches a value, that might just be a match with the "junk" that was present in the memory to begin with.

      I've generally been of the opinion that you should initialise correctly, and the correct initialisation of a region is not necessarily all zeros. I've seen bugs where failure to set correct initial values for an algorithm has been masked by an earlier initialisation (to shut the compiler up? I don't really know why people do this, int somevar=0; and then set the value it really should be later). Calloc is in the same class, if you really want zeros then it's the fastest way to achieve it, a nul-terminated string then you'll get it but it's not the most efficient. And if using realloc you'll need to deal with it anyway. (There's even a more subtle type of bug, which is more at the algorithm than processing level, where starting with an array of zeroes will bias your output, have been looking at that in a variant of multilevel spline fits for a while now, it's not a coding error as such, but a tendency to reach for things like calloc might encourage the mindset.)

      1. DS999 Silver badge

        Re: calloc?

        But the default should be 0. That's already the default for global variables, it is only an issue for stack variables. C should have specified that all stack variables start at 0, but when it was designed K&R didn't want to pay the performance penalty for that. There's no reason why that couldn't have been added in C99 or other updates to the standard though!

        Global variables being zeroed was/is "free" because process startup allocates enough data pages to hold all the global variables and new page allocations are zeroed in Unix (and any other reasonable OS) but there would need to be explicit work on function entry to zero the variables on the stack which was a much bigger hit on a PDP-8 than a modern CPU. So it made sense in the early days to leave them undefined, but that's silly today.

        If the programmer wants something other than 0 to be the starting value, he can explicitly set it - which is no different than the situation today. If you ever have a stack variable that just happens to be preset to the value you want without explicitly setting it, you are relying on side effects of the stack framing which could change the next time you recompile and would definitely fail if you ever ported to another OS or ISA.

        1. Dan 55 Silver badge

          Re: calloc?

          There's -ftrivial-auto-var-init=zero in gcc 12/clang 8 and above, but I'm not sure if it's the kind of thing to use in existing code in production if 0 could be a valid value. Personally I'd use -ftrivial-auto-var-init=pattern as a way of finding uninitialised variables.

          1. ibmalone

            Re: calloc?

            -ftrivial-auto-var-init=pattern

            This is a nice trick I didn't previously know about, although it obviously doesn't help with alloc heap memory. I've found libasan + -fsanitise=address useful in the past.

        2. ibmalone

          Re: calloc?

          If the programmer wants something other than 0 to be the starting value, he can explicitly set it - which is no different than the situation today. If you ever have a stack variable that just happens to be preset to the value you want without explicitly setting it, you are relying on side effects of the stack framing which could change the next time you recompile and would definitely fail if you ever ported to another OS or ISA.

          Well, this is exactly what I mean. I'm not talking about relying on things being non-zero on allocation, I'm talking about zero only being a suitable initialisation in certain trivial cases anyway and it generally being preferable to using explicit appropriate initialisation. Of which calloc is one type, but I'm not sure I'd propose always using calloc instead of malloc just because sometimes zero is what's wanted. As you mention, global variables default to =0, but it's difficult to tell a global variable someone wanted initialised to 0 from one where they just forgot to give the correct value. An example might be a volume in medical imaging where NaN may be a more appropriate way to initialise data in certain cases, but typically people start with zeroes, a more common one would be structures, where normally some initialisation function is needed.

          Which is a roundabout way of saying I'd read malloc() as "allocate the memory, still to be initialised" and calloc as "allocate the memory and initialise it to zeroes", i.e. in the second case zeroes are the correct starting value, rather than just a starting value.

  10. F. Frederick Skitty Silver badge

    "It's slated to be overseen by Rowe and Pantera".

    Nice of Pantera to take time out from touring to oversee this.

  11. Alien Doctor 1.1

    This'll be down voted...

    For all my own coding needs I still use Fortran77 (and I am still COBOL proficient but retired). I never had the chance to learn c or ++ within a business environment or, tbh, never had the need.

    1. Alan Mackenzie

      Re: This'll be down voted...

      I'm not down voting you, but I'm curious - don't you use any scripting languages for the small problems which crop up, day to day? Something like bash, or AWK, or Python, or Perl?

      For example, to count the total size of files in a directory, using bash and AWK would look something like this:

      ls -lrt | awk 'tot += $5; END {print tot}'

      . I don't doubt you could code this in Fortran, but it would be much longer, more tedious, and more error prone to write.

      1. This post has been deleted by its author

  12. StrangerHereMyself Silver badge

    Managed pointers

    I had the same idea and called it "managed pointers" in C or Pascal. You can make efficient algorithms but the pointers wouldn't be "real" pointers (i.e. memory addresses) but constructs that are managed by the runtime (not a virtual machine, mind you; more like a library).

    The biggest drawback would be that these managed pointers would always be slightly slower than the real thing because of the overhead involved. But it's still a lot better than (relatively) slow languages like C# or Java, which in addition need a runtime for them to function.

    You'd probably still need some "unsafe" escape hatch to interact with real pointers, like video memory.

  13. alcachofas

    Dead in the water.

  14. martinusher Silver badge

    Maybe a useful wheel to reinvent

    The typical "Hello World" programming example doesn't really tell you what's going on, it is using a model of the computer that overlooks things like rounding up variables to a machine word size (unless specified as packed), the operation of stacks and data caches and so on. All stuff that a C programmer has to be aware of, along with watching out for missteps with post/pre increment/decrement operators, execution sequence (especially with bit test / bit wise operations), integer over and underflow. All grist to the mill.

    The fact is that people do put diagnostic wrappers around key bits of code. During testing. If you're not prepared for that level of intensity when testing code (its time consuming and fiddly so its understandable) then you're better off using a language that's got built in checks. There's plenty to choose from just don't expect to write operating systems in them. (Anything's possible, but...)

  15. rgjnk
    Devil

    Code analysis

    Isn't a lot of this covering stuff that a static or maybe a dynamic analysis run would show up anyway? Uninitialized use without a test or whatever is basic stuff, and even the 'safe' languages will complain it needs fixing in the IDE because it will still go bang in a potentially nasty way, just with an exception instead of something lower level.

    Feels like reinventing the wheel to cover careless mistakes which are already avoidable, and without truly fixing anything?

    Surely it's better to check and test your code than to try to childproof the environment in what's still a limited way?

    1. NickHolland

      Re: Code analysis

      you aren't wrong...but

      1) the demand for programmers greatly outstrips the supply of GOOD programmers.

      2) the demand from bosses to produce results NOW and worry about mess later is, if not universal, very common.

      3) more and more programming work is going to barely-skilled low-cost "other country" development houses, where quality of work is irrelevant.

      So...safer languages are needed.

      Except...that lowers the bar for people to think they are "good" programmers, which ends up reminding people there are more ways to lose data than just memory errors in C. I saw something once a number of years ago, where some prestigious school washed out 75% of their computer science students when they were teaching C. Once they switched to Java, they graduated 75% of their entering CS students. So most of the graduates still sucked, but they could pass and get a sheet of paper and go writing banking software.

      I have no idea what the answer is...

      1. Bebu sa Ware
        Coat

        Re: Code analysis

        the demand for programmers greatly outstrips the supply of GOOD programmers.

        I suspect the demand for good programmers is virtually non-existent - the demand for cheap programmers is insatiable which is why manglement are tossing themselves blind over autonomous AI programming systems.

        1. Anonymous Coward
          Anonymous Coward

          Re: Code analysis

          Cheap programmers usually end up costing a fortune unless you are really lucky ... Then again expensive programmers don't always equate to being good either....

  16. david 12 Silver badge

    Just add a byref keyword and be done with it.

    50 or more years ago they invented languages where pointers were handled by the compiler, you didn't declare a "pointer" var, you declared the memory pointed to, and the compiler indexed correctly.

    No, that's not the same as overrun protection, and no, it doesn't add any overhead. It just lets the compiler handle the stuff compilers are good at.

  17. vekkq

    Odd take to make it to easily replace C but then require to rewrite every malloc.

  18. Ken Y-N
    Alert

    No terminating '\0'?

    char buff[8];

    ...

    if(!strcmp(buff,"s3cr8tpw"))

    That code implies that there's no NUL character at the end of strings. I can see why it might not be needed if you have a length field somewhere, but that's quite a change.

    Also, the next snppet has:

    const char* ptr = "Hello World"; // 12 char wide

    Shouldn't that be 11?

    1. DS999 Silver badge

      Re: No terminating '\0'?

      You didn't read it closely enough.

      There IS a terminating /0, but it will block any attempt to write anything other than /0 to the 8th character of a 8 character array. It will fail the comparison with that 8 character string for that reason.

      If you ran that same code in C that comparison would succeed, because the 'success' variable that immediately follows it on the stack is where the 9th character /0 would be written beyond the bounds of the 8 character buffer[] variable. If you ran that same code in C but with success set to -1, the value of success would be altered (-2^24+1 or something like that) when that 9th character /0 was written.

      1. Ken Y-N
        Headmaster

        Re: No terminating '\0'?

        Ah yes, I see my misunderstanding and I wasn't thinking at all of the contiguous memory... The comment "TrapC blocked strcpy overwrite, success good" means that it hasn't been trampled by the 'strcpy()' rather than being set to 1 explicitly in the previous 'if' branch. I know, read the code, not the comments!

        But, assuming 'success' comes directly after "buffer[]' is incorrect except in perhaps a debug build, as a release build would likely put 'success' in a register, so "Welcome" would not be printed despite the memory overwrite. You've now got a bug of the most annoying type, working in Release but failing in Debug.

        To sum up, this is a bad example.

        1. DS999 Silver badge

          Re: No terminating '\0'?

          Well it is a bad example but not for the reason you think. If success is a register it will still work properly in TrapC, because the TrapC runtime will not allow the 8th character in buffer[] to be overwritten.

  19. Bebu sa Ware
    Facepalm

    Seeing a picture of Linus just under this article...

    I imagine he is thinking "not another <finnish-expletive/> language demanding the keys to the kingdom."

  20. Nevyn

    An old idea

    The concepts behind this have been around for a while. There was a C/C++ compiler available from Salford Software in the 1990s that did pointer validation and it was fairly comprehensive. There was a price - speed and additional memory usage.

    The Salford C/C++ compiler checks meant that every use of a pointer was validated and the validations were put into the code by the compiler itself. This meant that vanilla C/C++ code could be used without modification.

    The code generated was larger as it had to perform the checks. The checks made the system slower and so they had to be turned on rather than being on by default. Machines in the 1990s were not that fast :).

    For transparency - I worked on the product.

    1. bbj

      Re: An old idea

      Perhaps look at EPOC16, from the late 80s/early 90s, then EPOC32 (the precursors to Symbian OS) to see just how old...

      TRAP() and TRAPD() - all sounds pretty familiar to this old git! and all within a std C/C++ compiler of its day - exceptions were not a thing back then.

      No amount of safety handling can deal with the 'open a file' to do some work, opening the file fails but we still magically manage to do the work. Sure some langs can automatically handle the error state more elegantly than others but they cant automagically fix the underlying issue - the data set becoming unavailable... or maybe they can these days by simply sprinkling some AI ontop...

      1. martinusher Silver badge

        Re: An old idea

        The fundamental problem is that unless you can guarantee that all API calls will be successful all the time then software can become a bunch of error handling with the actual work path buried somewhere inside. Traps are just an elegant way of disconnecting error handling from program flow so that the program structure doesn't get buried.

        FWIW -- Logic design has the same problem. You can't just ignore or rationalize unnatural system states with a 'that can never happen' unless its really true, that situation cannot happen by design. If you fail to dot every 'i' and cross every 't' in your design then by Murphy's Law the logic will unerringly find its way to an error condition (usually at a critical or embarrassing time).

  21. efa

    sanitizers

    all modern compiler has an option to add runtime code that check data boundary, double free, use after free, miss free, stack overflow, and so on.

    At beginnig was Clang/LLVM, but GCC 4+ has it from some years now.

    That runtime code slow down binary to the level of C#, Java and Rust, so must be used only when build for debug with -g.

    Once code is clean, you can remove sanitize address and get fast pure C compiled memory safe code without compromize.

    Today we do not need memory sage languages, simply skilled programmers

  22. ssieler

    What if, say, you go to open a file in C and if you don't say what happens when the file doesn't open, then that creates some kind of error condition that gets implicitly called?"

    Gee, like in Burroughs ALGOL in 1970?

    Their OPEN could be called 3 ways:

    If open (....) then

    ... // your code to do some error handling

    Open (...) [error_label]

    // implied goto if open fails

    Open (...)

    // implied abort() if open fails

POST COMMENT House rules

Not a member of The Register? Create a new account here.

  • Enter your comment

  • Add an icon

Anonymous cowards cannot choose their icon

Other stories you might like