The #1 thing is to ban free() and base a C library on garbage collection.
At the low level, daemons and such, I prefer pool allocators. That is, having each allocation belong to a context, and being able to free an entire context. This matches very well the needs of connection-oriented services, and also allows trivial implementation of per-connection memory use limits.
I am very ambivalent on GC. If rock solid, it does eliminate a big swathe of possible bugs. On the other hand, I've never found those bugs to be hard to avoid anyway. I think it is slightly more higher-level concept than I'd like; the memory use overhead, especially in a service daemon, worries me. Speed is not an issue, I know. In any case, I'm not ruling either one out for now.
I do believe easy control of allocation limits is important, because typical Linux machines overcommit memory, and if it is easy for a service to internally control its memory use (with minimal code overhead), developers might actually use it. In particular, if a service runs out of memory, I'd prefer it just drops a few connections, rather than die.
Make a single standard for the sizes of types and printf()-like format strings
Using u8/u16/s32/s64 as typedefs for uint8_t/uint16_t/int32_t/int64_t, sure. Having printf()-like function with native formatting specifiers for them, definitely.
But, because this is C, and not a new programming language, we cannot restrict the size of say int or long. We do need to stay within the rules of freestanding C, more or less.
There do need to be a couple of types that depend on the architecture, like size_t/ssize_t and uintptr_t/intptr_t. But these should obviously have native formatting specifiers, just like size_t has (%zu) and ssize_t has (%zd).
Saner string funcs
Most definitely; strlcpy() (which ensures the target will contain an end-of-string nul byte), and also
memfill(buffer, offset, size) which repeats the first
offset bytes of
buffer to the rest of the buffer, up to
size; for example, to initialize floating-point vectors or structure arrays efficiently. I also like strndup(), which is not in standard C (they're in BSD and POSIX.1), but is definitely useful.
Some of these are optimizations (memfill() definitely is), some avoid the horrible corner cases (like strncpy() not adding a string-terminating nul byte if the source string is long enough), and others make it easier to use better patterns.
For example, GNU and BSD provide asprintf(), which dynamically allocates the buffer to be formatted. Very few programmers actually use it. I'd prefer something along the lines of
ssize_t my_printf(char **strp, size_t *sizep, const char *fmt, ...) with an interface similar to
getline(). That is, to e.g. construct some complicated string, you might use
char *p = NULL;
size_t p_max = 0;
ssize_t p_len = my_printf(&p, &p_max, "foo-%s-%.3f", name, version);
(using current standard C library types here, for clarity). This way, if one needs to construct such strings often, they can reuse the buffer, but still get it dynamically reallocated whenever it needs be.
I also dislike the interfaces that use static internal storage, and are therefore non-thread-safe (strtok() and so on). BSD and GNU provide thread-safe versions, that point to either a prepared context variable (strtok_r()), or use dynamically allocated memory.