Live data from Hacker News

Modernizing C arrays for greater memory safety: a case study in the Linux kernel

people.kernel.org

41–50 of 126 posts

Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel

#41

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…

You can do it without trailing arrays, by stacking the structures after one and other: 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…

This is pretty similar to:

  MyStructA {
    ...
    MyStructB b[];
  };

  MyStructA* a = malloc(sizeof(MyStructA) + sizeof(MyStructB));
  b = &a->b[0];
(Except, of course, that the syntax for locating 'b' is nicer this way, because you don't have to explicitly address the memory after 'a' and cast it to 'MyStructB'.)

Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel

#42
post #21

> C is not just a fancy assembler any more I wish this trope would die. It really never was one.

Optimising C compilers maybe not, but you absolutely can naïvely translate C into assembler - at least for stack based machines. I do think ‘fancy assembler’ is a fitting description in that case.

Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel

#43

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…

> Does modern C++ have a better solution to implement the same thing? 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…

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 main is also placed within the extern "C" scope; but not the headers, as C++ constructs like templates cannot have C linkage.

Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel

#44
post #13

TL;DR is the introduction of C99 VLAs, not Pascal-style arrays, though a potential attribute could be added so we could do int some_int; int some_array[] __attribute__((__element_count__(some_int))); to store the size of some_array in some_int .

You could take this idea further by adding an "array_ref" type to the C standard where it is a length and elements. In practice this would be broken into separate parameters when passed to a function so existing functions could be fixed post-hoc using attributes - similar to printf formatting attributes. Then passing an array_ref to a function that expects a pointer/length would let the compiler automatically translate. Then you could define the rules for how an array_ref decays to a pointer and how to make one out of a pointer and length.

In other words the C standard could make bounds-checking of arrays possible with a good interop story if the standards committee believed it was worth doing. Compilers would have a flag to enable or disable the runtime checks based on safety/perf tradeoffs. Libraries would slowly add the relevant annotations. Eventually most code would have the option of having all array accesses bounds checked.

Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel

#45
post #4

Call 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.

both c and c++ have the concept of zero-length arrays, if you malloc them - int * a = malloc(0); is ok

malloc(0) return value is undefined by POSIX and can return NULL (IIRC it did on NetBSD).

Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel

#46
post #32
post #9

Earlier quoted context omitted.

According to the article, it's better to use the new flexible array syntax (int arr[]) instead of the old zero-length syntax (int arr[0]), because that allows the compiler emit better warning messages.

how would compiler confusion manifest between [] and [0] if it wanted to emit warning messages?

Technically, [0] is not allowed by the standard. The real issue is [] vs [1].

Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel

#47
post #13

TL;DR is the introduction of C99 VLAs, not Pascal-style arrays, though a potential attribute could be added so we could do int some_int; int some_array[] __attribute__((__element_count__(some_int))); to store the size of some_array in some_int .

Since clang will never support VLAIS, your proposition is a non-starter.

Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel

#48

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…

No, C++ has nothing better.

Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel

#49
post #5
post #4

Earlier quoted context omitted.

both c and c++ have the concept of zero-length arrays, if you malloc them - int * a = malloc(0); is ok

I think the parent is talking about the c pattern of having the last member of a struct be a zero length array, which is actually a dynamically sized array that the struct is only the header to (ostensibly with another field of the struct specifying the length of the array). It's fallen a bit out of favor, but it is a handy way to commingle the header and array with one allocation/pointer. And interestingly COBOL han…

In cobol it wasn’t dynamic, or infinite. The syntax of the array/table declaration includes a maximum and it would allocate the entire array statically up to the max.

Re: Modernizing C arrays for greater memory safety: a case study in the Linux kernel

#50
post #40
post #13

TL;DR is the introduction of C99 VLAs, not Pascal-style arrays, though a potential attribute could be added so we could do int some_int; int some_array[] __attribute__((__element_count__(some_int))); to store the size of some_array in some_int .

Sibling already pointed out this article is not talking about VLAs, but I do like your flexible-array attribute extension proposal.

The proposal is almost exactly the same as the one in the article (near the end).
Post reply on HN