Earlier quoted context omitted.
Frama-C as a bare minimum is a pipe dream. It's a nice thought, don't get me wrong, but it's hard enough to convince people to add `-fsanitize=...` to their compiler flags. An entire separate static analysis tool with its own learning curve (and its own set of idiosyncrasies) doesn't really qualify for "bare minimum" IMO.
Thankfully the ongoing cybersecurity laws will change that mindset.
Neverflow: C macros that guard against buffer overflows
71–80 of 150 posts
Re: Neverflow: C macros that guard against buffer overflows
#72The problem with C and buffer overflows isn't that you can't guard against them, or that there is no existing, reusable code to do so — it's that none of this functionality is standardized. Adding another one to the existing 41383 ways of doing this is in fact the exact opposite of what's needed. Ideally C needs one way of doing this, and that would be described in the standard. But that's not how C "rolls", and we'l…
C never has just one way to do something. myArr[5] == 5[myArr] == (insert pointer arithmetic that I won't write here without a compiler check). I think that part of C's beauty is that it gives you freedom. Freedom to shoot yourself in the foot, freedom to write hyper efficient code, and freedom to choose another tool. I agree that this will never be implemented as a standard, but I think that's a good thing. Higher l…
Re: Neverflow: C macros that guard against buffer overflows
#73Earlier quoted context omitted.
Multiplying array length by sizeof(element type) can overflow. Of course, you can write your own malloc_array() that uses __builtin_mul_overflow() and doesn't come with calloc's drawback (the cost of zeroing the allocated memory).
OpenBSD's libc has reallocarray for this, which is realloc with the same bounds checking as calloc, but if the first parameter is NULL, it's just calloc without the zeroing. And I believe you'll find it in glibc too these day? Or if not, there's always libbsd, which has lots of handy stuff anyways.
Re: Neverflow: C macros that guard against buffer overflows
#74Earlier quoted context omitted.
And yet, even with that, Yann Collet credits Google's use of C++ for the compression library as a critical mistake that allowed him, an unknown, to gain traction with his own compression methods. Google later rewrote their library in C: https://overcast.fm/+LfVPHmBTo Even if the tool chain exists, it must be adopted, unless you can rely on binaries being available for your end users, which will never be the case for…
Unless we are talking about an obscure platform or some PIC CPU, a C++ compiler is available on the same box as the C compiler. Second, extern "C" exists. Third, in what concerns clang and MSVC, the C library is actually implemented in C++ with extern "C".
Even if it's the "same" toolchain for compiling C++ as it is C, adding the complexity of an additional language to the build process, and the extra versioning headaches that C++ adds over C, is enough to kill library adoption.
As I said originally, providing bindings is not the challenge, it's all the other stuff.
Re: Neverflow: C macros that guard against buffer overflows
#75Interesting idea, although given the demotion into optional feature in C11, it isn't necessarly portable. Also doesn't cover all the string and memory buffer manipulations. SAL and Frama-C are the bare minimum for security in C code.
Re: Neverflow: C macros that guard against buffer overflows
#76Earlier quoted context omitted.
But this isn't something the C++ language provides, which is hilarious. C++ keeps C's crap array type as its native array type. You need to reach into the C++ standard library to get this awkward library type, std::array and then finally you get an array type that remembers how big it is and has some basic features like swap.
True, but it also adds lot of features that help to easily migrate to saner features without rewriting the world and throw away 30 years of tooling. Microsoft security team is on the record that just because they are adopting Rust, they won't shy away from C++.
Example, Rust 1.0 had std::mem::uninitialized::() which gives a T but it's obviously uninitialized. It's marked "unsafe" of course, but is that enough? Turns out they later realised that no, it's strictly never OK to do this, so the unsafe label was insufficiently cautious. Today std::mem::uninitialized is deprecated, Rust never removes stuff from the standard library, but you should not use this library call.
The type MaybeUninit is the fix. Since MaybeUninit might not be initialized, it's OK if it's not initialized, and since it might be T, it's OK for it to occupy the same amount of space as T. So, then we can initialize this memory, and tell the compiler it's initialized now, it's a T not a MaybeUninit.
Can you guess how that works? It's pretty clever, and C++ could do almost the same trick, but it never has and my guess is it never will. If you don't know and are wondering, check that type definition carefully - MaybeUninit is a union
For contrast, in his safety talk Bjarne Stroustrup just says as if it's obviously true, that it's safe to have uninitialized char arrays in C++. And his rationale sounds exactly like how std::mem::uninitialized happened - any possible value of a byte is a valid byte, so that's good enough, right? Nope, ask compiler engineers, there were plenty in the room when Bjarne said that, but he didn't ask them.
Re: Neverflow: C macros that guard against buffer overflows
#77Re: Neverflow: C macros that guard against buffer overflows
#78Even without array bounds checking, a bit of discipline and smart conventions will go a long way of reducing errors: 1. Define a macro function for retrieving the length of an array: #define LEN(arr) (sizeof (arr) / sizeof (arr)[0]) 2. Don't introduce macro constants for array lengths; hard code the length in the declaration and use LEN to retrieve it. Example: int a[100]; ... for (i = 0; i 3. Define a macro function…
The issue with 1 is that it only works until you pass an array into a function by pointer, then the macro no longer works. In my experience it's most likely that a function will write past the bounds of a buffer that's been passed as an argument. In that case, make sure the size of array is always included as an argument as you said in 4.
Re: Neverflow: C macros that guard against buffer overflows
#79Even without array bounds checking, a bit of discipline and smart conventions will go a long way of reducing errors: 1. Define a macro function for retrieving the length of an array: #define LEN(arr) (sizeof (arr) / sizeof (arr)[0]) 2. Don't introduce macro constants for array lengths; hard code the length in the declaration and use LEN to retrieve it. Example: int a[100]; ... for (i = 0; i 3. Define a macro function…
You could extend point 1. by making a convention of always declaring pointers to arrays like so: int (*data)[datalen]; This requires you to dereference it once to get an array, then dereference it a second time to get a value. The advantage is that the array value can be used the same as an normal array on the stack, including passing it to the array length macro you describe.
Re: Neverflow: C macros that guard against buffer overflows
#80Even without array bounds checking, a bit of discipline and smart conventions will go a long way of reducing errors: 1. Define a macro function for retrieving the length of an array: #define LEN(arr) (sizeof (arr) / sizeof (arr)[0]) 2. Don't introduce macro constants for array lengths; hard code the length in the declaration and use LEN to retrieve it. Example: int a[100]; ... for (i = 0; i 3. Define a macro function…