[HN Gopher] No strcpy either
       ___________________________________________________________________
        
       No strcpy either
        
       Author : firesteelrain
       Score  : 173 points
       Date   : 2025-12-30 13:14 UTC (9 hours ago)
        
 (HTM) web link (daniel.haxx.se)
 (TXT) w3m dump (daniel.haxx.se)
        
       | senthil_rajasek wrote:
       | Title is :
       | 
       | No strcpy either
       | 
       | @dang
        
         | Snild wrote:
         | I don't see a problem with that, but for the record, the title
         | on the site is lower-case for me (both browser tab title, and
         | the header when in reader mode).
        
           | 1f60c wrote:
           | I think the submission originally had a typo ("strpy", with
           | no C)
        
             | Snild wrote:
             | Ah.
        
       | pama wrote:
       | Congrats 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 wrote:
         | Removing strcpy from your code does not make it memory safe.
        
           | kjjfnkeknrn wrote:
           | Removing strcpy from your code does make it a little memory
           | safer.
        
             | alexfoo wrote:
             | Removing strcpy from your code makes it a little less
             | memory unsafe.
             | 
             | (Depends on what you replace it with obviously...)
        
           | pama wrote:
           | Apologies. I never meant to imply that of course. It is a
           | long and arduous process, and this is but a single tiny step.
        
         | Tempest1981 wrote:
         | Yes, 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 wrote:
       | The 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 wrote:
         | Because humans generate and relay the slop-reports in the hopes
         | of being helpful
        
           | captn3m0 wrote:
           | s/being helpful/making money.
        
           | nottorp wrote:
           | There is or was a cash bug bounty.
           | 
           | And even if not, the motivation is building a reputation as a
           | security "expert".
        
         | trollbridge wrote:
         | Making 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 wrote:
           | That got those Core SDI abo vibes.
           | 
           | Flashback of writing exploits for these back in high school.
        
         | easterncalculus wrote:
         | It's a symptom of complete failure of this industry that
         | maintainers are even remotely thinking about, much less
         | implementing changes in their work to stave off harassment over
         | false security impact from bots.
        
       | Scubabear68 wrote:
       | From 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 wrote:
         | Because people are stupid and use AI for things it is not good
         | at.
        
           | Tempest1981 wrote:
           | > people are stupid
           | 
           | people overestimate AI
        
             | lesuorac wrote:
             | Its 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 wrote:
               | As 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.
        
               | zahlman wrote:
               | Apparently FOSS developers have been getting this kind of
               | slop report even though they _clearly don 't_ offer a bug
               | bounty.
        
               | pixl97 wrote:
               | There are no shortage of people wanting to be able to say
               | they found CVE-XXXX-XXX or a bug in product X.
        
               | zahlman wrote:
               | > 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.
               | 
               | This sounds a bit like expecting the people who followed
               | a "make your own drop-shipping company" tutorial to try
               | using the products they're shipping to understand that
               | they suck.
        
         | CGamesPlay wrote:
         | It's not quite as black and white as the article implies. The
         | hallucinated vulnerability reports don't flag it "without
         | caveat", they invent a convoluted proof of vulnerability with a
         | logical error somewhere along the way, and then this is what
         | gets submitted as the vulnerability report. That's why it's so
         | agitating for the maintainers: it requires reading a "proof"
         | and finding the contradiction.
        
         | Sharlin wrote:
         | Because these people who run AI checks on OSS code and submit
         | bogus bug reports either assume that AIs don't make mistakes,
         | or just don't care if the report is legit or not, because
         | there's little to no personal cost to them even if it isn't.
        
       | stabbles wrote:
       | Apart 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/
        
         | p2detar wrote:
         | So? 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/07f7581f6e3d78ef37dfbfc81fd1d...
        
         | molf wrote:
         | That's very interesting! It links to:
         | 
         | https://daniel.haxx.se/blog/2025/10/10/a-new-breed-of-analyz...
         | 
         | and its HN discussion:
         | 
         | https://news.ycombinator.com/item?id=45449348
        
       | swinglock wrote:
       | I'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 wrote:
         | I 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 wrote:
           | assert() 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 wrote:
         | This 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!?
        
       | loeg wrote:
       | A 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 wrote:
       | I'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
        
         | formerly_proven wrote:
         | strncpy 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
        
           | ufo wrote:
           | A big footgun with strncpy is that the output string may not
           | be null terminated.
        
             | kccqzy wrote:
             | Yeah 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 wrote:
               | Until 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.
        
               | kccqzy wrote:
               | You don't do that by accident. Fixed-width strings are
               | thoroughly outdated and unusual. Your mental model of
               | them is very different from regular C strings.
        
               | ninkendo wrote:
               | The mental model doesn't matter, it's the compiler's
               | model that is going to bite you. If the compiler doesn't
               | reject it, it will happen eventually.
        
               | arka2147483647 wrote:
               | Sadly, all the bug trackers are full of bugs relating to
               | char*. So you very much do those by accident. And in C,
               | fixed width strings are not in any way rare or unusual.
               | Go to any c codebase you will find stuff like:
               | char buf[12];        sprintf(buf, "%s%s", this, that); //
               | or        strcat(buf, ...) // or        strncpy(buf, ...)
               | // and so on..
        
               | snickerbockers wrote:
               | Thats only really a problem if this and that are coming
               | from an external source and have not been truncated. I
               | really don't see this as any more significant of a
               | problem than all the many high level scripting languages
               | where you can potentially inject code into a variable and
               | interpret it.
               | 
               | There are certainly ways in which the c library could've
               | been better (eg making strncpy handle the case where the
               | source string is longer than n) but ultimately it will
               | always need to operate under the assumption that the
               | people using it are both competent and acting in good
               | faith.
        
               | kccqzy wrote:
               | When you write such code your mental model is C strings,
               | not fixed-width strings, the intended use case for
               | strncpy.
        
               | Sharlin wrote:
               | Good luck though remembering not to pass one to any
               | function that does expect to find a null terminator.
        
               | andrepd wrote:
               | Seriously. We have type systems and compilers that help
               | us to not forget these things. It's not the 70s anymore!
        
               | kevin_thibedeau wrote:
               | Ignore the prefix and always treat strncpy() as a special
               | binary data operation for an era where shaving bytes on
               | storage was important. It's for copying into a struct
               | with array fields or direct to an encoded block of
               | memory. In that context you will never be dependent on
               | the presence of NUL. The only safe usage with strings is
               | to check for NUL on every use or wrap it. At that point
               | you may as well switch to a new function with better
               | semantics.
        
               | integralid wrote:
               | That's not a problem with strncpy, right? Fixed width
               | records are a thing of the past, and even then it was
               | only used for on-disk storage.
        
           | Cyph0n wrote:
           | strncpy doesn't handle overlapping buffers (undefined
           | behavior). Better to use strncpy_s (if you can) as it is
           | safer overall. See:
           | https://en.cppreference.com/w/c/string/byte/strncpy.html.
           | 
           | As an aside, this is part of the reason why there are so many
           | C successor languages: you can end up with undefined behavior
           | if you don't always _carefully_ read the docs.
        
             | Asooka wrote:
             | Back when strncpy was written there was no undefined
             | behaviour (as the compiler interprets it today). The result
             | would depend on the implementation and might differ between
             | invocations, but it was never the "this will not happen"
             | footgun of today. The modern interpretation of undefined
             | behaviour in C is a big blemish on the otherwise excellent
             | standards committee, committed (hah) in the name of
             | extremely dubious performance claims. If "undefined"
             | meaning "left to the implementation" was good enough when
             | CPU frequency was measured in MHz and nobody had more than
             | one, surely it is good enough today too.
             | 
             | Also I'm not sure what you mean with C successor languages
             | not having undefined behaviour, as both Rust and Zig
             | inherit it wholesale from LLVM. At least last I checked
             | that was the case, correct me if I am wrong. Go, Java and
             | C# all have sane behaviour, but those are much higher
             | level.
        
               | Cyph0n wrote:
               | The problem isn't undefined behavior per se; I was using
               | it as an example for strncpy. Rust is a no - in fact, the
               | goal of (safe) Rust is to eliminate undefined behavior.
               | Zig on the other hand I don't know about.
               | 
               | In general, I see two issues at play here:
               | 
               | 1. C relies heavily on unsized pointers (vs. fat
               | pointers), which is why strncpy_s had to "break" strncpy
               | in order to improve bounds checks.
               | 
               | 2. strncpy memory aliasing restrictions are not encoded
               | in the API and can only be conveyed through docs. This is
               | a footgun.
               | 
               | For (1), Rust APIs of this type operate on sized slices,
               | or in the case of strings, string slices. Zig defines
               | strings as sized byte slices.
               | 
               | For (2), Rust enforces this invariant via the borrow
               | checker by disallowing (at compile-time) a shared slice
               | reference that points to an overlapping mutable slice
               | reference. In other words, an API like this is simply not
               | possible to define in (safe) Rust, which means you (as
               | the user) do not need to pore over the docs for each
               | stdlib function you use looking for memory-related
               | footguns.
        
             | formerly_proven wrote:
             | > strncpy doesn't handle overlapping buffers (undefined
             | behavior).
             | 
             | It would make little sense for strncpy to handle this case,
             | since, as I pointed out above, it converts between
             | different kinds of strings.
        
           | dundarious wrote:
           | Yes, these were also common in several wire formats I had to
           | use for market data/entry.
           | 
           | You would think char symbol[20] would be inefficient for such
           | performance sensitive software, but for the vast majority of
           | exchanges, their technical competencies were not there to
           | properly replace these readable symbol/IDs with a
           | compact/opaque integer ID like a u32. Several exchanges tried
           | and they had numerous issues with IDs not being "properly"
           | unique across symbol types, or time (restarts intra-day or
           | shortly before the open were a common nightmare), etc. A char
           | symbol[20] and strncpy was a dream by comparison.
        
           | dingi wrote:
           | Isn't strlcpy the safer solution these days?
        
             | jandrese wrote:
             | I don't think anybody in this thread read the article.
             | 
             | Strlcpy tries to improve the situation but still has
             | problems. As the article points out it is almost never
             | desirable to truncate a string passed into strXcpy, yet
             | that is what all of those functions do. Even worse, they
             | attempt to run to the end of the string regardless of the
             | size parameter so they don't even necessarily save you from
             | the unterminated string case. They also do loads of
             | unnecessary work, especially if your source string is very
             | long (like a mmaped text file).
             | 
             | Strncpy got this behavior because it was trying to
             | implement the dubious truncation feature and needed to tell
             | the programmer where their data was truncated. Strlcpy
             | adopted the same behavior because it was trying to be a
             | drop in replacement. But it was a dumb idea from the start
             | and it causes a lot of pain unnecessarily.
             | 
             | The crazy thing is that strcpy has the best interface, but
             | of course it's only useful in cases where you have
             | externally verified that the copy is safe before you call
             | it, and as the article points out if you know this then you
             | can just use memcpy instead.
             | 
             | As you ponder the situation you inevitably come to the
             | conclusion that it would have been better if strings
             | brought along their own length parameter instead of relying
             | on a terminator, but then you realize that in order to
             | support editing of the string as well as passing substrings
             | you'll need to have some struct that has the base pointer,
             | length, and possibly a substring offset and length and
             | you've just re-invented slices. It's also clear why a
             | system like this was not invented for the original C that
             | was developed on PDP machines with just a few hundred KB of
             | RAM.
             | 
             | Is it really too late for the C committee to not develop a
             | modern string library that ships with base C26 or C27? I
             | get that they really hate adding features, but C strings
             | have been a problem for over 50 years now, and I'm not
             | advocating for the old strings to be removed or even
             | deprecated at this time. Just that a modern replacement be
             | available and to encourage people to use them for new code.
        
               | cyberpunk wrote:
               | Do they really need to at this point? Just include
               | bstrlib and stop thinking about it?
        
               | jandrese wrote:
               | Having an official replacement is the only thing that I
               | think will motivate the majority C programmers to finally
               | switch.
        
         | lesuorac wrote:
         | It's from a time before computer viruses no?
         | 
         | But also all of this book-keeping takes up extra time and space
         | which is a trade-off easily made nowadays.
        
           | rini17 wrote:
           | Yes, in the old times if you crashed a program or whole
           | computer with invalid input, it was your fault.
           | 
           | Viruses did exist, and these were considered users' fault
           | too.
        
         | alexfoo wrote:
         | Yet software developed in C, with all of the foibles of its
         | string routines, has been sold and running for years with
         | trillions of USD is total sales.
         | 
         | A library that records how much memory is allocated to a string
         | along with the pointer isn't a necessity.
         | 
         | Most people who write in C professionally are completely used
         | to it although the footgun is (and all of the others are)
         | always there lurking.
         | 
         | You'd generally just see code like this:-
         | char hostname[20];         ...         strncpy( hostname,
         | input, 20 );         hostname[19]=0;
         | 
         | The problem obviously comes if you forget the line to NUL that
         | last byte AND you have a input that is greater than 19
         | characters long.
         | 
         | (It's also very easy to get this wrong, I almost wrote
         | `hostname[20]=0;` first time round.)
         | 
         | I remember debugging a problem 20+ years ago on a customer site
         | with some software that used Sybase Open/Server that was
         | crashing on startup. The underlying TDS communications protocol
         | (https://www.freetds.org/tds.html) had a fixed 30 byte field
         | for the hostname and the customer had a particularly long FQDN
         | that was being copied in without any checks on its length. An
         | easy fix once identified.
         | 
         | Back then though the consequences of a buffer overrun were
         | usually just a mild annoyance like a random crash or something
         | like the Morris worm. Nowadays such a buffer overrun is deadly
         | serious as it can easily lead to data exfiltration, an RCE
         | and/or a complete compromise.
         | 
         | Heartbleed and Mongobleed had nothing to do with C string
         | functions. They were both caused by trusting user supplied
         | payload lengths. (C string functions are still a huge source of
         | problems though.)
        
           | __float wrote:
           | > Yet software developed in C, with all of the foibles of its
           | string routines, has been sold and running for years with
           | trillions of USD is total sales.
           | 
           | This doesn't seem very relevant. The same can be said of
           | countless other bad APIs: see years of bad PHP, tons of
           | memory safety bugs in C, and things that have surely led to
           | significant sums of money lost.
           | 
           | > It's also very easy to get this wrong, I almost wrote
           | `hostname[20]=0;` first time round.
           | 
           | Why would you do this separately every single time, then?
           | 
           | The problem with bad APIs is that even the best programmers
           | will occasionally make a mistake, and you should use
           | interfaces (or...languages!) that prevent it from happening
           | in the first place.
           | 
           | The fact we've gotten as far as we have with C does not mean
           | this is a defensible API.
        
             | alexfoo wrote:
             | Sure, the post I was replying to made it sound like it's a
             | surprise that anything written in C could ever have been a
             | success.
             | 
             | Not many people starting a new project (commercial or
             | otherwise) are likely to start with C, for very good
             | reason. I'd have to have a very compelling reason to do so,
             | as you say there are plenty of more suitable alternatives.
             | Years ago many of the third party libraries available only
             | had C style ABIs and calling these from other languages was
             | clumsy and convoluted (and would often require implementing
             | cstring style strings in another language).
             | 
             | > Why would you do this separately every single time, then?
             | 
             | It was just an illustration or what people used to do. The
             | "set the trailing NUL byte after a strncpy() call" just
             | became a thing lots of people did and lots of people looked
             | for in code reviews - I've even seen automated checks. It
             | was in a similar bucket to "stuff is allocated, let me make
             | sure it is freed in every code path so there aren't any
             | memory leaks", etc.
             | 
             | Many others would have written their own function like
             | `curlx_strcopy()` in the original article, it's not a novel
             | concept to write your own function to implement a better
             | version of an API.
        
           | t43562 wrote:
           | I learned C in about 1989/1990 and have used it a lot since
           | then. I have worked on a fair amount of rotten commercial C
           | code, sold at a high price, in which every millimeter of
           | extra functionality was bought with sweat and blood. I once
           | spent a month finding a memory corruption issue that happened
           | every 2 weeks with a completely different stack trace which,
           | in the end, required a 1-line fix.
           | 
           | The effort was usually out of proportion with the
           | achievement.
           | 
           | I crashed my own computer a lot before I got Linux. Do you
           | remember far pointers? :-( In those days millions of dollars
           | were made by operating systems without memory protection that
           | couldn't address more than 640k of memory. One accepted that
           | programs sometimes crashed the whole computer - about once a
           | week on average.
           | 
           | Despite considering myself an acceptable programmer I still
           | make mistakes in C quite easily and I use valgrind or the
           | sanitizers quite heavily to save myself from them. I think
           | the proliferation of other languages is the result of all
           | this.
           | 
           | In spite of this I find C elegant and I think 90% of my
           | errors are in string handling so therefore if it had a decent
           | string handling library it would be enormously better. I
           | don't really think pure ASCIIZ strings are so marvelous or so
           | fast that we have to accept their bullshit.
        
             | alexfoo wrote:
             | > I learned C in about 1989/1990 and have used it a lot
             | since then. I have worked on a fair amount of rotten
             | commercial C code, sold at a high price, in which every
             | millimeter of extra functionality was bought with sweat and
             | blood. I once spent a month finding a memory corruption
             | issue that happened every 2 weeks with a completely
             | different stack trace which, in the end, required a 1-line
             | fix.
             | 
             | That sums up one of my old roles where this kind of thing
             | accounted for about 10% of my time over a 10 year period.
             | 
             | Heisenbug, mutating stack traces, weeks between
             | occurrences, 1 line fix, do some other interesting work
             | before the next weird thing comes along.
             | 
             | I think the longest running one I had (several years) was
             | some weird interaction between pthread_cond_wait() and
             | pthread_cond_broadcast(). Ugh.
        
           | bluecalm wrote:
           | >>(It's also very easy to get this wrong, I almost wrote
           | `hostname[20]=0;` first time round.)
           | 
           | Impossible to get wrong with a modern compiler that will warn
           | you on that or LSP that will scream the moment you type ; and
           | hit enter/esc.
        
         | jerf wrote:
         | Yes, not having a length along with the string was a mistake.
         | It dates from an era where every byte was precious and the
         | thought of having two bytes instead of one for length was a
         | significant loss.
         | 
         | I have long wondered how terrible it would have been to have
         | some sort of "varint" at the beginning instead of a hard-coded
         | number of bytes, but I don't have enough experience with that
         | generation to have a good feel for it.
        
         | Someone wrote:
         | > I've always wondered at the motivatons of the various string
         | routines in C
         | 
         | This idiom:                   char hostname[20];         ...
         | strncpy( hostname, input, 20 );         hostname[19]=0;
         | 
         | exists because _strncpy_ was invented for copying file names
         | that got stored in 14-byte arrays, zero terminated only if
         | space permitted (https://stackoverflow.com/a/1454071)
        
           | masklinn wrote:
           | Technically strncpy was invented to interact with null-padded
           | fixed-size strings in general. We've mostly (though not
           | entirely) moved away from them but fixed-size strings used to
           | be _very_ common. You can see them all over old file formats
           | still.
        
         | CupricTea wrote:
         | >every one of them seems to have some huge caveat which makes
         | them useless
         | 
         | They were added into C before enough of the people designing it
         | knew the consequences they would bring. Another fundamentally
         | broken oversight is array-to-pointer demotion in function
         | signatures instead of having fat pointer types.
        
       | TZubiri wrote:
       | LMAO
       | 
       | After all this time the initial AI Slop report was right:
       | 
       | https://hackerone.com/reports/2298307
        
         | lesuorac wrote:
         | ?
         | 
         | 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 wrote:
       | > 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 wrote:
       | > 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 wrote:
         | I'd use different types for those. Like Java's String vs.
         | CharSequence.
        
       | Tharre wrote:
       | It'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 wrote:
         | We should just move away from null-terminated strings, where we
         | can, as fast as we can.
        
           | raverbashing wrote:
           | Yes
           | 
           | And maybe even have a (arch dependent) string buffer zone
           | where the actual memory length is a multiple of 4 or even 8
        
           | masklinn wrote:
           | We 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 wrote:
             | We 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.
        
             | saghm wrote:
             | Given that the C ABI is basically the standard for how
             | arbitrary languages interact, I wouldn't characterize all
             | of the headaches this can cause as just when other
             | languages interact with C; arguably it can come up when any
             | two languages interact at all, even if neither are C.
        
         | samshine wrote:
         | I haven't seen a strcpy use a scalar loop in ages. Is this an
         | ARM thing?
        
           | manwe150 wrote:
           | The spec and some sanitizers use a scalar loop (because they
           | need to avoid mistakenly detecting UB), but real world libc
           | seem unlikely to use a scalar loop.
        
       | ahoka wrote:
       | "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 wrote:
         | Your 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 wrote:
           | "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 wrote:
           | > 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 wrote:
         | strlcpy 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
        
           | tptacek wrote:
           | Who cares? Just vendor it into your project. It's a tiny
           | string manipulation function.
           | 
           | (I agree with the author of the piece that strlcpy doesn't
           | actually solve the real problem.)
        
           | bentley wrote:
           | strlcpy is in POSIX now, actually.
           | 
           | https://pubs.opengroup.org/onlinepubs/9799919799/functions/s.
           | ..
        
             | manwe150 wrote:
             | Ah, good point. I forgot it had just gotten added. Past
             | context https://news.ycombinator.com/item?id=36765747
        
       ___________________________________________________________________
       (page generated 2025-12-30 23:01 UTC)