Comment by o11c

Comment by o11c a day ago

17 replies

`_t` should not be used for custom types since it's reserved for future standard types (and/or types declared in a header you might include someday). This does cause real-world problems (`key_t` anyone?).

Gratuitous allocations are gratuitous.

The whole "prevent double free" claim is completely bogus. Setting a variable to `NULL` only works for cases where there is one, obvious, owner, which is not the circumstance under which double free is prone to happening in the first place. Actually preventing double free requires determining ownership of every object, and C sucks at that.

flohofwoe a day ago

> `_t` should not be used for custom types since it's reserved for future standard types (and/or types declared in a header you might include someday).

That old thing again...

The _t postfix is only reserved in the POSIX standard, but not in the C standard (and C and POSIX are entirely different things - outside the UNIX bubble at least).

It's unlikely that POSIX changes anymore, but if you get a name collision in a new POSIX version it's still just a simple name collision, and it's up to the user code to fix that.

And it's not like symbol collision problems are limited to POSIX, the world won't end because some piece of C code collides with a symbol used in a dependency, there's always ways to isolate its usage.

Also, it's good practice in the C world to use a namespace prefix for libraries, and such a prefix will also make sure that any _t postfix will not collide with POSIX symbols (the question is of course why POSIX couldn't play nice with the rest of the world and use a posix_ prefix - historical reasons I guess, but then just going a ahead and squatting on the _t postfix for all eternity is a bit rich).

  • shakna a day ago

    The C23 spec also says:

    > A potentially reserved identifier becomes a reserved identifier when an implementation begins using it or a future standard reserves it, but is otherwise available for use by the programmer.

    Which, in practice, does mean using _t is likely to cause you problems, as it may become a reserved identifier, when an implementation like POSIX begins using it.

    • flohofwoe a day ago

      Still debatable since the C standard doesn't reserve the _t postfix (it does reserve a single leading underscore followed by a capital letter, e.g. _Bool, and IIRC it also reserves two leading underscores).

      What POSIX reserves or doesn't reserve doesn't affect code that follows only the C standard but doesn't care about POSIX compatibility, and especially _t is so widely used in C libraries that POSIX's opinion obviously doesn't matter all that much in the real world.

      • shakna a day ago

        Whilst you do point to 6.4.3 for where it does reserve "All identifiers that begin with a double underscore (__) or begin with an underscore (_) followed by an uppercase letter"... That section also has the lovely:

        > Other identifiers may be reserved.

        If an implementation of C uses it... Just... Don't. The standard won't save you here, because it's happy for an implementation to do whatever they feel like.

        • flohofwoe a day ago

          Yeah, and that makes any reserved name rules pretty much useless anyway, e.g. anything goes until a collision actually happens, and then it needs to be fixed on the user side anyway.

    • [removed] a day ago
      [deleted]
  • froh a day ago

    "the UNIX bubble" is an interesting take in the context of C, given the origins of C

    Is your point "why did posix not establish a prefix_ ... _suffix" combo, and maybe even better some reserved "prefix_" namespace?

    which --- I think --- for better or worse leads to the reality that C doesn't have a namespace mechanism, like, say, Java.

    • flohofwoe a day ago

      Well, C does have a namespace mechanism, it's called prefixes ;) It's just unfortunate that both POSIX and the C stdlib don't use prefixes (except for the new C23 stdc_ functions which is going into the right direction at least).

      The problem with C++ style namespaces as language feature is that they require name mangling, which opens up a whole new can of worms.

      In the end, the POSIX _t just means "don't blame us when your library names collide with POSIX names", and that's fine. Other platforms have that problem as well, but the sky hasn't fallen because an occasional type or function name collision.

      • froh 20 hours ago

        thanks for clarifying.

        to all of this I agree:

        if the linker doesn't have namespaces (and it doesn't, unlike, say, the Java class loader, or even more extravagant the OSGi bundle loading mechanism), you need to flatten names into one name space. Which means, as you say, name mangling. and that, even without overloading, is a major PITA.

        and indeed, not prescribing a prefix and just blocking a useful suffix was also an idea others hopefully took as inspiration how to not do things...

        wrt prefixes in the C stdlib, I'd strictly prefer the prefix to be '#define' able, so _if_ you need to move th stdlib to a namespace, #define the prefix before #include-ing the library. needs a statically linked trampoline, though or some other nasty lionk time mechanism. meh. there is a reason languages come with namespaces from the start, these days ...

wavemode a day ago

> The whole "prevent double free" claim is completely bogus.

The way I interpreted the author's intent was that, the logic of error handling (something C sucks even more at) can be greatly simplified if your cleanup routine can freely be called multiple times. At the moment an error happens you no longer have to keep track of where you are in the lifecycle of each local variable, you can just call cleanup() on everything. I actually like the idea from that standpoint.

  • UncleEntity a day ago

    That seemed kind of dubious to me as well but setting the pointer to the freed memory to NULL is good, maybe. Though, with their design, I think it would cause problems with passing the address of a stack allocated wrapper struct to the constructor function if one were into that sort of thing.

    I was reading something a day or two ago where they were talking about using freed memory and their 'solution' to the problem was, basically, if the memory location wasn't reassigned to after it was freed it was 'resurrected' as a valid memory allocation. I'm fairly certain that won't ever lead to any impossible to diagnose bugs...

tialaramex a day ago

For the _t suffix it is deeply unfortunate that on the one hand C's standard library gives people this idea but then the standard says they mustn't use it.

I understand exactly why it was necessary, but to my mind that highlighted an urgent need to provide actual namespacing so that we don't need to rope off whole categories of identifiers for exclusive use by the stdlib, with the implication that every single library will need to do the same. This should have been addressed last century IMO.

lelanthran a day ago

> The whole "prevent double free" claim is completely bogus.

"Completely" means "for all". Are you seriously claiming that "for all instances of double-free, setting the pointer to NULL after freeing it would not help"?

  • lisper a day ago

    > "Completely" means "for all".

    Not in the case of bogosity. Completely bogus things might occasionally work under some very particular circumstances, but unless those particular circumstances just happen to be the circumstances you actually care about, complete bogosity can still obtain.

    > setting the pointer to NULL

    There is no such thing as setting a pointer to null. You can set the value of a variable (whose current value is a pointer) to null, but you cannot guarantee that there isn't a copy of the pointer stored somewhere else except in a few very particular circumstances. This is what the GP meant by "setting a variable to `NULL` only works for cases where there is one, obvious, owner". And, as the GP also pointed out, this "is not the circumstance under which double free is prone to happening in the first place." Hence: complete bogosity.

  • taneq a day ago

    Eeeeh, I don't think 'completely bogus' means 'exhaustively false for all situations'. It just means 'demonstrably false' (for some relatively sane example, we're talking about C after all which means there will always be bogus examples which break any given assumption). There's plenty of cases where zeroing a pointer immediately after freeing it will prevent any further issues. It's still bogus to claim that it categorically solves the problem of double frees. But it does help.

    • tialaramex 16 hours ago

      Yeah. For example "Add four to it" is Completely Bogus way to implement "Multiply by three". Yes, if you had 2 then indeed 2 + 4 == 6 while the "more usual" 2 x 3 == 6, but for other values it doesn't work, it's Completely Bogus.