4 ms·
The core of C is pointer arithmetic; This creates a fundamentally unsafe environment. You can't even do anything in C without some asm (syscall wrappers) becau
by oliverkwebb 2y ago
The core of C is pointer arithmetic; This creates a fundamentally unsafe environment.
You can't even do anything in C without some asm (syscall wrappers) because C was meant to boil down and streamline PDP-11 assembly (Your computer is not a fast PDP-11) to a set of consistent principles. The consequence of this is that the
core of the language is pointers and pointer arithmetic, and raw unabstracted pointers are fundamentally unsafe to work with.
Using the rust type system I can essentially confirm code is bug and edge-case free with exhaustive
matching and unit testing (C's lack of tooling blessed the world with autoconf and cmake btw). Not to mention rusts ability to abstract away necessary boilerplate gives
me more time to think about my code instead of pointer arithmetic and allocation heuristics.
The "cure" for C is a language that abstracts away raw pointers and memory allocation.
- oguz-ismail 2y ago> You can't even do anything in C without some asm (syscall wrappers) Which language can do anything without some asm and support as many platforms as C?
- oliverkwebb 2y ago> Which language can do anything without some asm and support as many platforms as C? I wouldn't be surprised if someone figured out how to do the interrupts and register control necessary to invoke syscalls with pure LISP/Scheme/CL :P P.S. anything that compiles with LLVM and has an ingrained way to do print() that doesn't invoke libc, although there's a blurry line here between "pure asm"/"compiles to asm" that involves trusting-trust-style bootstrapping of features into the compiler
- oguz-ismail 2y agoYou don't know what you're talking about
- nolist_policy 2y ago> > Which language can do anything without some asm and support as many platforms as C? > I wouldn't be surprised if someone figured out how to do the interrupts and register control necessary to invoke syscalls with pure LISP/Scheme/CL :P Haha > P.S. anything that compiles with LLVM and has an ingrained way to do print() that doesn't invoke libc, although there's a blurry line here between "pure asm"/"compiles to asm" that involves trusting-trust-style bootstrapping of features into the compiler Actually LLVM IR has no concept of syscalls, you have to use inline assembly inside your IR to issue syscalls.
- kazinator 2y agoWhat haha; we had that decades ago: systems programmed in Lisp from the bare metal. Here is what assembly code looks like in (ccl) Clozure Common Lisp: https://github.com/Clozure/ccl/blob/master/level-0/X86/x86-hash.lisp https://github.com/Clozure/ccl/blob/master/level-0/X86/x86-h... ARM version of same file: https://github.com/Clozure/ccl/blob/master/level-0/ARM/arm-hash.lisp https://github.com/Clozure/ccl/blob/master/level-0/ARM/arm-h...
- mjburgess 2y agoYou can write every program you want to without pointer arithmetic. If you mean that a dereference of a memory location involves the compiler emitting pointer arithmetic instructions -- that's true of all languages. If you want your language to completely disguise the machine from you, and "abstract away" memory allocation, you're going to pay a high complexity cost to do so. If you have never run C in a debugger, with the massive amount of highly sophisticated tooling available to C debuggers, then you're operating from a profoundly mistaken starting point for evaluating the viability of C for modern safe sofware development. C debuggers and tooling are vastly more powerful than Rust's static type system, and catch a much wider array of memory problems (, and bugs) than the Rust compiler can catch. Static verification is far more limited than the dynamic verification a sophisticated debugger can perform. People's undergrad C course is a terrible basis on which to evaluate what C is today. The reason C is associated with a lack of security is that almost all software is written in C, written in a time when either the internet didnt exist or didnt imply an adversarial local environment. Running a network cable through every facet of our O/S and software breaks many assumptions about the entire history of programming -- which C predominated in. This is a very poor basis on which to generalize the capabilities of a well-specified C programming environment (which today, is much more powerful than Rust's compiler).
- mschuster91 2y ago> People's undergrad C course is a terrible basis on which to evaluate what C is today. The reason C is associated with a lack of security is that almost all software is written in C, written in a time when either the internet didnt exist or didnt imply an adversarial local environment. The problem is - undergrad C is about the lowest common denominator that all tooling understands and that all people understand. Of course you're probably not going to have to go as low as C89 like sqlite or, until 2022, the Linux kernel [1], but still, the long support cycles of many distributions make it challenging to move standards upgrades forward. [1] https://www.zdnet.com/article/linus-torvalds-prepares-to-move-the-linux-kernel-to-modern-c/ https://www.zdnet.com/article/linus-torvalds-prepares-to-mov...
- LegionMammal978 2y ago> C debuggers and tooling are vastly more powerful than Rust's static type system, and catch a much wider array of memory problems (, and bugs) than the Rust compiler can catch. Static verification is far more limited than the dynamic verification a sophisticated debugger can perform. Is there any dynamic verifier that fully validates all acesses w.r.t. the object trees specified by the C standard? Tools like ASan and UBSan won't detect a write to one field running into another field, only a write overrunning the complete object. (Compiler-level hardening might catch that to some extent, but it's limited to TU boundaries.) Not to mention things like 'misuse of restrict pointers' that I've never seen any verifiers for, except for special cases like overlapping memcpy() buffers. Meanwhile, Rust does have its own dynamic verifier, called Miri [0], which checks just about every language-level rule at runtime. The main drawbacks are that it's slow and doesn't support calling arbitrary C functions, but it would be hard to get that to work short of the Valgrind route of emulating the whole process on an instruction level. [0] https://github.com/rust-lang/miri https://github.com/rust-lang/miri