Live data from Hacker News

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

people.kernel.org

111–120 of 126 posts

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

#111
post #107

Earlier quoted context omitted.

Wow, such a great annotation language. Wish it were in GCC as well.

I keep hoping that the C and C++ committees will get together and standardize some of that in the form of C23/C++11 style attributes. But that is sadly likely a naïve hope.

Microsoft hopes to be able to map SAL into C++ contracts if they ever be part of the standard, as that was their initial goal when they started implementing lifetimes support in VC++.

As for C folks, I don't have any hopes of them every going down that route.

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

#112
post #88
post #27

Earlier quoted context omitted.

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.

That is not true, as long as VLA:s are in the language spec for the version you're using. 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 enou…

In your example, sizeof works because the type of foo is int[n], so I'm not sure what point you're making. It's still true that the way sizeof works depends solely on the static type of the expression that it is applied to - if it's an array, you get the actual size, including the necessary dynamic computation if it's a VLA, and if it's a pointer, you get the size of a pointer even if it points to an array.

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

#113
post #54
post #14

Earlier quoted context omitted.

The previous paragraph says > ...due to yet more historical situations (e.g. struct sockaddr, which has a fixed-size trailing array that is not supposed to actually be treated as fixed-size), GCC and Clang actually treat all trailing arrays as flexible arrays. But I don't know, that doesn't seem to match the result I am getting with clang 13.1.6. It does seem to respect the array size declared in the struct, not trea…

It treats them as flexible arrays in the sense that it doesn't assume indexing beyond the declared size is undefined behavior, which would have implications for code elision and other optimizations.

Thanks for the explanation! That makes sense.

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

#114

Earlier quoted context omitted.

> When `p` is a parameter in a function, the function cannot know that it can create a slice of up to 10 elements (I assume that the `p[0 .. 10]` creates an array indexed from 0 - 9). That's right, when a bounds checked array is converted to a pointer, the bounds does not go with it. Presumably, the function receiving the p has some way to determine the length (such as strlen, or via another parameter) from which the…

Thank you. I'm always pleased when I get a reply from WalterBright[1]. Some follow up questions: 1. If you could redesign the above mechanism, would you do anything differently? 2. In my Own Toy Language[2], I've toyed with the idea making all native arrays fat objects as it seems the best way to ensure that the compiler, at any point, as the ability to bounds check if necessary. All that goes out the window when you…

> If you could redesign the above mechanism, would you do anything differently?

Nope. It was a home run.

> All that goes out the window when you want to do FFI to some C function.

And there you go! What D does, though, is bounds check the conversion of an array to a pointer, and then (in code marked @safe) not allow arithmetic on the pointer.

Additionally, D introduced the `ref` parameter which eliminates nearly all use cases of needing to pass by pointer to a function.

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

#115
post #104

Earlier quoted context omitted.

Objective-C and C++ never had any issues having additionaly types for arrays and strings, C could do the same, but WG14 has clearly decided they don't want to do that.

Yes, so why WG14 or whoever in charge has not accepted that one simple addition responsible for so many errors ? It's not like it would affect performance. For strings, it would even make it better, simply moving the lenght around with the compiler's help.

It turns out that bounds checked arrays are ideal for strings. One no longer has to run strlen, which is inherently slow and cache-unfriendly. One can also slice a substring without needing to allocate and copy.

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

#116
post #94

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

The problem is that this would have one specific ABI, which probably wouldn't match many existing structs with a flexible array member at the end. Could potentially be used for new code (while requiring every user to upgrade the standard they compile with), but has the risk of not usable for modernizing old code.

You're right that bounds checked arrays do nothing at all for existing code. But they can be added incrementally to an existing code base, as a normal part of working on the code.

In that aspect it's like when prototypes were added to C. Nothing changed for existing code, but prototypes are so advantageous people would retrofit existing code incrementally when doing routine maintenance.

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

#117

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

We have bounds-checkable arrays already since C99:

int (p)[n] = malloc(sizeof p); (*p)[i] = 1; // run-time bounds check

https://godbolt.org/z/vb8dqx1od

But yes, having a type that included the bound makes sense. But I do not think using array syntax for pointers as in your proposal makes any sense.

Dennis Ritchie got it right: https://www.bell-labs.com/usr/dmr/www/vararray.pdf

Ritchie DM. Variable-size arrays in C. The Journal of C Language Translation 1990;2:81-86.

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

#119
post #24

Earlier quoted context omitted.

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.

free(NULL) is required to be a no-op by the ISO C standard.

Oh, good call. I had that backwards in my memory. The issue is when you give out non NULL pointers to zero sized objects, you have to make sure to give out unique pointer bit patterns at least versus nonzero sized objects so that the matching calls to free don't stomp on eachother.

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

#120
post #117

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

We have bounds-checkable arrays already since C99: int ( p)[n] = malloc(sizeof p); (*p)[i] = 1; // run-time bounds check https://godbolt.org/z/vb8dqx1od But yes, having a type that included the bound makes sense. But I do not think using array syntax for pointers as in your proposal makes any sense. Dennis Ritchie got it right: https://www.bell-labs.com/usr/dmr/www/vararray.pdf Ritchie DM. Variable-size arrays in C.…

> We have bounds-checkable arrays already since C99

    void foo(int n, int (*p)[n]) {
      (*p)[n] = 1;
    }
which has failed to catch on, because it still stores the pointer and the length as two separately handled objects.

> Dennis Ritchie got it right

"This paper proposes to extend C by allowing pointers to adjustable arrays and arranging that the pointers contain the array bounds necessary to do subscript calculations and compute sizes."

It appears to be phat pointers.

Post reply on HN