For code that is critical to performance, C99's "flexible array at the end of a struct" is an useful tool. It basically allows you to attach a header at the beginning of some dynamically-allocated binary data of infinite length (yes, it can be implemented as a pointer at the end of the struct, but the extra latency of another pointer chasing can reduce performance). Before C99, the "size-1 hack" or "size-0 GCC extens…
Modernizing C arrays for greater memory safety: a case study in the Linux kernel
81–90 of 126 posts
Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel
#82For code that is critical to performance, C99's "flexible array at the end of a struct" is an useful tool. It basically allows you to attach a header at the beginning of some dynamically-allocated binary data of infinite length (yes, it can be implemented as a pointer at the end of the struct, but the extra latency of another pointer chasing can reduce performance). Before C99, the "size-1 hack" or "size-0 GCC extens…
No, C++ has nothing better.
https://gist.github.com/cozzyd/efda739301bb7eb3a4a63a145c93e...
Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel
#83Good article. If you're compiling C with MSVC then you can use SAL annotations [1] which serve the same purpose. [1] https://learn.microsoft.com/en-us/cpp/code-quality/annotatin...
Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel
#84> C is not just a fancy assembler any more I wish this trope would die. It really never was one.
Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel
#85> int flex[] __attribute__((__element_count__(items))); While what the article describes is clever, it is needlessly complex, and filled with various compiler switches and extensions. In contrast, here's a stupid simple approach: https://www.digitalmars.com/articles/C-biggest-mistake.html where bounds-checkable arrays are declared as: int a[..]; `a` consists of two fields, a `length` and a `pointer`. Indexing it mean…
Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel
#86Earlier quoted context omitted.
malloc() doesn't allocate arrays. It allocates blocks of memory. Hence sizeof doesn't work the same for malloc() objects as it does on arrays.
sizeof doesn't work the same for malloc() because the type of the returned value is a pointer, and the behavior of sizeof is dependent solely on the static type. For comparison, calloc() is specifically defined as "allocates space for an array of ... objects" in the Standard, but since return type is still void*, the caveat with sizeof still applies.
so what, an array has a size that sizeof can measure. what is returned from malloc is not an array and what sizeof measures is not reflective of the size of the allocation
Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel
#87Earlier quoted context omitted.
Flexible array members are commonly supported as an extension in C++ compilers, but the C++ standard itself does not permit them. And FWIW `extern "C"` doesn't drop a C++ compiler into a "C mode", it merely effects linkage (i.e. name mangling); all the code within the scope must still be valid, compiler-supported C++. Your example code compiles the same without the extern "C" declaration. And it compiles the same if…
Unrelated to the article but since you seem to know this stuff, do you know what happens when a function in an “extern C” block exposes C++ types (parameters or return types)? I assume it’s broken because it’d expect the actual C++ types to be passed in despite the lack of ABI stability, and only the linking / name mangling is affected (possibly calling conventions as well?) but I’m not actually sure.
Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel
#88Earlier quoted context omitted.
malloc() doesn't allocate arrays. It allocates blocks of memory. Hence sizeof doesn't work the same for malloc() objects as it does on arrays.
sizeof doesn't work the same for malloc() because the type of the returned value is a pointer, and the behavior of sizeof is dependent solely on the static type. For comparison, calloc() is specifically defined as "allocates space for an array of ... objects" in the Standard, but since return type is still void*, the caveat with sizeof still applies.
This works:
void vla_print(int n)
{
int foo[n];
printf("Got %zu bytes right there!\n", sizeof foo);
}
int main(void)
{
vla_print(47);
return 0;
}
This prints 188 [1].Even if you "hide" n from the compiler, i.e. make its value something that is only known at run-time (which is jumping through hoops, pretty sure the above is enough).
Also, it was jarring that the fine article kept referring to sizeof as sizeof(), a notation that C programmers typically use to identify function names. As everyone knows, sizeof is not a function. It's an operator. I really need to print up that t-shirt soon. Or maybe my first tattoo ... Hm.
Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel
#89Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel
#90Earlier quoted context omitted.
That's nice, but attributes let us easily retrofit existing C code such as the Linux kernel in a way that supports multiple compilers and compiler versions. Just extensions, not compiler switches. And they don't muck with the ABI which is a requirement for stable kernel driver interfaces. Also what you're proposing...would be an extension!
Starting with "That's nice" is extremely flippant and is an immediate turn off to any subsequent statement. A stronger opening to discredit the [..] proposal would be to take the closing quote "We've been doing that with D for over 20 years" and point out that storing the length of an array of a certain type is a specialization to arrays of dependent typing that has been around since Howard and de Bruijn extended lam…