News for hackers. Stuff that matters.
Re:Git's list of banned C functions by moonchild on Thursday March 04, 2021 @06:28PM (#26350002)
It's because to get that to actually work you need dependent types. Which—it's not gonna happen.
Re:Git's list of banned C functions by kiwidrew on Thursday March 04, 2021 @06:38PM (#26350106)
But the caller to strnlen() has already provided both the (pointer to the) array and the length! Note that C99 does permit declaring a VLA in the body of the function:

  char *strndup(size_t n; const char *s[n], size_t n) {
    char buf[n];                /* alloc a temporary VLA */
    assert(sizeof(buf) == n);   /* yep! */
    assert(sizeof(s) == n);     /* nope, sizeof(s) == 1 */
  }
So there's absolutely no reason (other than being in violation of the C99 specification) for the compiler to refuse to let you make the assertion that sizeof(s) == n.

And given the prototype for this VLA-enhanced strndup(), a smart C compiler could catch errors like this:

  char * bugged_func() {
    char buf[20];
    /* do stuff with buf, e.g. snprintf() into it */
    return strndup(buf, 30);    /* error: 30 > sizeof(buf) */
  }
Since of course within a function the C type system is already tracking the size of an array -- so no additional type information is required, and certainly not dependent types!
Re:Git's list of banned C functions by moonchild on Thursday March 04, 2021 @10:52PM (#26352429)
With standard VLAs, you always have a guarantee of being able to access sizeof(buf) bytes from buf, for any variable buf. With your syntax, that guarantee would no longer hold, unless c had dependent types that could prove said guarantee.
Re:Git's list of banned C functions by kiwidrew on Thursday March 04, 2021 @11:49PM (#26352861)
Well, given that C is fundamentally about separate compilation and external linkage, most "guarantees" in the language are really just promises or contracts. As demonstrated in david2ndaccount's comment, standard C already handles VLA function arguments just fine (without any need for dependent types).

The only issue is that C99 insists that the first dimension of an array argument must decay to a pointer, discarding the associated type information of that array's dimension.

Re:Git's list of banned C functions by ufo on Thursday March 04, 2021 @08:55PM (#26351497)
We wouldn't need to go all the way to dependent types, which would guarantee at compile-time that array accesses are safe. Even if all the bounds checking happened at run-time it would still be tremendously helpful.
Re:Git's list of banned C functions by moonchild on Friday March 05, 2021 @02:35AM (#26353928)
Bounds checking can be done, and it doesn't need any special language features. Tcc does it, as do some of the sanitizers (present in gcc and clang).
Re:Git's list of banned C functions by ufo on Friday March 05, 2021 @07:56AM (#26356324)
Can you bounds check dynamically sized arrays? For example, a function that receives the size as a separate argument?

    double f(double *xs, int n){
        return xs[g()];
    }
Re:Git's list of banned C functions by kiwidrew on Friday March 05, 2021 @05:14PM (#26362863)
Yes. In my hypothetical world where the C compiler makes use of the VLA declaration in the function arguments, it would certainly be possible for the compiler to insert automatic bounds checking in this case:

  double f(xs, n)
    double xs[n];
    size_t n;
  {
    size_t _tmp0 = g();   /* temporary var created by compiler */
    assert(_tmp0 < n);    /* bounds check inserted by compiler */
    return xs[_tmp0];
  }
The key to making this possible is telling the compiler about the relationship between double* xs and size_t n; once the compiler has the knowledge that the type of xs is double [n] (array of double with first dimension n) it would be able to automatically insert dynamic bounds checks.
Re:Git's list of banned C functions by moonchild on Friday March 05, 2021 @05:44PM (#26363195)
> dynamically sized arrays

Yes. What you can't do is associate bounds information with some specific pointer to an array, but this will work, for instance:

  int *x = malloc(2 * sizeof(int));
  x[1]; //ok
  x[2]; //runtime error