Live data from Hacker News

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

people.kernel.org

31–40 of 126 posts

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

#31
post #21

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

In what sense was C never a fancy assembler?

I am not an expert on C nor assembly and would be curious if you could expand on this. The statement makes sense to me because my impression is that most of what happens in C code gets translated fairly straightforwardly to machine code, with the compiler taking care of bridging differences in the instruction sets of targeted architectures. I guess the reason this is simplistic is the inlining and loop unrolling done by an optimizing compiler. Is this what you mean?

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

#32
post #9
post #5

Earlier quoted context omitted.

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…

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?

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

#34
post #15
post #7

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

In reality, who cares of what the C spec says? Unless you have to port code on different compilers (which is very unlikely, unless you are building a library meant to be shared with different projects) you only care about the fact that the code works correctly with the compiler you choose to use.

I don't get all the programmers that scandalize if you use GNU extensions, they are fine, and mostly useful, so if you are using GCC to program I don't see why not use -std=gnu11 instead of -std=c11... who cares if the program is not compliant?

Even if you want to be compliant to share code, the C standard is you last problem, the thing is that you probably use a ton of libraries and header files specific to that implementation (such as POSIX or even worse Linux-specific stuff), so your code is 99% not portable anyway without rewriting most of it.

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

#36

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…

Yes, you can do this in C++, but keep in mind that implicitly generated copy/move constructors don't understand this and will not copy the full object. This can produce surprising memory corruption that can be difficult to debug. So you should be sure to either explicitly mark the struct not copy/movable, or implement smarter copy/move operators.

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

#37
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…

> And interestingly COBOL handled this in a cleaner way

That is the least reassuring sentence I have read on HN in a while!

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

#38
post #12
post #8

Earlier 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?

malloc is a user level library function - c/c++ implementers can do what they like with it assume the downvote was from someone that malloc is a system call

I downvoted for the assumption that sbrk is involved in any way. It's an implementation detail of (some) historical malloc implementations, not some inherent aspect of all implementations. The entire thought experiment is faulty.

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

#39
post #27

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

Well, sure, but the reason for that is that C's type system simply cannot represent functions returning arrays with known size. This is a weakness of the type system. Arrays degrade to a pointer type, lacking array length, as soon as you pass them between functions.

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

#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.
Post reply on HN