> would this have been a problem had it been written in rust?
The answer would be "it depends on whether you consider denial-of-service a problem". The key detail which makes all the difference is that, unless you're playing with raw pointers (which can only be dereferenced in "unsafe" blocks), the pointer to a buffer slice is always kept together with its length (in a "fat pointer"). Attempting to write through it past the buffer's bounds will result in a Rust panic, which usually aborts the whole process (there are ways to abort just one thread, or even to treat it similarly to a C++ exception, but a library cannot depend on them since the program might be compiled in the panic=abort mode). While that's obviously better than allowing for remote code execution, it still could be considered an issue.
Of course, that's assuming you want a similar API and are writing the code in a similar style, just replacing the direct pointer manipulation with slice manipulation. I don't know whether, in this particular case, more idiomatic Rust code would have avoided the issue. And, of course, the "growable container" approach would completely avoid it, but Rust is also used in places where memory allocation is not allowed, so having a non-allocating API still makes sense.
It should be noted that you can simply use the fallible API's for slices in Rust, then you don't have a crash but can cleanly abort the operation and return an error.
True, but it doesn't make much sense to use the fallible slice APIs when you know they will never fail (the only way they could fail would be if the code has a bug). It would just complicate not only the code within the function, but also the API to the function, which also becomes a fallible API (and this propagates outward, until it meets a caller which already was fallible for other reasons). And complicating the code unnecessarily increases the chance of logic bugs.
It's actually preferrable in many of those "infallible" cases to panic rather than handling the error since it usually indicates that your application is in unknown territory and there is no "safe" way to handle it.
If you're writing cryptographic code, panicking for every issue is not good, that's a DoS vector that could be easily exploited. It's safer to handle the error in-band and let the application higher up decide if it should panic, error or continue.
IMO you should use the fallible slice API's in any safety-critical code, such a cryptographic code.
Yes, there is more code, but it does not become a lot more complex, if you need to you can unwrap to explicitly panic. You should still insert asserts to catch issues. But if there is an issue, such as running out of memory or anything else, you can handle it more appropriately than producing a Denial-of-Service issue immediately, which is definitely not good.
The answer would be "it depends on whether you consider denial-of-service a problem". The key detail which makes all the difference is that, unless you're playing with raw pointers (which can only be dereferenced in "unsafe" blocks), the pointer to a buffer slice is always kept together with its length (in a "fat pointer"). Attempting to write through it past the buffer's bounds will result in a Rust panic, which usually aborts the whole process (there are ways to abort just one thread, or even to treat it similarly to a C++ exception, but a library cannot depend on them since the program might be compiled in the panic=abort mode). While that's obviously better than allowing for remote code execution, it still could be considered an issue.
Of course, that's assuming you want a similar API and are writing the code in a similar style, just replacing the direct pointer manipulation with slice manipulation. I don't know whether, in this particular case, more idiomatic Rust code would have avoided the issue. And, of course, the "growable container" approach would completely avoid it, but Rust is also used in places where memory allocation is not allowed, so having a non-allocating API still makes sense.