8 ms·
No strcpy either
- senthil_rajasek 10mo agoTitle is : No strcpy either @dang
- pama 10mo agoCongrats on the completion of this effort! C/C++ can be memory safe but take some effort. IMHO the timeline figure could benefit in mobile from using larger fonts. Most plotting libraries have horrible font size defaults. I wonder why no library picked the other extreme end: I have never seen too large an axis label yet.
- saagarjha 10mo agoRemoving strcpy from your code does not make it memory safe.
- kjjfnkeknrn 10mo agoRemoving strcpy from your code does make it a little memory safer.
- alexfoo 10mo agoRemoving strcpy from your code makes it a little less memory unsafe. (Depends on what you replace it with obviously...)
- pama 10mo agoApologies. I never meant to imply that of course. It is a long and arduous process, and this is but a single tiny step.
- Tempest1981 10mo agoYes, the graph font-sizes seem intended for printing them on a single sheet of paper, vs squeezed into a single column in a blog.
- snvzz 10mo agoThe AI chatbot vulnerability reports part sure is sad to read. Why is this even a thing and isn't opt-in? I dread the idea of starting to get notifications from them in my own projects.
- Y_Y 10mo agoBecause humans generate and relay the slop-reports in the hopes of being helpful
- trollbridge 10mo agoMaking a strcpy honeypot doesn’t sound like a bad idea… void nobody_calls_me(const char *stuff) { char *a, *b; const size_t c = 1024; a = calloc(c); if (!a) return; b = malloc(c); if (!b) { free(a); return; } strncpy(a, stuff, c - 1); strcpy(b, a); strcpy(a, b); free(a); free(b); } Some clever obfuscation would make this even more effective.
- snvzz 10mo agoThat got those Core SDI abo vibes. Flashback of writing exploits for these back in high school.
- trollbridge 10mo agoIn an interesting way, this is an attempt to exploit LLMs into revealing themselves.
- Scubabear68 10mo agoFrom the article: > It has been proven numerous times already that strcpy in source code is like a honey pot for generating hallucinated vulnerability claims This closing thought in the article really stood out to me. Why even bother to run AI checking on C code if the AI flags strcpy() as a problem without caveat?
- saagarjha 10mo agoBecause people are stupid and use AI for things it is not good at.
- Tempest1981 10mo ago> people are stupid people overestimate AI
- lesuorac 10mo agoIts weird though because looking through the hackone reports in the slop wiki page there aren't actually reproduction steps. It's basically always just a line of code and an explanation of how a function can be mis-used but not a "make a webserver that has this hardcoded response". So like why doesn't the person iterate with the AI until they understand the bug (and then ultimately discover it doesn't exist)? Like have any of this bug reports actually paid out? It seems like quickly people should just give up from a lack of rewards.
- amenhotep 10mo agoAs long as the number of people newly being convinced that AI generated bounty demands are a good way to make money equals or exceeds the number of people realising it isn't and giving up, the problem remains. Not helped, I imagine, that once you realise it doesn't work, an easy pivot is to start convincing new people that it'll work if they pay you money for a course on it.
- 10mo ago
- stabbles 10mo agoApart from Daniel Sternberg's frequent complaints about AI slop, he also writes [1] > A new breed of AI-powered high quality code analyzers, primarily ZeroPath and Aisle Research, started pouring in bug reports to us with potential defects. We have fixed several hundred bugs as a direct result of those reports – so far. [1] https://daniel.haxx.se/blog/2025/12/23/a-curl-2025-review/ https://daniel.haxx.se/blog/2025/12/23/a-curl-2025-review/
- p2detar 10mo agoSo? Those are automated analysis tools and by "slop" he seems to refer to careless reports crafted using AI, solely for collecting bounties: https://gist.github.com/bagder/07f7581f6e3d78ef37dfbfc81fd1d1cd https://gist.github.com/bagder/07f7581f6e3d78ef37dfbfc81fd1d...
- molf 10mo agoThat's very interesting! It links to: https://daniel.haxx.se/blog/2025/10/10/a-new-breed-of-analyzers/ https://daniel.haxx.se/blog/2025/10/10/a-new-breed-of-analyz... and its HN discussion: https://news.ycombinator.com/item?id=45449348 https://news.ycombinator.com/item?id=45449348
- swinglock 10mo agoI'm surprised curlx_strcopy doesn't return success. Sure you could check if dest[0] != '/0' if you care to, but that's not only clumsy to write but also error prone, and so checking for success is not encouraged.
- AlexeyBrin 10mo agoI guess the idea is that if the code does not crash at this line: DEBUGASSERT(slen < dsize); it means it succeeded. Although some compilers will remove the assertions in release builds. I would have preferred an explicit error code though.
- swinglock 10mo agoassert() is always only compiled if NDEBUG is not defined. I hope DEBUGASSERT is just that too because it really sounds like it, even more so than assert does. But regardless of whether the assert is compiled or not, its presence strongly signals that "in a C program strcpy should only be used when we have full control of both" is true for this new function as well.
- jutter 10mo agoThis is especially bizarre given that he explains above that "it is rare that copying a partial string is the right choice" and that the previous solution returned an error... So now it silently fails and sets dest to an empty string without even partially copying anything!?
- ahoka 10mo agoYeah, thought the same. Expect some CVEs in the future.
- spacechild1 10mo agoWhat kind of CVE would you expect? The destination buffer will always contain a valid null-terminated string (as long as the buffer size is not zero).
- deleted 10mo ago
- loeg 10mo agoA weird Annex-K like API. The destination buffer size includes space for the trailing nul, but the source size only includes non-nul string bytes. I don't really think this adds anything over forcing callers to use memcpy directly, instead of strcpy.
- t43562 10mo agoI've always wondered at the motivatons of the various string routines in C - every one of them seems to have some huge caveat which makes them useless. After years I now think it's essential to have a library which records at least how much memory is allocated to a string along with the pointer. Something like this: https://github.com/msteinert/bstring https://github.com/msteinert/bstring
- formerly_proven 10mo agostrncpy is fairly easy, that's a special-purpose function for copying a C string into a fixed-width string, like typically used in old C applications for on-disk formats. E.g. you might have a char username[20] field which can contain up to 20 characters, with unused characters filled with NULs. That's what strncpy is for. The destination argument should always be a fixed-size char array. A couple years ago we got a new manual page courtesy of Alejandro Colomar just about this: https://man.archlinux.org/man/string_copying.7.en https://man.archlinux.org/man/string_copying.7.en
- ufo 10mo agoA big footgun with strncpy is that the output string may not be null terminated.
- kccqzy 10mo agoYeah but fixed width strings don’t need null termination. You know exactly how long the string is. No need to find that null byte.
- ninkendo 10mo agoUntil you pass them as a `char *` by accident and it eventually makes its way to some code that does expect null termination. There’s languages where you can be quite confident your string will never need null termination… but C is not one of them.
- TZubiri 10mo agoLMAO After all this time the initial AI Slop report was right: https://hackerone.com/reports/2298307 https://hackerone.com/reports/2298307
- lesuorac 10mo ago? Nonce and websockets don't appear at all in the blog post. The only thing the ai slop got right is that by removing strcpy curl will get less issues [submitted about it].
- zahlman 10mo ago> To make sure that the size checks cannot be separated from the copy itself we introduced a string copy replacement function the other day that takes the target buffer, target size, source buffer and source string length as arguments and only if the copy can be made and the null terminator also fits there, the operation is done. ... And if the copy can't be made, apparently the destination is truncated as long as there's space (i.e., a null terminator is written at element 0). And it returns void. I'm really not sold on that being the best way to handle the case where copying is impossible. I'd think that's an error case that should be signaled with a non-zero return, leaving the destination buffer alone. Sure, that's not supposed to happen (hence the DEBUGASSERT macro), but still. It might even be easier to design around that possibility rather than making it the caller's responsibility to check first.
- Waterluvian 10mo ago> Enforce checks close to code This makes a lot of sense but one time I find this gets messy is when there’s times I need to do checks earlier in a dataset’s lifetime. I don’t want to pay to check multiple times, but I don’t want to push the check up and it gets lost in a future refactor. I’m imagining a metadata for compile time that basically says, “to act on this data it must have been first checked. I don’t care when, so long as it has been by now.” Which I’m imagining is what Rust is doing with a Result type? At that point it stops mattering how close to code a check is, as long as you type distinguish between checked and unchecked?
- deepsun 10mo agoI'd use different types for those. Like Java's String vs. CharSequence.
- masklinn 10mo ago> Which I’m imagining is what Rust is doing with a Result type? Result only carries information about the success / failure of an unspecified operation, it is not a long term signal and furthermore is not resistant to tampering (so a mistake processing the Result can undo the validation). What you want in this case is a new separate type, which can only be constructed through the check operation. This is the ethos of "parse, don't validate". And you're correct that in that case you don't need the check to be close to the consumer, in fact you want the opposite, for the check to be as close to the software edge as possible such that tainted data has limited to no presence inside the system and it's difficult or impossible to unwittingly interact with it. But of course the farther into that direction you head the more expressive a type system you need. And some constraints are not so easily checked as there's a multitude of consumers each with their own foibles, or as in this case you need to check the interaction of multiple runtime objects.
- Tharre 10mo agoIt's worth noting that strcpy() isn't just bad from a security perspective, on any CPU that's not completely ancient it's bad from a performance perspective as well. Take the best case scenario, copying a string where the precise length is unknown but we know it will always fit in, say, 64 bytes. In earlier days, I would always have used strcpy() for this task, avoiding the "wasteful" extra copies memcpy() would make. It felt efficient, after all you only replace a i < len check with buf[i] != null inside your loop right? But of course it doesn't actually work that way, copying one byte at a time is inefficient so instead we copy as many as possible at once, which is easy to do with just a length check but not so easy if you need to find the null byte. And on top of that you're asking the CPU to predict a branch that depends completely on input data.
- amelius 10mo agoWe should just move away from null-terminated strings, where we can, as fast as we can.
- raverbashing 10mo agoYes And maybe even have a (arch dependent) string buffer zone where the actual memory length is a multiple of 4 or even 8
- masklinn 10mo agoWe have. C is basically the only langage in any sort of widespread use where terminated strings are a thing. Which of course causes issues when languages with more proper strings interact with C but there you go.
- thayne 10mo agoWe should move away from it in C usage as well. Ideally, the standard would include a type that packages a string with its length, and had functions that used that type and/or took the length as an argument. But even without that it is possible avoid using null terminated strings in a lot of places.
- ahoka 10mo ago"strncpy() is a weird function with a crappy API." Well if you bother looking up that it's originally created for non null-terminated strings, then it kinda makes sense. The real problem begun when static analyzers started to recommend using it instead of strcpy (the real alternative used to be snprintf, now strlcpy).
- tourist2d 10mo agoYour comment makes no sense. If it was designed for non-null terminated strings, why would it specifically pad after a null terminator? I looked up the actual reason for its inception: --- Rationale for the ANSI C Programming Language", Silicon Press 1990. 4.11.2.4 The strncpy function strncpy was initially introduced into the C library to deal with fixed-length name fields in structures such as directory entries. Such fields are not used in the same way as strings: the trailing null is unnecessary for a maximum-length field, and setting trailing bytes for shorter names to null assures efficient field-wise comparisons. strncpy is not by origin a "bounded strcpy," and the Committee has preferred to recognize existing practice rather than alter the function to better suit it to such use.
- bentley 10mo ago“fixed-length name fields in structures such as directory entries” “the trailing null is unnecessary for a maximum-length field” That is a non–null terminated string.
- masklinn 10mo ago> If it was designed for non-null terminated strings, why would it specifically pad after a null terminator? Padded and terminated strings are completely different beasts. And the text you quote tells you black on white that strncpy deals in padded strings.
- manwe150 10mo agostrlcpy is a BSD-ism that isn't in posix. The official recommendation is stpecpy. Unfortunately, it is only implemented in the documentation, but not available anywhere unless you roll your own: https://man7.org/linux/man-pages/man7/string_copying.7.html https://man7.org/linux/man-pages/man7/string_copying.7.html
- self_awareness 10mo agoBikeshedding.
- user____name 10mo agoLibraries this well established can afford to bikeshed.
- self_awareness 10mo agoTrue. But for most projects, this is pretty much counterproductive.
- rf15 10mo agoit feels like the arguments' off-by-one buffer size vs string length is horrible ergonomics and will probably lead to further usage errors in the future. Yes I have a degree in bike shedding, why am I always getting this particular question
- juliangmp 10mo agoString handling (or arrays in general) has got to be the single aspect of C that I despise the most. Its clunky to use, often needs unnecessary copying (e.g. atoi) and makes it really easy to invoke undefined behavior. I still don't get why a simple ptr+size type hasn't made its way into the language. #embed got in but I guess a new type would have been too much... at least we got bool after a few decades. Also, for those that want the trimming behavior of strncpy but with the null termination, you can replace the strncpy calls with snprintf. You should also always enable -Wstringop-truncation.