C-coders of HN, do you use plain vanilla C strings in your project (s)? I was under the impression that most (at least bigger ones) use some custom length carrying string type to avoid exactly these sort of problems
It depends. If I'm writing a library, it's bare pointers. If I'm writing something not a library that's big enough, I'll use a struct {size_t length; char* string;} where the length is the string length, and string contains (length) characters + a nul byte. I might even mix in allocation data for the total allocated size of the buffer if it's important enough.
Simple to implement and use (and also backwards compatible), provided you have a library of common functions for allocating, copying, etc.
If I'm size constrained, I'll consider uint16_t for the length field. If I'm REALLY size constrained, I'll use a VLQ [1] for the length field and take the slight performance hit.
The right thing to do here is generally to avoid dealing with strings at all: you only need it to parse input and print/log output, beyond that everything should be using integer identifiers and handles.
You can use small strings directly on the stack for massive performance gains in many scenarios, where such strings are manipulated in same context with macros or inner(called from within the current string stack context) functions.
https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html#Vari...
These days my work is focused on kernel/systems programming, so plain C (char or wchar_t) strings outside the kernel, and whatever the kernel requires inside it (e.g. UNICODE_STRING on Windows).
When I do apps I have my own length-prefixed variant.