Currently COM methods are not marked as unsafe, but they should be especially if they take any kind of raw pointers as arguments. COM methods with no arguments could potentially be marked safe since presumably, it's part of the COM ABI that the "this" pointer is always valid if there are valid handles to the interface, but I'm unsure if this reasoning fully holds.
The COM methods are not themselves unsafe. They are guaranteed to be callable. Only those interface methods that include pointer parameters are unsafe and should be marked unsafe. A null interface pointer is represented by None and thus cannot be called.
My statement above about methods that include pointer parameters is not a good indicator whether a method should be marked unsafe. As you pointed out here, the mere presence of pointers is not enough to call something unsafe.
But I am a little skeptical of the argument here #498.
it's probably correct to mark any COM interface that has any parameters (beyond the this pointer) as unsafe.
What does the parameter have to do with it? The implementation could "do unsafe things" regardless of whether or not the function has explicit parameters.
The windows crate lets you call code written in any language across an ABI. The ABI does not guarantee safety of implementation. What it does is guarantee a safe calling convention by virtue of a stable and safe type system. This type system does not have an "unsafe" marker to indicate whether a given call is safe or not. However, Win32, COM, and WinRT APIs are meant to follow strict conventions to ensure the safety and security of the various calls. At worst, APIs that are misused are meant to cause an access violation, which is not unsafe in the Rust sense. Making it harder to use the entire Windows API because some unsafe APIs may exist does not seem very practical. We could however attempt to identify any such unsafe APIs and add some metadata to indicate the risk though. This metadata could then be turned into the unsafe keyword in Rust.
Rust's unsafe keyword does something very specific. By marking a function/method as unsafe, the developer is saying that it is the responsibility of the calling code to maintain certain invariants in order for the call to be safe (i.e., correct). This is not a pass to have buggy code, but a way of signaling that calling the function in certain ways which lead to memory unsafety is a bug in the callers code not the callee. If a function is not marked unsafe and calling it in some way leads to memory unsafety, it is the responsibility of the callee to fix that bug.
What does the parameter have to do with it?
With the above in mind, parameters have quite a bit to do with safety. If a function can get called in a certain way that leads to unsafety, one must ask the question, is that just a bug or is that an invariant the callee is placing on the caller? If the answer is the latter, then the function must be marked unsafe.
For example, imagine the falling COM method call:
myInterface.Foo(1);
If the callee documents that the caller must always call Foo with numbers greater than 0 (otherwise potential memory safety invariants are violated), than Foo must be marked as unsafe. If calling Foo called with the wrong argument leads to some error condition that does not violate memory safety, then Foo does not need to be marked as unsafe. And of course, if Foo can be called with any argument, then Foo is not unsafe.
Making it harder to use the entire Windows API because some unsafe APIs may exist does not seem very practical.
Unfortunately, this is paramount to the promise of Rust. Safety is not about developer productivity. It's a shame that COM does not have enough information to specify whether a method call is safe or not, but the correct response there is not to decide to not follow the Rust safety convention.
It might well be that all Windows APIs with no pointer arguments are safe to call. If that's the case, then we can certainly skip marking them as unsafe. But this code may be used in highly security critical code where unsafe is an extremely important tool to know whether a bit of code is memory safe or not. The promise of Rust is that if you do not use unsafe in your code, and you experience memory safety issue, it must be a bug in someone else's code.
Ryan and I chatted offline. We're going to mark all APIs as unsafe, whether Win32, COM, or WinRT, and regardless of signature. As I mentioned, the Windows ABI guarantees safety in its calling convention but not safety in implementation. This does not mean that Windows APIs are generally unsafe but only that they are not guaranteed to be safe in the strict sense that Rust requires. I would thus expect developers to create many crates that wrap various Windows APIs and easily provide safe and idiomatic Rust libraries that make use of Windows APIs under the hood.
Most helpful comment
Ryan and I chatted offline. We're going to mark all APIs as
unsafe, whether Win32, COM, or WinRT, and regardless of signature. As I mentioned, the Windows ABI guarantees safety in its calling convention but not safety in implementation. This does not mean that Windows APIs are generally unsafe but only that they are not guaranteed to be safe in the strict sense that Rust requires. I would thus expect developers to create many crates that wrap various Windows APIs and easily provide safe and idiomatic Rust libraries that make use of Windows APIs under the hood.