Live data from Hacker News

No strcpy either

daniel.haxx.se

101–110 of 151 posts

Re: No strcpy either

#101
post #41
post #28

Earlier quoted context omitted.

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.

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 perf…

Rust safe subset doesn't have UB. At all. So long as you never write the "unsafe" keyword you're fine, the compiler will check you are obeying all of the language rules at all times.

Whereas in C, oops, sorry, you broke a rule you didn't even know existed and so that's Undefined Behaviour left and right. Some of it you could argue falls into the category you're describing, where in a better world it should have been made Implementation Defined, not UB, and too bad. However lots of it is just because the language was designed a very long time ago and prioritized ease of implementation.

If you wish the language was properly defined, you should use (safe) Rust. If you just wish that when you write nonsense the compiler should somehow guess what you meant and do that, you're not actually a programmer, find a practice which suits you better - take up knitting, learn to paint, something like that.

Re: No strcpy either

#102
post #58
post #41

Earlier quoted context omitted.

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 perf…

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 alias…

> 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.

At least the last time I cared about this, the borrow checker wouldn't allow mutable and immutable borrows from the same underlying object, even if they did not overlap. (Which is more restrictive, in an obnoxious way.)

Re: No strcpy either

#103
post #102
post #58

Earlier quoted context omitted.

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 alias…

> 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. At least the last time I cared about this, the borrow checker wouldn't allow mutable and immutable borrows from the same underlying object, even if they did not overlap. (Which is more restrictive, in an obnoxious way.)

Do you mean borrows for different fields of a struct? If so, that’s handled today - it’s sometimes called “splitting borrows”: https://doc.rust-lang.org/nomicon/borrow-splitting.html

Re: No strcpy either

#104
post #103
post #102

Earlier quoted context omitted.

> 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. At least the last time I cared about this, the borrow checker wouldn't allow mutable and immutable borrows from the same underlying object, even if they did not overlap. (Which is more restrictive, in an obnoxious way.)

Do you mean borrows for different fields of a struct? If so, that’s handled today - it’s sometimes called “splitting borrows”: https://doc.rust-lang.org/nomicon/borrow-splitting.html

Not exactly -- independent subranges of the same range (as would be relevant to something like memcpy/memmove/strcpy). E.g.,

https://godbolt.org/z/YhGajnhEG

It's mentioned later in the same article you shared above.

Re: No strcpy either

#105
post #104
post #103

Earlier quoted context omitted.

Do you mean borrows for different fields of a struct? If so, that’s handled today - it’s sometimes called “splitting borrows”: https://doc.rust-lang.org/nomicon/borrow-splitting.html

Not exactly -- independent subranges of the same range (as would be relevant to something like memcpy/memmove/strcpy). E.g., https://godbolt.org/z/YhGajnhEG It's mentioned later in the same article you shared above.

Gotcha. There is a split_at_mut method that splits a mutable slice reference into two. That doesn’t address the problem you had, but I think that’s best you can do with safe Rust.

Re: No strcpy either

#106
post #105
post #104

Earlier quoted context omitted.

Not exactly -- independent subranges of the same range (as would be relevant to something like memcpy/memmove/strcpy). E.g., https://godbolt.org/z/YhGajnhEG It's mentioned later in the same article you shared above.

Gotcha. There is a split_at_mut method that splits a mutable slice reference into two. That doesn’t address the problem you had, but I think that’s best you can do with safe Rust.

Yeah. It just isn't something the borrow checker natively understands.

Re: No strcpy either

#107

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.

[deleted]

Re: No strcpy either

#108
post #53

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…

I haven't seen a strcpy use a scalar loop in ages. Is this an ARM thing?

Modern x86 CPUs have actual instructions for strcpy that work fairly well. There were several false starts along the way, but the performance is fine now.

Re: No strcpy either

#109
post #30

Earlier quoted context omitted.

Good luck though remembering not to pass one to any function that does expect to find a null terminator.

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 f…

> an era where shaving bytes on storage was important

Fixed size strings don’t save bytes on storage tho, when the bank reserves 20 bytes for first name and you’re called Jon that’s 17 bytes doing fuckall.

What they do is make the entire record fixed size and give every field a fixed relative position so it’s very easy to access items, move record around, reuse allocations (or use static allocation), … cycles is what they save.

Post reply on HN