And the answer to this is writing text-processing functions that you expose to the world, in C... skeptical face
And the answer to this is writing text-processing functions that you expose to the world, in C... skeptical face
Rust is a good solution, but it isn't trivial to learn, and might not suite all situations. I think it's great to have a C solution like this.
It isn't hard to build tools like Valgrind and AFL into your C workflow. I would take that over simply taking for granted that a higher-level language was secure just because it is interpreted. After all it's probably C under the hood anyway.
> When a TCP packet or UDP packet arrives with a particular destination port number, inetd launches the appropriate server program to handle the connection. For services that are not expected to run with high loads, this method uses memory more efficiently, since the specific servers run only when needed. Furthermore, no network code is required in the service-specific programs, as inetd hooks the sockets directly to stdin, stdout and stderr of the spawned process.
Just ask init or getty.
Init and getty are small, self-contained system demons that are part of the O/S rather than application servers inviting long-running, single address-space processes for business logic.
CGI is also the way the web used to work. Spawning processes has only gotten faster since then. The entire "process spawning doesn't scale to the modern web" argument is completely and totally bogus. Today, spawning a process in Linux is only 10-20 microseconds slower than creating a thread: http://www.bitsnbites.eu/benchmarking-os-primitives/
The performance problems are elsewhere.
The folks who started at a small scale in serverless but see traffic growing and kind of are in the middle space before jumping to dedicated servers have an entire art form of keeping their functions "hot" since both Lambda and AppEngine actually keep your functions hot loaded when once it's spun up for some time.
https://www.google.com.sg/search?q=serverless+warm+up&oq=ser...
If you're serving thousands of requests per second, you probably need a pretty beefy server anyway, regardless of the stack you're running. Forking makes good use of multiprocessor capabilities if nothing else.
Shell scripting is a handy tool but it is also slow so you wouldn't write hot paths in shell scripts. And for the same reasons you wouldn't write busy web servers in CGI. Both are fork() heavy.
Maybe another opportunity to mention Zig again as a possible good alternative in the learning curve front? (I learned about it when it appeared recently in the HN front page)
Let SQLite deal with it! The JSON1 extension is quite capable of parsing, extracting, sorting and filtering JSON data and by default it's enabled.
C still has some unique portability characteristics that are very hard to match in other languages. If your requirements lead you down this path, it can be done.
You rightly point out however that this isn’t a path one travels lightly. Maybe the flip side of all this is, “if you’re prepared to invest the kind of rigor into testing that SQLite has, then rock on.”
Isn't the learning curve of C pretty similar or even higher than rust's if you concider all the best practices you'll have to learn and understand and use? Imho in that regard rust pays off very well (and fast), because it's compiler _enforces_ most of these "best practices" to everyone.
What could possibly go wrong
Also what is the point of calling out on projects that are not using "cool" languages? You don't agree with the developer choice that is OK, probably that developer does not agree with your choice and has other priorities and if is an open source project probably he wants also to have fun while coding it.
The time and effort to secure a C program against malicious input is absolutely huge. It would be quicker to write a secure dsl that using raw C. Which brings us back to scripting languages that have that implemented already as a library you load to run your requests through.
Most people who write code in C are not that good at avoiding memory safety issues. The process is mostly to write some code, run it, then fix it until it doesn't crash immediately anymore.
Have you ever been the first person to run valgrind on a codebase? Lots of uninitialized reads and use-after-free issues will be flagged, because they don't normally crash the program and therefore go undetected without using an additional checker.
It can be fun to watch the error messages flow by, until you realize that now you have to file tickets for all of them. And some people won't even see the problem with those errors that don't crash the program, because potentially exploitable vulnerabilities are not as obviously bad as crashes.
Btw, I am not a C fan, in fact I think I have no favorite language, I use what I have to for the project
Why not just build the ecosystem to do that and still have it all be “C”?
Why not some fixes to the standard and update then old but useful code, and work on better compilers?
This is what’s been confusing me for a while
If you can write safe enough C for the core of an interpreted language, why not abstract that into tools and patterns that generate better, safer C and learn how to do that over the last 30 years
Instead of JS and dozens of flavors, Python, ruby, lua...
DRY right?
My suspicion is “vanity projects generate a sense of novelty that’s easier to sell.”
But if the OS and bulk of the stack are “C inside anyway” why the extra nonsense?
For example you could implement a string class in C++ using strlen, strdup etc. if you were feeling insane and it would probably be fine since you only use strdup once and then all the users of you class don't have to worry about getting it wrong.
If you write in C you have to use strdup every time you copy a string and there's no way you get it right 1000 times.
You got me thinking about ways one could get strdup wrong:
- input is not a string -> possible UB
- input is a string, but the character encoding wasn't what you thought -> possible UB
- input is a string, but it was the pointer-plus-length kind -> possible UB
- input is modified by another thread -> possible UB
- strdup called from within a signal handler -> possible UB
- failure to handle error return values -> possible UB
- failure to free the memory when it's no longer needed -> memory leak
- freed the memory more than once -> possible UB
- used the memory after freeing it -> possible UB
I've personally seen several of these in real-world code.
- forget to #include string.h, so strdup is implicitly declared, so its return type is int, which implicitly converts to char*, so everything still compiles -> possible UB
You'd be surprised how far large static buffers and snprintf will get you. Easy to deal with, no leaks, valgrind is happy...
Uh... am I missing the joke? The C programs don't "call binary files", the C programs become the binary files through compilation.
Yes, yes you are.
Seasoned developers would use a tool more fit for the job, like Java, Python or even PHP. Seasoned hipsters would use Node, Clojure or Elixir.