Writing a SQLite clone from scratch in C (2017)
cstack.github.io
cstack.github.io
Writing a SQLite clone from scratch in C - https://news.ycombinator.com/item?id=15168467 - Sept 2017 (146 comments)
https://sqlite.org/src/doc/trunk/README.md
Wouldn’t this be more worthwhile to write in [insert favorite modern language]?
I get it is to learn. C is a much more difficult language in which to work. A higher level language would allow one to better abstract the concepts and iterate faster
sqlite isn’t your average C development, it’s got more lines of code written for tests than it does for actual code. Given the extensive tests written against sqlite, rewriting it from scratch in any language, even a more modern/safer one, would ultimately end up with a buggier program.
The only practical reason for rewriting sqlite is as a learning exercise. Which is what I believe the point behind this submitted project.
And yet, people keep finding use-after-free bugs in sqlite3 that allow attackers to escalate the memory corruption into arbitrary code execution... bugs that have affected major projects, including iCloud and Chrome; here are a handful: there are lots more even from just the past year :/.
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-1363...
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-9327
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-1387...
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-2022...
The reality is that programming in C is just such a horrible thing--making it so easy to accidentally make mistakes that don't merely lead to "your database is corrupted" but escalate all the way to "the attacker is now running their own code on your computer"--that we simply need to stop doing it (preferably 15 years ago: there is really no excuse to not be at least using the C++ compiler to compile all of our C to get at minimum templates, deconstructors, and better type checks), get everyone else to stop doing it, and then actively go through and scour the ecosystem to remove it all, as every line of C running on your computer is a liability.
The underlying thing to appreciate here is that the goal is to make these kinds of mistakes not only much harder but impossible: I simply don't need tests to prove a Rust program (which I say as an example: I am not one of those Rust advocates that you see... I actually hate the language for not having exceptions and I even dislike some of the key people involved in both Rust and Cargo, and so my noting the dominating superiority of Rust to C should come as a pretty strong/sobering commentary; it is unfortunate as I honestly think they are making decisions that have been holding back widespread deployment of Rust, and yet they think they are doing well... hopefully they will claw their way out of the pit soon: at least some progress was finally made recently?) is at least better than sqlite3 apparently is in practice :(.
But nobody uses my projects anyways :-/
edit: oh shit, saurik. I respect you work a lot. Still love my insecure "bad" language, though.
Would you have been able to make as big of an impact on securing our digital freedoms without the faults of memory and pointer errors, though? I almost feel like you owe a debt of gratitude to C's faults. I'm half kidding. But only half
I would _love_ to use Rust on embedded and older hardware on which LLVM simply isn't available.
* The community is tiny. A rounding error compared to Go, Rust, etc.
* The core team of contributors is even smaller. You could comfortably have an intimate dinner party with all of them. If they lose interest, the language would likely die.
* The library distribution story wasn't great last I checked.
Caveat: I haven't used Nim for more than a year now. Maybe all these issues are no longer relevant. I really want it to succeed, but who knows what the future holds.
I'm a C++ developer and, for now, sticking to it on larger projects since I love the thinking behind the C++ evolution over the decades. Rust still feels like a hype/moving target. The big selling point appears to be memory safety, but that's just a detail and not enough to justify a switch. I'm keeping an eye on how Rust and Nim will evolve in the next 5–10 years, but for now, C++, Erlang, and Lisp are my go-to choices for projects which should last the upcoming decades.
The safety is limited to data races, not concurrency or parallelism problems.
I don't understand why I see so many requests for LLVM-based languages to change around their backend or IR, that seems to be a huge amount of work for comparatively little benefit. The correct thing to do there is to just add support for those to LLVM.
GCC, and various proprietary vendor compilers, are often the only C compilers available on some hardware; and llvm doesn't have a mature, stable and supported backend for them, either.
So I take the liberty of asking you a little naughty question :-)
What is your take on "Google C++ Style Guide" advice on the use of C++ Exceptions?
https://google.github.io/styleguide/cppguide.html
"We do not use C++ exceptions"
https://google.github.io/styleguide/cppguide.html#Exceptions
Also as stated in the guidelines, some of the reasons are the intention of integrating the open source projects with an internal Google C++ code base that does not use exceptions. So integration would be difficult.
However, the question is how come such a large code base using C++ without Exceptions come to be. Specially on a company with so many employees chairs of C++ committees :-)
Just to make it clear, I prefer the C and Rust model around error handling. I will also concede that, for GUI applications and when on a coherent code base, you probably want C++ Exceptions.
Each possible contructor now needs a matching static method.
Can't put things in standard containers unless you rewrite all copy / move contructors (and you didn't forget to mark your move constructor noexcept, did you ?).
What happens when you have classes with more than 3 members ? Constructors with 12 arguments ? That's unambiguously terrible, and does not even save you from exceptions coming from C++ itself.
If 79% of surveyed C++ projects can use exceptions (https://www.jetbrains.com/lp/devecosystem-2020/cpp/), likely so can you.
Googles strategy does come with some significant drawbacks, such as requiring init() functions everywhere (what happens if you forget one?), and needing to test error codes after every function call (easy to forget). It also locks them out of useful features like overloaded operators for the most part (since those have no error return option other than exceptions). In general, the 'happy path' becomes cluttered with error handling everywhere, leading to programs that dedicate more lines to error handling than actual processing.
Also, it says "WE do not use exceptions", not "NOBODY should use exceptions". It's a statement about the situation at Google, based on their unique circumstances, not a general guideline.
Rust it self also has it's fare share of free after use etc bugs. Please check: https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=Rust
I'm personally thankful that we have SQLite which is written in C - It's efficient, tiny and severe bugs are relatively rare.
As the original article quotes: “What I cannot create, I do not understand.”
All of those are secondary if Rust is able to reliably produce memory safe software.
> Rust it self also has it's fare share of free after use etc bugs. Please check: https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=Rust
A relatively quick skim through those issues seems to indicate that the unsafe keyword really is unsafe. I wonder if SQLite can be written without it Rust?
Nothing in Rust requires you to use Cargo. It's really convenient to have a good build system like Cargo—but if you like C style of manually invoking the compiler, rustc can do that too.
Rust is no worse by bundling Cargo. It strictly dominates the alternative, which would be to just ship rustc and allow the user to pick whatever build system they like. You still can pick your favorite build system; but if you don't have a particularly strong preference, Cargo is a very good default.
Hate to break it to you, but it is not "impossible" to have CVEs in Rust [1].
> people keep finding use-after-free bugs in sqlite3
is true, but
> that allow attackers to escalate the memory corruption into arbitrary code execution... bugs that have affected major projects, including iCloud and Chrome; here are a handful: there are lots more even from just the past year :/
is just incorrect. I'd strongly encourage you to read https://www.sqlite.org/cves.html
Application dev: "yes it's an SQL injection, but it's fine because this database is only used for unimportant data"
The thing is that the real attacks usually come by chaining a bunch of vulnerabilities together.
Before today, I didn’t know that CVEs aren’t vetted and can be easily spammed for self-gain[1]. I should be more skeptical the next time I see scores of links to CVEs with 0 comments and bare-bones descriptions.
It’d be a cool exercise to rewrite in a language that easily targets the C ABI and can thus use the same suite of tests for verification. I suspect Zig would be ideal for this, as would maybe Rust.
Edit: looks like the tests are in tcl not C so nevermind!
Rewrite in C if you want to learn the underlying data structures, algorithms, and real-world computer science of the field. Database design is field with exceptional depth and many lessons to be learned.
Only if they want to learn how to write an SQLite clone.
But maybe their goal is to learn C. In that case the SQLite clone is a very good project because there's already huge test suite to test the new implementation.