5 ms·
Yes, and interestingly, because even when used correctly they "complicate audits". This is an interesting use of preprocessor macros, I'm strongly debating intr
by opticfluorine 7y ago
Yes, and interestingly, because even when used correctly they "complicate audits". This is an interesting use of preprocessor macros, I'm strongly debating introducing something like this at work.
- kbumsik 7y agoI'm not an expert in C, but then what's the issue with strncpy() or any "n" functions? It prevents overflow AFAIK. Also what is the alternative (memcpy?) and why?
- susam 7y agostrncpy() does not guarantee that the copied string would be terminated with a null byte ('\0'). For a call that looks like strncpy(dst, src, n), if there is no null byte in the first n bytes of src, the string copied to dst would also not contain a null byte. Here is an example code to demonstrate the problem: #include <stdio.h> #include <string.h> int main() { char a[] = "01234567"; strncpy(a, "foobar", 4); printf("%.8s\n", a); return 0; } Here is the output: $ cc -std=c89 -Wall -Wextra -pedantic foo.c && ./a.out foob4567 A C89-conforming alternative I use is a macro like this that guarantees '\0'-termination as the first thing: #define strcp(a, b, c) (a[0] = '\0', strncat(a, b, c - 1)) An example from my code: https://github.com/susam/uncap/blob/master/uncap.c#L78-L87 https://github.com/susam/uncap/blob/master/uncap.c#L78-L87 Here is how to use it: #include <stdio.h> #include <string.h> #define strcp(a, b, c) (a[0] = '\0', strncat(a, b, c - 1)) int main() { char a[] = "01234567"; strcp(a, "foobar", 4); printf("%.8s\n", a); return 0; } Here is the output: $ cc -std=c89 -Wall -Wextra -pedantic foo.c && ./a.out foo
- saagarjha 7y agoYour macro refers to a twice; it might be better as a function.
- foo101 7y agoWhat has referring to a variable twice got to do with whether it should be a macro or function?
- mras0 7y agoBecause it's a standard pitfall: https://gcc.gnu.org/onlinedocs/cpp/Duplication-of-Side-Effects.html#Duplication-of-Side-Effects https://gcc.gnu.org/onlinedocs/cpp/Duplication-of-Side-Effec...
- jfk13 7y agoIf the strcp() macro is used with a function as the first argument (or an expression that has side-effects), it's not obvious at the call site (or, probably, intended by the programmer) that the argument will be evaluated twice. E.g. suppose we write something like char* buf = strcp(((char*)malloc(4)), "foobar", 4); expecting this to copy the beginning of the string "foobar" into a newly-allocated 4-byte buffer. Oops... this will actually call malloc twice (leaking the first buffer), and it won't have written the intended '\0' into the buffer that actually ends up getting used, so all bets are off... If strcp were a function, its first argument would be evaluated just once, and it would work as intended.
- aflag 7y agostrncat is also banned, though.
- kd5bjo 7y agoIt doesn’t ensure that there’s a null terminator in the resultant string. This may potentially lead to a later overrun when the copied string is read back. (See also https://linux.die.net/man/3/strncpy https://linux.die.net/man/3/strncpy )
- opticfluorine 7y agoThe issue is that strncpy doesn't guarantee that the destination string is null-terminated after a copy, particularly in the case where n is shorter than the original string, so you could run into overflows if you then ran strlen() or similar against it. Here's a good explanation from Raymond Chen: https://devblogs.microsoft.com/oldnewthing/?p=36773 https://devblogs.microsoft.com/oldnewthing/?p=36773
- deleted 7y ago[deleted]
- Zardoz84 7y agostrncpy have the danger of not putting a null character at the end of the destination , if source is longer than num. > Copies the first num characters of source to destination. If the end of the source C string (which is signaled by a null-character) is found before num characters have been copied, destination is padded with zeros until a total of num characters have been written to it. No null-character is implicitly appended at the end of destination if source is longer than num. Thus, in this case, destination shall not be considered a null terminated C string (reading it as such would overflow).
- deleted 7y ago[deleted]
- 1over137 7y agostrlcpy() is a nice alternative, it's from OpenBSD from 1996. Was later added to the other BSDs, Solaris and macOS. But, last I checked, Linux never added them. :( https://www.sudo.ws/todd/papers/strlcpy.html https://www.sudo.ws/todd/papers/strlcpy.html
- ncmncm 7y agostrlcpy is a terrible alternative. I have never seen it used correctly. It takes more and uglier code to use it correctly than to use strlen and strcpy. People who use it don't bother. Finding use of strlcpy in a program is a red warning of sloppy code. There are good reasons it was kept out of glibc for so long.
- jandrese 7y agoI agree that strlcpy is braindamaged, but why in God's Green Earth isn't there a sensible replacement in stdlib in 2019? This shouldn't be that hard, yet the best alternative is I think snprintf, which is just so ugly. For a long time it wasn't used because compiler support was spotty, but it's been 20 years now so that shouldn't be a major issue anymore.
- ncmncm 7y agoThe (more-or-less) sensible replacement is std::string. Adoption has been spotty, for practical, ideological, and fetishistic reasons. The first step is to compile the C program with a C++ compiler. Next, start making improvements. If you skip the first step, the ceiling on improvements is limited.