20 ms·
Some Were Meant For C (2017) [pdf]
- ncmncm 6y agoThe article mentions C++ three times, all in contexts equating it with C. But C++, as it is coded today, is a very different language from C, and does not suffer from the problems that make C an extremely poor choice for starting any new project that might matter. All the article's arguments for C apply substantially moreso to C++. Thus, the article leaves us with no objectively plausible reason ever to code in C, except where artificial constraints mandate it, or where merit doesn't matter. (I leave to the reader to decide where Linux and BSD kernels fit in that.) There is especially no excuse for systemd to be coded in C.
- coliveira 6y agoI disagree. First of all, most C code can be run as C++, so everything bad you can say about C applies to C++ as well. Second, C++ introduces its own problems that also make programming unsafe compared to other managed languages and even compared to C.
- qznc 6y agoYou would constraint yourself to a subset of C++ which is not C. For example, forbid all raw pointers and only use smart pointers. Now your memory is freed automatically via RAII and use-after-free errors are much harder to create.
- coliveira 6y agoAs you said, this is a subset of C++. But everyone debates what the right subset should be. In reality C++ is incapable of solving the problem, it can only propose good practices.
- aromatic_dev 6y agoThough if one only uses smart pointers they will have to accept the performance hit that that brings -- in high performance situations, this may be unacceptable.
- ncmncm 6y agoCircumstances where using smart pointers affects performance are vanishingly rare. Where performance matters, on any critical path no allocation or deallocation is done, so a smart pointer can have no effect. On other paths, any difference is swamped by overhead in malloc and free. So, in actual practice, no.
- wheybags 6y agoThere's some argument to be made about bookkeeping and (maybe? I'm not sure) an extra level of indirection with shared_ptr, but the cost of unique_ptr is literally zero.
- ncmncm 6y agoPassing unique_ptr by move works out to be surprisingly expensive, so one doesn't, where that matters. (It is usually a mistake to have unique_ptr visible in an interface at all, but passing a pimpl type, implemented with unique_ptr, by move costs exactly the same.) And of course no one who cares for their reputation is seen using shared_ptr.
- boring_twenties 6y agoWhat's the expense of moving unique_ptr -- is it resetting the source to nullptr?
- mawww 6y agoMy guess is that because in most common x86_64 calling conventions the caller is responsible for destructing the parameters, it has to run the unique_ptr parameter destructor which needs to check if it was moved from in the callee or not. Additionally, because this destructor is not a trivial one (i.e. it does something), unique_ptr cannot be passed directly through a register but must be spilled on the stack.
- qznc 6y agoC++ still has a lot of rope to hang yourself. For example, there is the stuff Rusts borrow checker prevents. Or that members are initialized by declaration order and a wrong initializer list can lead to undefined behavior. Or all those implicit conversion rules (ok, the annoying tendency to convert to int is inherited from C). The most ugly aspect is that C++ has a lock-in effect like Whatsapp. As long as your codebase is in C, you can easily interface with nearly all other languages. Once important parts are in C++ though, only C++ can reasonably interface with it.
- ncmncm 6y agoIf "lock-in" is something wrong with C++, it is equally so with Rust. But in fact anything you want callable from C, in either C++ or Rust, is easy to keep that way. To the other point, you can write bad code in any language, Rust included. But you don't have to. A language can help by making good code easier to write than bad code. C fails so frequently by making good code much harder to write, instead.
- sweeneyrod 6y agoC++ is about 17 languages
- AlbertoGP 6y agoRelevant to recent discussions, even if it was published in 2017. It is quite more elaborate than other publications I’ve seen mentioned in those discussions. I’ll quote section 6.2, “What is Safety Anyway?”: > I have learned to enjoy provoking indignant incredulity by claiming that C can be implemented safely. It usually transpires that the audience have so strongly associated “safe” with “not like C” that certain knots need careful unpicking. > In fact, the very “unsafety” of C is based on an unfortunate conflation of the language itself with how it is implemented. > Working from first principles, it is not hard to imagine a safe C. As Krishnamurthi and Felleisen [1999] elaborated, safety is about catching errors immediately and cleanly rather than gradually and corruptingly. Ungar et al. [2005] echoed this by defining a safety property as “the behavior of any program, correct or not, can be easily understood in terms of the source-level language semantics”—that is, with a clean error report, not the arbitrary continuation of execution after the point of the error.
- coliveira 6y agoI believe the main issue at play here is a paradox in software engineering. The paradox is this: safe languages are more useful on complex projects that in simple projects, but complex projects suffer more from performance degradation and system integration issues when these languages are used. Put from the other side, C is perfectly fine to write short pieces of code, but despite its problems it may be the only reasonable language to write large pieces of system software (I'm including C++ here as a "kind of" of C, just like Objective-C).
- vmchale 6y ago> safe languages are more useful on complex projects that in simple projects, but complex projects suffer more from performance degradation I don't think that's true. C is often slower than C++ because of how inlining works, plus some domains (e.g. compilers) it's best to just use a GC language from the get-go.
- iainmerrick 6y agoC is often slower than C++ because of how inlining works Hang on, you’re cutting a few corners there! It’s easy to use inline functions in C too. Are you thinking of C++ templates, and the fact that e.g. std::sort is faster than qsort because it directly calls an inlined comparison function rather than a function pointer? That’s true, although it’s possible to achieve similar performance levels in C via hand-rolled data structures or macro hackery. I’ll grant you that the efficient C++ code is more idiomatic and likely safer. On the other hand, idiomatic C code is likely smaller when compiled, which can be important for performance too. I don’t believe “C is often slower than C++” is true in general.
- jstimpfle 6y agostd::sort is the poster child that is supposed to demonstrate the power of C++ templates. When in fact it is awkward to use (as an infrequent user of C++, why can't I never seem to remember how to wrap / make the comparison object?) and more importantly, sort performance is most often completely irrelevant to the performance of a program. And when it's not irrelevant, it's almost 100% certain that std::sort is not the right thing to use. Where it matters, it's probably possible to examine the context a little more closely and come up with a custom sort that runs in O(n) or at least faster than std::sort.
- coliveira 6y agoThe author raises an important issue here: many people are lead to believe that using C is inherently unsafe. That's not true, and many of the most secure systems in the world were written in C. The other direction also doesn't work: software written in languages like Java can be effectively unsafe.
- pjmlp 6y agoOne of the most secure OSes is ClearPath MCP, zero lines of C on its kernel, rather NEWP. Azure Sphere, Solaris and latest versions of iOS all rely on some variation of hardware memory tagging to tame C exploits.
- astrange 6y agoiOS uses ARM "pointer authentication codes". There's actually a newer extension called ARM "memory tagging extension" and it doesn't use it as far as I know.
- pjmlp 6y agoCorrect, the point being it uses something. It also uses a safe C dialect for iBoot. https://support.apple.com/guide/security/memory-safe-iboot-implementation-sec30d8d9ec1/web https://support.apple.com/guide/security/memory-safe-iboot-i...
- bitwize 6y agoOnce again. We know from 40 years of discovering memory-related vulnerabilities in even the most carefully written, rigorously tested C programs that writing safe C is intractable for real, human software engineers. So yes, C IS INHERENTLY UNSAFE. If you claim otherwise you clearly haven't been paying attention to what's going on.
- thesuperbigfrog 6y agoC and C++ code CAN be secure, but most of it is not. It is too easy to write or update C / C++ code so that it is no longer secure or has unexpected and unsafe results. https://blog.regehr.org/archives/213 https://blog.regehr.org/archives/213 gives great insights into how undefined behavior in C and C++ can be difficult to reason about and cause problems. The lack of bulletproof memory safety and easy-to-stray-into undefined behavior of C and C++ make it easy to create code that is difficult to fully grasp how it will behave, especially when optimizing compilers are used. The C / C++ code runs really fast, but there are hidden dangers lurking. I don't doubt that C and C++ will be with us for a long time to come, but the growing use of Rust, Zig, Ada, and others show that better alternatives exist and that they will replace the use of C and C++ for many domains and use cases. Edit: Downvotes? Did you read my whole comment? I am saying that C / C++ are not secure for real-world use cases.
- coliveira 6y agoUndefined behavior is not the problem that people make it to be. First of all, undefined behavior is well understood by compilers, in fact it is exactly exploited by compilers to make code run faster. The only thing you need to solve UB is to ask compilers to stop exploiting it (which normally can be done by reducing optimization). And of course you can rewrite your code to stop relying on UB. Despite all the complains, I have never seen code suffering from UB that couldn't be fixed.
- thesuperbigfrog 6y ago>> undefined behavior is well understood by compilers The security implications of undefined behavior are poorly understood by software developers: https://arc.aiaa.org/doi/pdf/10.2514/1.I010699 https://arc.aiaa.org/doi/pdf/10.2514/1.I010699
- MaxBarraclough 6y ago> Undefined behavior is not the problem that people make it to be No, undefined behaviour is a serious problem, especially regarding security. There's a long history of serious security problems in C and C++ codebases due to unintended invocation of undefined behaviour. These issues continue to arise even in well-resourced C/C++ projects with highly skilled developers, such as the Linux kernel and Chromium.
- jvanderbot 6y agoI've entered a mid-life zen w.r.t. languages. Most important is the people and irreplaceable knowledge they have in their heads, about the tricks, methods, and environments they've worked in. Languages correlate with that, and so are a semi-useful indicator of past skills. You want a person to write the bootloader for your Mars helicopter? You hire a C programmer most likely, not a C# programmer, but who knows? You want a person to bootstrap your image processing pipelines for your scientists? Maybe Python? Maybe? This area is much more loose. If a valuable tool or method is expressed in (or even only expressible in) a particular language, then so be it. Often, there are many more choices than people believe, and what is right for the person, so long as it serves the organization or need appropriately, is fine by me. A language is a tool. Most languages do pretty much the same thing. Most languages' ecosystems, application adoption, and developers are much more important than the languages' seatbelts and headlights.
- qznc 6y agoI disagree that languages "pretty much the same thing". However, I do agree that language choice is overrated. Other factors, e.g. which one you know better, weigh heavier.
- jvanderbot 6y agoOK, over-simplification. Perhaps: Language in-class variance is small (C# ~= Java, C++, C, RUST are close-ish). Cross-class variance is big (JS vs Rust). Therefore, recruiting a programmer from the same problem / language class is more important than the particular language.
- derekp7 6y agoWhat is also important is the ecosystem that comes along with the language. Modern languages have a wide ranging list of libraries and plugins for them which make certain programming tasks easier. But that also means you have an ever shifting stack that is required to support them. This became apparent to me when trying to get some infrastructure software to play nice with some of the older systems we need to keep around. There were some nice Python based solutions that I had to reject because the dependencies didn't exist for some older RHEL installations we have (yes, we still need to keep a hand full of RHEL 4.x systems around because management doesn't want to tell customers "no we won't support you unless you upgrade to our latest product that works on newer OS releases". So for backup and management solutions, I have to stick with tools that can be easily compiled on the older environments. Another example, one of our architects at work is a strong supporter of Apple, and wanted me to look into Swift. Well at the time you could get Swift for Ubuntu, but couldn't for any version of RHEL (that has finally changed now though). So again, writing my code in plain C was more of a win.
- FpUser 6y ago>"...I use because I’m stuck with it; I use it for positive reasons. " I absolutely agree with that statement. When I do firmware for small MCUs I feel big fat zero need for any other language.
- bachmeier 6y agoI remember when this paper came out, I tweeted at the author about D's "Better C" mode since he used that very term. It really is a better C, because C is almost a subset of D. You get nice features like array bounds checking, but no runtime, no garbage collector, etc. It's a good choice for those that prefer to stick with C but wish there was a 2021 upgrade. https://dlang.org/spec/betterc.html https://dlang.org/spec/betterc.html
- ducktective 6y agoWho are the designers/institution behind D and why they have not promoted it as much as newer alternatives?
- bachmeier 6y agohttps://en.wikipedia.org/wiki/Walter_Bright https://en.wikipedia.org/wiki/Walter_Bright https://en.wikipedia.org/wiki/Andrei_Alexandrescu https://en.wikipedia.org/wiki/Andrei_Alexandrescu They've promoted it (holding annual conferences and such) but they don't have Mozilla or Google behind them, so resources are limited. Edit: And here are some blog posts by Walter Bright about D as a Better C. https://dlang.org/blog/2017/08/23/d-as-a-better-c/ https://dlang.org/blog/2017/08/23/d-as-a-better-c/ https://dlang.org/blog/2018/02/07/vanquish-forever-these-bugs-that-blasted-your-kingdom/ https://dlang.org/blog/2018/02/07/vanquish-forever-these-bug... https://dlang.org/blog/2018/06/11/dasbetterc-converting-make-c-to-d/ https://dlang.org/blog/2018/06/11/dasbetterc-converting-make...
- rob74 6y agoWell, Rust doesn't have Mozilla behind them anymore either (ok, they now have a foundation with not only Mozilla, but also Microsoft, Amazon, Google and - whoa! - Huawei as sponsors, so you could argue that's an improvement). And I'm not sure how much Google is really invested in backing Go. But yeah, I guess D looks small in comparison to both...
- mhh__ 6y ago
- xianwen 6y agoBut is there some guides or books that teach people write safe C codes? Is writing safe C codes possible?
- sigjuice 6y agohttps://wiki.sei.cmu.edu/confluence/display/c https://wiki.sei.cmu.edu/confluence/display/c
- peterburkimsher 6y agoI'm an embedded software engineer for a medical device manufacturer, and we've had training on MISRA C. It applies to the whole software lifecycle, and tries hard to make a subset of C that is appropriate for safety-critical systems. https://en.wikipedia.org/wiki/MISRA_C https://en.wikipedia.org/wiki/MISRA_C Personally I don't agree with all the guidelines. This morning a colleague said "I'm so glad someone had the foresight to include [unused API function]". Strict MISRA compliance would require "no unused code". I also prefer having more comments. Generally though, I think the advice is helpful, particularly about specific types (uint32_t not int), avoiding malloc, and complexity limits. This is a totally different style of coding to what I've been used to at startups in the past. It's "software engineering" instead of "move fast and break things". During my 20s, I'm glad I had more broad experience of creative solutions, new languages, janky code, late nights, pretty demos, shipping /something/ then iterating on that. Now I'm 31 and settling down, this slower-paced but much more careful approach seems more suitable.
- RcouF1uZ4gsC 6y ago> Most obviously in C, we note that a malloc() implementa- tion is usually written in C—or rather, in a subset of C that lacks malloc() since malloc() is mandated by the C standard. Not always. Google’s tcmalloc is actually written in C++. I actually would have agreed with a lot of this in 2017. However, in the past several years, I think Rust has been a game changer. It can interface with the C ABI. It can access the same low-level abstract machine that C can. It doesn’t have garbage collection or virtual machines. And it provides memory safety out of the box. In addition, features such as strong types and pattern matching help less logical bugs as well (like the compiler checking that you did not forget one arm of an Enum). This is born out now that a lot of security facing software is starting to do at least part of their internals in Rust, where they had been in C before. I think Rust is and will be even more in the future a game changer in how we write the foundation programs and libraries that the computing world is built on.
- astrange 6y agoWhat they're saying is that malloc() can't be implemented in C, because C defines malloc() as having behavior that's not possible in C's memory model. I think it is more possible in C++ due to placement new, though tcmalloc is probably still relying on language extensions.
- ttt0 6y agoWhat? Linux is written in C and it there is no malloc in the kernel. Just don't include standard library.
- astrange 6y agoLinux isn't written in C either, it's written in C with a lot of language extensions. The ability to implement malloc() is just another language extension where the compiler promises to ignore the type aliasing issues. Implementing memory barriers (pthread_mutex_lock()) used to be strictly speaking impossible in C too, but it's possible now that it has a defined memory model.
- 6y ago
- dleslie 6y agoAll I really want added to C is Zig's comptime.
- zokier 6y agoIs the second example (the auxv stuff in section 5.1) invoking undefined behavior in here "at_null−>a_type == AT_NULL"? As far as I understand, in C you really generally can not pull out valid pointer out of thin air like author is doing there. Isn't that the whole idea behind "pointer provenance"?
- khuey 6y agoIt's not pulled out of thin air, it's constructed from `environ`.
- jxy 6y ago> A final interesting property of this code is that its be- haviour is undefined according to the C language standard. The reason is that it calls memcpy() across a range of memory comprising multiple distinct C objects, copying them all into memory-mapped storage in a single operation. What's wrong with memcpy here? As long as dst and src are both non-zero and the ranges of memory are not overlapping, the behavior of memcpy is well defined.
- MaysonL 6y agoStructure alignments…
- jxy 6y agoAs long as the size argument is initialized as sizeof(struct ...), it is totally fine, isn't it?
- rurban 6y agoPointers into a copied region are invalidated. Only GC languages do such memory copying safely. It's also insanely slow with gcc, compared to clang. Like factor 1000 with some compile-time constants.
- dang 6y agoIf curious, past threads: Some Were Meant for C (2017) [pdf] - https://news.ycombinator.com/item?id=19736214 https://news.ycombinator.com/item?id=19736214 - April 2019 (176 comments) Some Were Meant for C: The Endurance of an Unmanageable Language [pdf] - https://news.ycombinator.com/item?id=15179188 https://news.ycombinator.com/item?id=15179188 - Sept 2017 (240 comments)
- ciarcode 6y agoCan someone explain me why do we use C for writing code for electronic control unit of a vehicle motor if it is so unsafe? It is true that ECUs are programmed with code generated though model based design,but there can be some parts manually programmed. Maybe this is why they use only a subset of C (Misra C)
- ironman1478 6y agoProbably because of 1. Inertia. its already being used, so why not keep using it? I can't prove this, but it feels true 2. Lots of microcontroller vendors provide tooling for it. You are basically guaranteed to be able to run C on whatever micro controller you want. Even if you don't get a standard library, you can implement your own if you need to. Languages like C++ have large runtimes and are hard to port to lots of platforms 3. Its an "easy" language to use for people who work on these devices and the problems of an ECU are not the problems of a database for example. I've worked on large enterprise databases and now I work on cameras for a car-ish company. The scale is just different and you simply don't need as many features as in C++, haskell, rust, python. The hard part on a small embedded system is not the coding per se, its the algorithms. A lot of these devices work at fixed rates on a timer (or respond to a very periodic interrupt), have a well understood amount of work to do in a fixed window of time, and then go back to sleep until the next job is queued. Memory safety won't help you when critical failure is defined as being late to respond. Would I love to have total memory safety at the moment? Totally! But its the least of my concerns at the moment and if my toolchain doesn't support it, then oh well we just have to code to the standards of misra and follow standards like iso26262. I should say, writing C on a large project sucks. I've seen it before and I personally hate it (large portions of the database were in C). Its just too complicated and while C++ isn't perfect, having things like a destructor and templates are really nice and just makes the problems tractable.
- cozzyd 6y agoUsually in embedded development you don't ever want to use dynamic allocation. Very few languages allow you to avoid dynamic allocation.
- 6y ago
- 0xdeadfeed 6y agoNASA just sent a rover on Mars using software written in C. Meanwhile some Rust fanatics are busy telling everyone how it doesn’t work.
- barongrounds 6y agoThe Rover is not connected to the internet. Do you know what subset of C NASA limits itself to? Or hw architecture? The rigour of their testing? Should all C developers follow the same restrictions as NASA?
- peterburkimsher 6y agoThe rover was built by NASA JPL, and they have their own coding standard based on MISRA 2004. https://andrewbanks.com/wp-content/uploads/2019/07/JPL_Coding_Standard_C.pdf https://andrewbanks.com/wp-content/uploads/2019/07/JPL_Codin... https://nodis3.gsfc.nasa.gov/displayAll.cfm?Internal_ID=N_PR_7150_002A_&page_name=all https://nodis3.gsfc.nasa.gov/displayAll.cfm?Internal_ID=N_PR... Hardware (according to Wikipedia) is a BAE Systems RAD750 radiation-hardened single board computer based on a ruggedized PowerPC G3 microprocessor (PowerPC 750). The computer contains 128 megabytes of volatile DRAM, and runs at 133 MHz. https://en.wikipedia.org/wiki/Perseverance_(rover) https://en.wikipedia.org/wiki/Perseverance_(rover) Testing sounds pretty rigorous, at least for large projects. https://www.quora.com/What-does-a-software-engineer-do-at-the-NASA-JPL https://www.quora.com/What-does-a-software-engineer-do-at-th... Personally I firmly believe that "all C developers" do not need to follow these regulations. It might even be counter-productive to slow down the development process for some clients. For safety-critical systems, these rules make sense. For little startups, they don't. Developers are smart enough to learn these rules, so HR shouldn't ask for "5 years MISRA experience". It's really a choice of business model, time to market, and risk management. If you're a big company looking to cut costs, be careful about outsourcing firmware development to a little startup who might not follow these rules so strictly. I won't follow these rules for the stuff I throw together in my free time and put on Github, but I will be careful before committing code to master for medical device firmware.
- jimbob45 6y ago
- microtherion 6y agoThe paper starts with a series of snippets designed to show off the unique abilities of C that are chock full of undefined behavior, and then argues that C can be used safely if only programmers and compiler writers were to agree to stay away from undefined behavior. I'm getting mixed messages here… And the title, to me, evokes William Blake: "Some are Born to Endless Night".
- adyavanapalli 6y agoThe author's conclusion: I have argued that C’s enduring popularity is wrongly ascribed to performance concerns; in reality one large component of it (the “application” component) owes to decades-old gaps in migration and integration support among proposed alternatives; another large component of it (the “systems”component) owes to a fundamental and distinctive property of the language which I have called its communicativity, and for which neither migration nor integration can be sufficient. I have also argued that the problems symptomatic of C code today are wrongly ascribed to the C language; in reality they relate to its implementations, and where for each problem the research literature presents compelling alternative implementation approaches. From this, many of the orthodox attitudes around C are ill-founded. There is no particular need to rewrite existing C code, provided the same benefit can be obtained more cheaply by alternative implementations of C. Nor is there a need to abandon C as a legitimate choice of language for new code, since C’s distinctive features offer unique value in some cases. The equivocation of “managed” with “safe”implementations, and indeed the confusion of languages with their implementations, have obscured these points. Rather than abandoning C and simply embracing new languages implemented along established, contemporary lines, I believe a more feasible path to our desired ends lies in both better and materially different implementations of both C and non-C languages alike. These implementations must subscribe to different principles, emphasising heterarchy, plurality and co-existence, placing higher premium on the concerns of (in application code) migration and interoperation, and (in the case of systems code) communicativity. My concrete suggestions—in particular, to implement a“safe C”, and to focus attention on communicativity issues in this and any proposed “better C”—remain unproven, and perhaps serve better as the beginning of a thought process than as a certain destination. C is far from sacred, and I look forward to its replacements—but they must not forget the importance of communicating with aliens.
- jqcoffey 6y agoIsn't OpenBSD written in C? w.r.t. "unsafe", just sayin'.
- nec4b 6y agoI would like to mention that C is able (certified) for writing safety critical code while rust isn't. Therefore critical systems for aerospace, auto industry and other special industries are mostly written in C.