Not knowing C very well, could you clarify what makes it unsafe? Thanks!
Not knowing C very well, could you clarify what makes it unsafe? Thanks!
Just scratching the surface, we have:
- The language doesn't really have vector and strings as data types, they are pointers to memory sections without any kind of protection
- All functions on the standard library deemed as safe, added as mitgation to fix possible memory corruptions have gotchas on their use, there isn't a single one that is safe, specially because all of them expect the developer to never get the buffer size parameters wrong.
- Enumerations are not type safe, decay implicitly to integers when used in numeric context, and all numeric values can be converted into an enumeration, even if there isn't a mapping available
- Implicit numeric convertions everywhere, and since there is no overflow/underflow checking, every single numeric operation can wrap around, or be the source for clever compiler optimizations
- ISO C documents at least around 200 cases of UB, where the compiler can take the liberty to optimize the code as it pleases
- Type casts that convert complex data types into others can be a source of surprises when moving across compilers and platforms
- Speaking of which, even if you restrict yourself to ISO C, without any compiler specific extensions, there are behaviours that are implementation defined, which can vary across compilers and platforms.
- Variables defined as const, aren't really constant and one can subvert their value
- There is no null checking, so whatever happens depends on the platform.
This is just a short overview, open the man page for GCC or clang and go through the list of all warnings that you can enable to try to write safer code, specially all that are enabled via -Wall and -Wextra.
All the above flaws are also present in Objective-C, Objective-C++ and C++, due to their copy-paste compatibility with C (yes C++ isn't 100% compatible).
Compilers have the freedom to place them into readonly memory segments, either in the case of static data, in the heap (mark the pages as such for safety), in embedded static const data can even be mapped into ROM chips, so who knows what happens if the compiler has decided to implement const data that way, or what the linker scripts are doing.
There's also stuff that obviously can't end up in rodata, such as const locals that are initialized from arguments or I/O. Sometimes people assume that this means that casting away constness is legal in such cases.
edit: eh sorry I wasn't thinking straight, you of course need unsafe to cast the argv itself to a type that has a seperate argc as well. Assuming such a type is available, if it's not its implementation would also have unsafe all over the place.
Maybe to answer the underlying question. What makes it unsafe is that in C it is assumed the programmer knows to keep all indexes into argv under argc. In Rust such an assumption must be made explicit by specifying "unsafe". It is idiomatic Rust to have all instances of "unsafe" in libraries whose implementation is vetted by the community, so ideally there are little to no instances of "unsafe" in the application logic itself. Rust's compiler and type system have various tricks that reduce the amount of "unsafe" you would think you'd need for even quite complex problems.
In rust, unsafe means accessing memory that's already freed or unallocated or things like that. You can look up the definition for the full definition.
I think the comment you replied to mistakenly used the term "unsafe" (that's part of the reason I dislike the term; it can mean multiple things). In rust context though, it isn't unsafe to index an array that's out of bounds. I.e. if argc=10 and you call argv[99], that will crash your program but isn't considered "unsafe".
Then if you wanted to handle dynamically set environment variables you'll need to call into your libc implementation, which crosses an ffi boundary, which means rust doesn't know about what that code is doing and therefor it requires `unsafe`.
edit: Question for others - is main a separate stackframe? I actually don't recall.
arr[n] == *(arr + n) == n[arr]
All these forms are valid C and gcc will happily compile them all without complaining.