[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)