I wish this trope would die. It really never was one.
Modernizing C arrays for greater memory safety: a case study in the Linux kernel
21–30 of 126 posts
Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel
#22Earlier quoted context omitted.
According to the C spec, zero length arrays are explicitly illegal. > Zero-length array declarations are not allowed, even though some compilers offer them as extensions (typically as a pre-C99 implementation of flexible array members). However, as they say, gcc (and therefore clang) have an extension that allows it. So does MSVC but it works slightly differently.
you should be specific about which C spec you are referring to, you talk about "the C spec" and then you mention the "pre-C99 implementation". Maybe you mean they've always been illegal in every version, but it would be more clear.
It's saying that C99 implemented flexible array members but before then some compilers introduced their own (nonstandard) implementation of flexible array members, using the (not allowed) zero sized array notation.
Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel
#23Meanwhile, unlike C99, this construction is not allowed by any version of the C++ standards, any such use would be a non-standard extension, I think this is unfortunate. I only write C, I wonder if any C++ guru out there can answer this question: does modern C++ have a better solution to implement the same thing?
[1] https://devblogs.microsoft.com/oldnewthing/20040826-00/?p=38...
Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel
#24Earlier quoted context omitted.
Hang on, let me think this through... If malloc(0) gets called as first malloc in the program the system break does not need to be moved, as there is always 0 bytes space available... but malloc does like to move sysbreak by a large amount at a time to reduce the need for repeated calls... I'm guessing malloc(0) does not move sysbreak and simply returns a pointer to the bottom of the heap?
Implementation defined. I've heard of returning null (under the case that your free() implementation allows nulls to be passed in) or returning a pointer to a zero length object on the heap like you're suggesting. Really just about the only requirement is that the pointer can subsequently be given to free() since dereferencing the pointer is UB.
Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel
#25Call me crazy, but zero length arrays are a great abstraction, when you working with implicit data-structures. Not safe, but elegant and performant. Many codebases could be 2x faster if their designers embraced that concept.
I'd say it's also not more dangerous (or equally dangerous, depending on your camp) than a pointer from malloc().
Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel
#26Earlier quoted context omitted.
both c and c++ have the concept of zero-length arrays, if you malloc them - int * a = malloc(0); is ok
Hang on, let me think this through... If malloc(0) gets called as first malloc in the program the system break does not need to be moved, as there is always 0 bytes space available... but malloc does like to move sysbreak by a large amount at a time to reduce the need for repeated calls... I'm guessing malloc(0) does not move sysbreak and simply returns a pointer to the bottom of the heap?
Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel
#27Earlier quoted context omitted.
both c and c++ have the concept of zero-length arrays, if you malloc them - int * a = malloc(0); is ok
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.
Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel
#28Earlier quoted context omitted.
you should be specific about which C spec you are referring to, you talk about "the C spec" and then you mention the "pre-C99 implementation". Maybe you mean they've always been illegal in every version, but it would be more clear.
The bit after `>` is a quote, not my words. See https://en.cppreference.com/w/c/language/array for the source It's saying that C99 implemented flexible array members but before then some compilers introduced their own (nonstandard) implementation of flexible array members, using the (not allowed) zero sized array notation.
1. Pre-C99, no flexible array was allowed.
2. Gradually, people started using the "size-1 array at the end of a sturct but write beyond" hack as flexible array.
3. As an attempt to do the hack in a more ordered manner, some compilers, including GCC, started officially supporting the non-standard "size-0" array extension.
4. C99 added flexible array with indefinite length (array[]), while prohibiting both the undefined-behavior "array[1]" and the non-standard extentios "array[0]".
So when people say "size-0" array, it could mean either of these three things, and it does get a bit confusing. But fundamentally the idea was the same, all of the three techniques are used to achieve the same practical effect.
Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel
#29For 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…
MyStructA a; MyStructB b;
a = malloc((sizeof a) + (sizeof b)); b = (MyStructB *)&a[1];
You need to make sure that the second struct doesn't have stricter alignment requirements than the one preceding it, but using this technique you can stack any number of structures or arrays of structures in one allocation.
(I would generally not recommend this coding style unless you have very specific requirements of memory usage)
Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel
#30For 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…
I'm no guru, but I know from experience you can do it in C++:
{0}[calvin ~] cat test.cpp
#include
#include
struct foo {
int len;
int v[];
};
int main(void) {
auto p = std::unique_ptr(reinterpret_cast(
malloc(sizeof(struct foo) + sizeof(int) * 2)));
p->v[1] = 99;
std::cerr v[1]
EDIT: Remove unnecessary extern block, as pointed out by wahern in the replies.