From 6c431f4e59892f824b703193d7466bc885bf4ad2 Mon Sep 17 00:00:00 2001 From: Immo Landwerth Date: Thu, 9 Jul 2020 21:19:36 -0700 Subject: [PATCH 1/7] Add proposal to mark Windows-specific APIs --- .../windows-specific-apis.md | 475 ++++++++++++++++++ 1 file changed, 475 insertions(+) create mode 100644 accepted/2020/windows-specific-apis/windows-specific-apis.md diff --git a/accepted/2020/windows-specific-apis/windows-specific-apis.md b/accepted/2020/windows-specific-apis/windows-specific-apis.md new file mode 100644 index 000000000..b04ce5333 --- /dev/null +++ b/accepted/2020/windows-specific-apis/windows-specific-apis.md @@ -0,0 +1,475 @@ +# Marking Windows-only APIs + +As discussed in [dotnet/runtime#33331] we're adding an analyzer to detect usage +of platform-specific APIs. This analyzer requires a custom attribute applied to +method, containing type, or assembly. + +In this proposal I'm covering which APIs we mark as Windows-specific an how. It +was largely informed by the work put into [platform-compat]. + +[dotnet/runtime#33331]: https://github.com/dotnet/runtime/issues/33331 +[platform-compat]: https://github.com/dotnet/platform-compat + +## Which Windows version will we use? + +The lowest version of Windows that we support with .NET Core is Windows 7. Also, +we generally don't expose functionality that requires a higher version of +Windows. + +Thus, I propose that we use `7.0` as the minimum version number instead of +hunting down which Windows version actually introduced a given feature, which +means the custom attribute will look as follows: + +```C# +[MinimumOSPlatform("windows7.0")] +``` + +## Entire assemblies + +There is a set of assemblies that we can mark wholesale as being +Windows-specific: + +> **OPEN**: Should `System.Threading.Overlapped.dll` be removed? +> **OPEN**: I was told that part of `DirectoryServices` is now cross-platform. Is that true? + +* **Microsoft.Win32.Registry.dll** +* **Microsoft.Win32.Registry.AccessControl.dll** +* **Microsoft.Win32.SystemEvents.dll** +* **System.Diagnostics.EventLog.dll** +* **System.Diagnostics.PerformanceCounter.dll** +* **System.DirectoryServices.dll** +* **System.DirectoryServices.AccountManagement.dll** +* **System.DirectoryServices.Protocols.dll** +* **System.IO.FileSystem.AccessControl.dll** +* **System.IO.FileSystem.DriveInfo.dll** +* **System.IO.Pipes.AccessControl.dll** +* **System.Management.dll** +* **System.Net.Http.WinHttpHandler.dll** +* **System.Runtime.InteropServices.WindowsRuntime.dll** +* **System.Security.AccessControl.dll** +* **System.Security.Cryptography.Cng.dll** +* **System.Security.Cryptography.ProtectedData.dll** +* **System.Security.Principal.Windows.dll** +* **System.ServiceProcess.ServiceController.dll** +* **System.Threading.AccessControl.dll** +* **System.Threading.Overlapped.dll** + +## Specific APIs + +### System + +> **OPEN** Should we treat those as Windows-only or should we consider them as +> partially portable? + +* **Console** + - `Beep(Int32, Int32)` + - `get_CapsLock()` + - `get_CursorVisible()` + - `get_NumberLock()` + - `get_Title()` + - `MoveBufferArea(Int32, Int32, Int32, Int32, Int32, Int32)` + - `MoveBufferArea(Int32, Int32, Int32, Int32, Int32, Int32, Char, ConsoleColor, ConsoleColor)` + - `set_BufferHeight(Int32)` + - `set_BufferWidth(Int32)` + - `set_CursorSize(Int32)` + - `set_WindowHeight(Int32)` + - `set_WindowLeft(Int32)` + - `set_WindowTop(Int32)` + - `set_WindowWidth(Int32)` + - `SetBufferSize(Int32, Int32)` + - `SetWindowPosition(Int32, Int32)` + - `SetWindowSize(Int32, Int32)` + +### System.Configuration + +> **OPEN** Should we mark the entire type? + +* **DpapiProtectedConfigurationProvider** + - `Decrypt(XmlNode)` + - `Encrypt(XmlNode)` + +### System.Diagnostics + +* **Process** + - `GetProcessById(Int32, String)` + - `GetProcesses(String)` + - `GetProcessesByName(String, String)` + - `set_MaxWorkingSet(IntPtr)` + - `set_MinWorkingSet(IntPtr)` + - `Start(String, String, SecureString, String)` + - `Start(String, String, String, SecureString, String)` +* **ProcessStartInfo** + - `get_Domain()` + - `get_LoadUserProfile()` + - `get_Password()` + - `get_PasswordInClearText()` + - `set_Domain(String)` + - `set_LoadUserProfile(Boolean)` + - `set_Password(SecureString)` + - `set_PasswordInClearText(String)` +* **ProcessThread** + - `set_PriorityLevel(ThreadPriorityLevel)` + - `set_ProcessorAffinity(IntPtr)` + +### System.Drawing + +> **OPEN** Should we mark the entire type? + +* **Graphics** + - `CopyFromScreen(Int32, Int32, Int32, Int32, Size)` + - `CopyFromScreen(Int32, Int32, Int32, Int32, Size, CopyPixelOperation)` + - `CopyFromScreen(Point, Point, Size)` + - `CopyFromScreen(Point, Point, Size, CopyPixelOperation)` + +### System.IO.MemoryMappedFiles + +* **MemoryMappedFile** + - `CreateFromFile(FileStream, String, Int64, MemoryMappedFileAccess, HandleInheritability, Boolean)` + - `CreateFromFile(String)` + - `CreateFromFile(String, FileMode)` + - `CreateFromFile(String, FileMode, String)` + - `CreateFromFile(String, FileMode, String, Int64)` + - `CreateFromFile(String, FileMode, String, Int64, MemoryMappedFileAccess)` + - `CreateNew(String, Int64)` + - `CreateNew(String, Int64, MemoryMappedFileAccess)` + - `CreateNew(String, Int64, MemoryMappedFileAccess, MemoryMappedFileOptions, HandleInheritability)` + - `CreateOrOpen(String, Int64)` + - `CreateOrOpen(String, Int64, MemoryMappedFileAccess)` + - `CreateOrOpen(String, Int64, MemoryMappedFileAccess, MemoryMappedFileOptions, HandleInheritability)` + - `OpenExisting(String)` + - `OpenExisting(String, MemoryMappedFileRights)` + - `OpenExisting(String, MemoryMappedFileRights, HandleInheritability)` + +### System.IO.Pipes + +* **NamedPipeClientStream** + - `get_NumberOfServerInstances()` +* **NamedPipeServerStream** + - `RunAsClient(PipeStreamImpersonationWorker)` +* **PipeStream** + - `set_ReadMode(PipeTransmissionMode)` + - `WaitForPipeDrain()` +* **PipeTransmissionMode** + - `Message` + +### System.IO.Ports + +> **OPEN** Should we mark the entire type/assembly? + +* **SerialDataReceivedEventArgs** + - `get_EventType()` +* **SerialErrorReceivedEventArgs** + - `get_EventType()` +* **SerialPinChangedEventArgs** + - `get_EventType()` +* **SerialPort** + - `.ctor()` + - `.ctor(IContainer)` + - `.ctor(String)` + - `.ctor(String, Int32)` + - `.ctor(String, Int32, Parity)` + - `.ctor(String, Int32, Parity, Int32)` + - `.ctor(String, Int32, Parity, Int32, StopBits)` + - `Close()` + - `DiscardInBuffer()` + - `DiscardOutBuffer()` + - `get_BaseStream()` + - `get_BaudRate()` + - `get_BreakState()` + - `get_BytesToRead()` + - `get_BytesToWrite()` + - `get_CDHolding()` + - `get_CtsHolding()` + - `get_DataBits()` + - `get_DiscardNull()` + - `get_DsrHolding()` + - `get_DtrEnable()` + - `get_Encoding()` + - `get_Handshake()` + - `get_IsOpen()` + - `get_NewLine()` + - `get_Parity()` + - `get_ParityReplace()` + - `get_PortName()` + - `get_ReadBufferSize()` + - `get_ReadTimeout()` + - `get_ReceivedBytesThreshold()` + - `get_RtsEnable()` + - `get_StopBits()` + - `get_WriteBufferSize()` + - `get_WriteTimeout()` + - `GetPortNames()` + - `Open()` + - `Read(Byte[], Int32, Int32)` + - `Read(Char[], Int32, Int32)` + - `ReadByte()` + - `ReadChar()` + - `ReadExisting()` + - `ReadLine()` + - `ReadTo(String)` + - `set_BaudRate(Int32)` + - `set_BreakState(Boolean)` + - `set_DataBits(Int32)` + - `set_DiscardNull(Boolean)` + - `set_DtrEnable(Boolean)` + - `set_Encoding(Encoding)` + - `set_Handshake(Handshake)` + - `set_NewLine(String)` + - `set_Parity(Parity)` + - `set_ParityReplace(Byte)` + - `set_PortName(String)` + - `set_ReadBufferSize(Int32)` + - `set_ReadTimeout(Int32)` + - `set_ReceivedBytesThreshold(Int32)` + - `set_RtsEnable(Boolean)` + - `set_StopBits(StopBits)` + - `set_WriteBufferSize(Int32)` + - `set_WriteTimeout(Int32)` + - `Write(Byte[], Int32, Int32)` + - `Write(Char[], Int32, Int32)` + - `Write(String)` + - `WriteLine(String)` + +### System.Net + +* **HttpListenerTimeoutManager** + - `set_EntityBody(TimeSpan)` + - `set_HeaderWait(TimeSpan)` + - `set_MinSendBytesPerSecond(Int64)` + - `set_RequestQueue(TimeSpan)` +* **IPEndPoint** + - `Create(SocketAddress)` +* **SocketAddress** + - `.ctor(AddressFamily)` + - `.ctor(AddressFamily, Int32)` + - `get_Family()` + - `ToString()` + +### System.Net.Sockets + +* **Socket** + - `AcceptAsync(SocketAsyncEventArgs)` + - `BeginAccept(Int32, AsyncCallback, Object)` + - `BeginAccept(Socket, Int32, AsyncCallback, Object)` + - `BeginReceiveFrom(Byte[], Int32, Int32, SocketFlags, EndPoint, AsyncCallback, Object)` + - `BeginReceiveMessageFrom(Byte[], Int32, Int32, SocketFlags, EndPoint, AsyncCallback, Object)` + - `IOControl(Int32, Byte[], Byte[])` + - `IOControl(IOControlCode, Byte[], Byte[])` + - `ReceiveFrom(Byte[], EndPoint)` + - `ReceiveFrom(Byte[], Int32, Int32, SocketFlags, EndPoint)` + - `ReceiveFrom(Byte[], Int32, SocketFlags, EndPoint)` + - `ReceiveFrom(Byte[], SocketFlags, EndPoint)` + - `ReceiveFromAsync(SocketAsyncEventArgs)` + - `ReceiveMessageFrom(Byte[], Int32, Int32, SocketFlags, EndPoint, IPPacketInformation)` + - `ReceiveMessageFromAsync(SocketAsyncEventArgs)` + - `SetIPProtectionLevel(IPProtectionLevel)` +* **SocketTaskExtensions** + - `AcceptAsync(Socket)` + - `AcceptAsync(Socket, Socket)` + - `ReceiveFromAsync(Socket, ArraySegment, SocketFlags, EndPoint)` + - `ReceiveMessageFromAsync(Socket, ArraySegment, SocketFlags, EndPoint)` +* **TcpListener** + - `AllowNatTraversal(Boolean)` +* **TransmitFileOptions** + - `Disconnect` + - `ReuseSocket` + - `UseKernelApc` + - `UseSystemThread` + - `WriteBehind` +* **UdpClient** + - `AllowNatTraversal(Boolean)` + +### System.Runtime.InteropServices + +* **DispatchWrapper** + - `get_WrappedObject()` +* **Marshal** + - `AddRef(IntPtr)` + - `BindToMoniker(String)` + - `ChangeWrapperHandleStrength(Object, Boolean)` + - `CreateAggregatedObject(IntPtr, Object)` + - `CreateAggregatedObject(IntPtr, T)` + - `FinalReleaseComObject(Object)` + - `GetComInterfaceForObject(Object, Type)` + - `GetComInterfaceForObject(Object, Type, CustomQueryInterfaceMode)` + - `GetComInterfaceForObject(T)` + - `GetIUnknownForObject(Object)` + - `GetNativeVariantForObject(Object, IntPtr)` + - `GetNativeVariantForObject(T, IntPtr)` + - `GetObjectForIUnknown(IntPtr)` + - `GetObjectForNativeVariant(IntPtr)` + - `GetObjectForNativeVariant(IntPtr)` + - `GetObjectsForNativeVariants(IntPtr, Int32)` + - `GetObjectsForNativeVariants(IntPtr, Int32)` + - `GetStartComSlot(Type)` + - `GetTypedObjectForIUnknown(IntPtr, Type)` + - `GetTypeFromCLSID(Guid)` + - `GetTypeInfoName(ITypeInfo)` + - `GetUniqueObjectForIUnknown(IntPtr)` + - `QueryInterface(IntPtr, Guid, IntPtr)` + - `Release(IntPtr)` + - `ReleaseComObject(Object)` + +### System.Security.Cryptography + +* **CspKeyContainerInfo** + - `get_Accessible()` + - `get_Exportable()` + - `get_HardwareDevice()` + - `get_KeyContainerName()` + - `get_KeyNumber()` + - `get_MachineKeyStore()` + - `get_Protected()` + - `get_ProviderName()` + - `get_ProviderType()` + - `get_RandomlyGenerated()` + - `get_Removable()` + - `get_UniqueKeyContainerName()` +* **DSACryptoServiceProvider** + - `get_CspKeyContainerInfo()` + - `ImportCspBlob(Byte[])` +* **PasswordDeriveBytes** + - `CryptDeriveKey(String, String, Int32, Byte[])` +* **RC2CryptoServiceProvider** + - `set_UseSalt(Boolean)` +* **RSACryptoServiceProvider** + - `.ctor(CspParameters)` + - `.ctor(Int32, CspParameters)` + - `get_CspKeyContainerInfo()` + - `ImportCspBlob(Byte[])` + +### System.Security.Cryptography.X509Certificates + +* **X509Chain** + - `.ctor(IntPtr)` + +### System.ServiceModel + +* **ActionNotSupportedException** + - `.ctor(SerializationInfo, StreamingContext)` + - `.ctor(String, Exception)` +* **BasicHttpBinding** + - `.ctor()` + - `.ctor(BasicHttpSecurityMode)` + - `CreateBindingElements()` +* **BasicHttpsBinding** + - `.ctor()` + - `.ctor(BasicHttpsSecurityMode)` + - `CreateBindingElements()` +* **ChannelFactory** + - `.ctor(Binding, EndpointAddress)` + - `.ctor(ServiceEndpoint)` + - `.ctor(String)` + - `.ctor(String, EndpointAddress)` + - `ApplyConfiguration(String)` + - `CreateDescription()` + - `InitializeEndpoint(Binding, EndpointAddress)` + - `InitializeEndpoint(ServiceEndpoint)` + - `InitializeEndpoint(String, EndpointAddress)` +* **ChannelTerminatedException** + - `.ctor(SerializationInfo, StreamingContext)` +* **ClientBase** + - `.ctor()` + - `.ctor(String)` + - `.ctor(String, EndpointAddress)` + - `.ctor(String, String)` +* **ClientBase+ChannelBase** + - `EndInvoke(String, Object[], IAsyncResult)` +* **ClientCredentialsSecurityTokenManager** + - `CreateSecurityTokenAuthenticator(SecurityTokenRequirement, SecurityTokenResolver)` + - `CreateSecurityTokenProvider(SecurityTokenRequirement)` + - `CreateSecurityTokenSerializer(SecurityTokenVersion)` +* **CommunicationException** + - `.ctor(SerializationInfo, StreamingContext)` +* **CommunicationObjectAbortedException** + - `.ctor(SerializationInfo, StreamingContext)` +* **CommunicationObjectFaultedException** + - `.ctor(SerializationInfo, StreamingContext)` +* **DuplexChannelFactory** + - `.ctor(InstanceContext, Binding, EndpointAddress)` + - `.ctor(InstanceContext, Binding, String)` + - `.ctor(InstanceContext, String)` + - `.ctor(InstanceContext, String, EndpointAddress)` +* **DuplexClientBase** + - `.ctor(InstanceContext)` + - `.ctor(InstanceContext, String)` + - `.ctor(InstanceContext, String, EndpointAddress)` + - `.ctor(InstanceContext, String, String)` +* **EndpointAddress** + - `ApplyTo(Message)` +* **EndpointIdentity** + - `Equals(Object)` + - `GetHashCode()` +* **EndpointNotFoundException** + - `.ctor(SerializationInfo, StreamingContext)` +* **FaultException** + - `.ctor(SerializationInfo, StreamingContext)` +* **InvalidMessageContractException** + - `.ctor(SerializationInfo, StreamingContext)` +* **MessageHeaderException** + - `.ctor(SerializationInfo, StreamingContext)` +* **MessageSecurityOverTcp** + - `get_ClientCredentialType()` + - `set_ClientCredentialType(MessageCredentialType)` +* **NetHttpBinding** + - `CreateBindingElements()` +* **NetHttpsBinding** + - `.ctor()` + - `.ctor(BasicHttpsSecurityMode)` + - `CreateBindingElements()` +* **NetTcpBinding** + - `.ctor(String)` + - `CreateBindingElements()` +* **ProtocolException** + - `.ctor(SerializationInfo, StreamingContext)` +* **QuotaExceededException** + - `.ctor(SerializationInfo, StreamingContext)` +* **ServerTooBusyException** + - `.ctor(SerializationInfo, StreamingContext)` +* **ServiceActivationException** + - `.ctor(SerializationInfo, StreamingContext)` + +### System.ServiceModel.Channels + +* **AddressHeader** + - `Equals(Object)` + - `GetHashCode()` +* **MessageHeaders** + - `set_To(Uri)` +* **SecurityBindingElement** + - `CreateSecureConversationBindingElement(SecurityBindingElement)` +* **TransportSecurityBindingElement** + - `GetProperty(BindingContext)` +* **WebSocketTransportSettings** + - `get_DisablePayloadMasking()` + - `set_DisablePayloadMasking(Boolean)` + +### System.ServiceModel.Security + +* **MessageSecurityException** + - `.ctor(SerializationInfo, StreamingContext)` +* **SecurityAccessDeniedException** + - `.ctor(SerializationInfo, StreamingContext)` +* **SecurityNegotiationException** + - `.ctor(SerializationInfo, StreamingContext)` +* **X509ServiceCertificateAuthentication** + - `set_CertificateValidationMode(X509CertificateValidationMode)` + +### System.Threading + +* **EventWaitHandle** + - `.ctor(Boolean, EventResetMode, String)` + - `.ctor(Boolean, EventResetMode, String, Boolean)` + - `OpenExisting(String)` + - `TryOpenExisting(String, EventWaitHandle)` +* **Semaphore** + - `.ctor(Int32, Int32, String)` + - `.ctor(Int32, Int32, String, Boolean)` + - `OpenExisting(String)` + - `TryOpenExisting(String, Semaphore)` +* **Thread** + - `SetApartmentState(ApartmentState)` +* **WaitHandle** + - `SignalAndWait(WaitHandle, WaitHandle)` + - `SignalAndWait(WaitHandle, WaitHandle, Int32, Boolean)` + - `SignalAndWait(WaitHandle, WaitHandle, TimeSpan, Boolean)` \ No newline at end of file From 34bb95ea30eefe032439f1277e68d7a8116f8e4d Mon Sep 17 00:00:00 2001 From: jeffhandley Date: Mon, 13 Jul 2020 10:23:20 -0700 Subject: [PATCH 2/7] address review feedback for windows-specific APIs --- .../windows-specific-apis.md | 188 ++++-------------- 1 file changed, 35 insertions(+), 153 deletions(-) diff --git a/accepted/2020/windows-specific-apis/windows-specific-apis.md b/accepted/2020/windows-specific-apis/windows-specific-apis.md index b04ce5333..8323ecf57 100644 --- a/accepted/2020/windows-specific-apis/windows-specific-apis.md +++ b/accepted/2020/windows-specific-apis/windows-specific-apis.md @@ -30,7 +30,6 @@ There is a set of assemblies that we can mark wholesale as being Windows-specific: > **OPEN**: Should `System.Threading.Overlapped.dll` be removed? -> **OPEN**: I was told that part of `DirectoryServices` is now cross-platform. Is that true? * **Microsoft.Win32.Registry.dll** * **Microsoft.Win32.Registry.AccessControl.dll** @@ -39,19 +38,16 @@ Windows-specific: * **System.Diagnostics.PerformanceCounter.dll** * **System.DirectoryServices.dll** * **System.DirectoryServices.AccountManagement.dll** -* **System.DirectoryServices.Protocols.dll** * **System.IO.FileSystem.AccessControl.dll** -* **System.IO.FileSystem.DriveInfo.dll** * **System.IO.Pipes.AccessControl.dll** * **System.Management.dll** -* **System.Net.Http.WinHttpHandler.dll** -* **System.Runtime.InteropServices.WindowsRuntime.dll** +* **System.Net.Http.WinHttpHandler.dll** (using an internal attribute within the assembly) * **System.Security.AccessControl.dll** * **System.Security.Cryptography.Cng.dll** -* **System.Security.Cryptography.ProtectedData.dll** +* **System.Security.Cryptography.ProtectedData.dll** (using an internal attribute within the assembly) * **System.Security.Principal.Windows.dll** * **System.ServiceProcess.ServiceController.dll** -* **System.Threading.AccessControl.dll** +* **System.Threading.AccessControl.dll** (using an internal attribute within the assembly) * **System.Threading.Overlapped.dll** ## Specific APIs @@ -82,18 +78,11 @@ Windows-specific: ### System.Configuration -> **OPEN** Should we mark the entire type? - * **DpapiProtectedConfigurationProvider** - - `Decrypt(XmlNode)` - - `Encrypt(XmlNode)` ### System.Diagnostics * **Process** - - `GetProcessById(Int32, String)` - - `GetProcesses(String)` - - `GetProcessesByName(String, String)` - `set_MaxWorkingSet(IntPtr)` - `set_MinWorkingSet(IntPtr)` - `Start(String, String, SecureString, String)` @@ -111,31 +100,9 @@ Windows-specific: - `set_PriorityLevel(ThreadPriorityLevel)` - `set_ProcessorAffinity(IntPtr)` -### System.Drawing - -> **OPEN** Should we mark the entire type? - -* **Graphics** - - `CopyFromScreen(Int32, Int32, Int32, Int32, Size)` - - `CopyFromScreen(Int32, Int32, Int32, Int32, Size, CopyPixelOperation)` - - `CopyFromScreen(Point, Point, Size)` - - `CopyFromScreen(Point, Point, Size, CopyPixelOperation)` - ### System.IO.MemoryMappedFiles * **MemoryMappedFile** - - `CreateFromFile(FileStream, String, Int64, MemoryMappedFileAccess, HandleInheritability, Boolean)` - - `CreateFromFile(String)` - - `CreateFromFile(String, FileMode)` - - `CreateFromFile(String, FileMode, String)` - - `CreateFromFile(String, FileMode, String, Int64)` - - `CreateFromFile(String, FileMode, String, Int64, MemoryMappedFileAccess)` - - `CreateNew(String, Int64)` - - `CreateNew(String, Int64, MemoryMappedFileAccess)` - - `CreateNew(String, Int64, MemoryMappedFileAccess, MemoryMappedFileOptions, HandleInheritability)` - - `CreateOrOpen(String, Int64)` - - `CreateOrOpen(String, Int64, MemoryMappedFileAccess)` - - `CreateOrOpen(String, Int64, MemoryMappedFileAccess, MemoryMappedFileOptions, HandleInheritability)` - `OpenExisting(String)` - `OpenExisting(String, MemoryMappedFileRights)` - `OpenExisting(String, MemoryMappedFileRights, HandleInheritability)` @@ -144,92 +111,11 @@ Windows-specific: * **NamedPipeClientStream** - `get_NumberOfServerInstances()` -* **NamedPipeServerStream** - - `RunAsClient(PipeStreamImpersonationWorker)` * **PipeStream** - - `set_ReadMode(PipeTransmissionMode)` - `WaitForPipeDrain()` * **PipeTransmissionMode** - `Message` -### System.IO.Ports - -> **OPEN** Should we mark the entire type/assembly? - -* **SerialDataReceivedEventArgs** - - `get_EventType()` -* **SerialErrorReceivedEventArgs** - - `get_EventType()` -* **SerialPinChangedEventArgs** - - `get_EventType()` -* **SerialPort** - - `.ctor()` - - `.ctor(IContainer)` - - `.ctor(String)` - - `.ctor(String, Int32)` - - `.ctor(String, Int32, Parity)` - - `.ctor(String, Int32, Parity, Int32)` - - `.ctor(String, Int32, Parity, Int32, StopBits)` - - `Close()` - - `DiscardInBuffer()` - - `DiscardOutBuffer()` - - `get_BaseStream()` - - `get_BaudRate()` - - `get_BreakState()` - - `get_BytesToRead()` - - `get_BytesToWrite()` - - `get_CDHolding()` - - `get_CtsHolding()` - - `get_DataBits()` - - `get_DiscardNull()` - - `get_DsrHolding()` - - `get_DtrEnable()` - - `get_Encoding()` - - `get_Handshake()` - - `get_IsOpen()` - - `get_NewLine()` - - `get_Parity()` - - `get_ParityReplace()` - - `get_PortName()` - - `get_ReadBufferSize()` - - `get_ReadTimeout()` - - `get_ReceivedBytesThreshold()` - - `get_RtsEnable()` - - `get_StopBits()` - - `get_WriteBufferSize()` - - `get_WriteTimeout()` - - `GetPortNames()` - - `Open()` - - `Read(Byte[], Int32, Int32)` - - `Read(Char[], Int32, Int32)` - - `ReadByte()` - - `ReadChar()` - - `ReadExisting()` - - `ReadLine()` - - `ReadTo(String)` - - `set_BaudRate(Int32)` - - `set_BreakState(Boolean)` - - `set_DataBits(Int32)` - - `set_DiscardNull(Boolean)` - - `set_DtrEnable(Boolean)` - - `set_Encoding(Encoding)` - - `set_Handshake(Handshake)` - - `set_NewLine(String)` - - `set_Parity(Parity)` - - `set_ParityReplace(Byte)` - - `set_PortName(String)` - - `set_ReadBufferSize(Int32)` - - `set_ReadTimeout(Int32)` - - `set_ReceivedBytesThreshold(Int32)` - - `set_RtsEnable(Boolean)` - - `set_StopBits(StopBits)` - - `set_WriteBufferSize(Int32)` - - `set_WriteTimeout(Int32)` - - `Write(Byte[], Int32, Int32)` - - `Write(Char[], Int32, Int32)` - - `Write(String)` - - `WriteLine(String)` - ### System.Net * **HttpListenerTimeoutManager** @@ -237,42 +123,46 @@ Windows-specific: - `set_HeaderWait(TimeSpan)` - `set_MinSendBytesPerSecond(Int64)` - `set_RequestQueue(TimeSpan)` -* **IPEndPoint** - - `Create(SocketAddress)` -* **SocketAddress** - - `.ctor(AddressFamily)` - - `.ctor(AddressFamily, Int32)` - - `get_Family()` - - `ToString()` ### System.Net.Sockets +* **IOControlCode** (Enum -- _all members except `NonBlockingIO`, `DataToRead`, and `OobDataRead`_) + - `AsyncIO` + - `AssociateHandle` + - `EnableCircularQueuing` + - `Flush` + - `GetBroadcastAddress` + - `GetExtensionFunctionPointer` + - `GetQos` + - `GetGroupQos` + - `MultipointLoopback` + - `MulticastScope` + - `SetQos` + - `SetGroupQos` + - `TranslateHandle` + - `RoutingInterfaceQuery` + - `RoutingInterfaceChange` + - `AddressListQuery` + - `AddressListChange` + - `QueryTargetPnpHandle` + - `NamespaceChange` + - `AddressListSort` + - `ReceiveAll` + - `ReceiveAllMulticast` + - `ReceiveAllIgmpMulticast` + - `KeepAliveValues` + - `AbsorbRouterAlert` + - `UnicastInterface` + - `LimitBroadcasts` + - `BindToInterface` + - `MulticastInterface` + - `AddMulticastGroupOnInterface` + - `DeleteMulticastGroupFromInterface` * **Socket** - - `AcceptAsync(SocketAsyncEventArgs)` - - `BeginAccept(Int32, AsyncCallback, Object)` - - `BeginAccept(Socket, Int32, AsyncCallback, Object)` - - `BeginReceiveFrom(Byte[], Int32, Int32, SocketFlags, EndPoint, AsyncCallback, Object)` - - `BeginReceiveMessageFrom(Byte[], Int32, Int32, SocketFlags, EndPoint, AsyncCallback, Object)` - - `IOControl(Int32, Byte[], Byte[])` - - `IOControl(IOControlCode, Byte[], Byte[])` - - `ReceiveFrom(Byte[], EndPoint)` - - `ReceiveFrom(Byte[], Int32, Int32, SocketFlags, EndPoint)` - - `ReceiveFrom(Byte[], Int32, SocketFlags, EndPoint)` - - `ReceiveFrom(Byte[], SocketFlags, EndPoint)` - - `ReceiveFromAsync(SocketAsyncEventArgs)` - - `ReceiveMessageFrom(Byte[], Int32, Int32, SocketFlags, EndPoint, IPPacketInformation)` - - `ReceiveMessageFromAsync(SocketAsyncEventArgs)` - `SetIPProtectionLevel(IPProtectionLevel)` -* **SocketTaskExtensions** - - `AcceptAsync(Socket)` - - `AcceptAsync(Socket, Socket)` - - `ReceiveFromAsync(Socket, ArraySegment, SocketFlags, EndPoint)` - - `ReceiveMessageFromAsync(Socket, ArraySegment, SocketFlags, EndPoint)` * **TcpListener** - `AllowNatTraversal(Boolean)` * **TransmitFileOptions** - - `Disconnect` - - `ReuseSocket` - `UseKernelApc` - `UseSystemThread` - `WriteBehind` @@ -458,18 +348,10 @@ Windows-specific: ### System.Threading * **EventWaitHandle** - - `.ctor(Boolean, EventResetMode, String)` - - `.ctor(Boolean, EventResetMode, String, Boolean)` - `OpenExisting(String)` - `TryOpenExisting(String, EventWaitHandle)` * **Semaphore** - - `.ctor(Int32, Int32, String)` - - `.ctor(Int32, Int32, String, Boolean)` - `OpenExisting(String)` - `TryOpenExisting(String, Semaphore)` * **Thread** - `SetApartmentState(ApartmentState)` -* **WaitHandle** - - `SignalAndWait(WaitHandle, WaitHandle)` - - `SignalAndWait(WaitHandle, WaitHandle, Int32, Boolean)` - - `SignalAndWait(WaitHandle, WaitHandle, TimeSpan, Boolean)` \ No newline at end of file From 8374f5f842d62ecedd6638a3d6a91b688e9340ce Mon Sep 17 00:00:00 2001 From: jeffhandley Date: Mon, 13 Jul 2020 11:19:06 -0700 Subject: [PATCH 3/7] Add Windows-only MemoryMappedFile.CreateOrOpen back into the list --- accepted/2020/windows-specific-apis/windows-specific-apis.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/accepted/2020/windows-specific-apis/windows-specific-apis.md b/accepted/2020/windows-specific-apis/windows-specific-apis.md index 8323ecf57..87e9ac6f6 100644 --- a/accepted/2020/windows-specific-apis/windows-specific-apis.md +++ b/accepted/2020/windows-specific-apis/windows-specific-apis.md @@ -103,6 +103,9 @@ Windows-specific: ### System.IO.MemoryMappedFiles * **MemoryMappedFile** + - `CreateOrOpen(String, Int64)` + - `CreateOrOpen(String, Int64, MemoryMappedFileAccess)` + - `CreateOrOpen(String, Int64, MemoryMappedFileAccess, MemoryMappedFileOptions, HandleInheritability)` - `OpenExisting(String)` - `OpenExisting(String, MemoryMappedFileRights)` - `OpenExisting(String, MemoryMappedFileRights, HandleInheritability)` From b0754a9e472f801762b038068c14ec923402dc4e Mon Sep 17 00:00:00 2001 From: Immo Landwerth Date: Tue, 14 Jul 2020 07:53:55 -0700 Subject: [PATCH 4/7] Add additional notes from review --- .../windows-specific-apis.md | 52 +++++++++++++------ 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/accepted/2020/windows-specific-apis/windows-specific-apis.md b/accepted/2020/windows-specific-apis/windows-specific-apis.md index 87e9ac6f6..d9180e8b1 100644 --- a/accepted/2020/windows-specific-apis/windows-specific-apis.md +++ b/accepted/2020/windows-specific-apis/windows-specific-apis.md @@ -24,6 +24,31 @@ means the custom attribute will look as follows: [MinimumOSPlatform("windows7.0")] ``` +## .NET Standard 2.0 assemblies + +Marking APIs as Windows specific requires the `MinimumOSPlatformAttribute`. +Thankfully, this doesn't require unification (nor a public type) so the analyzer +can simply check for the attribute by name. Thus, in order to mark .NET Standard +2.0 assemblies, we'll include an internal version of +`MinimumOSPlatformAttribute` in those assemblies. + +## Open Issues + +* We should run the tool again .NET 5 +* We currently don't have a way to mark an API as unsupported on a given + platform. That is, the design is agnostic (no attribute) or inclusion list + (attributes with support platforms). We need to add this feature to support + Blazor. + - `System.Security.Cryptography.OpenSSL` should be marked as not supported + on Windows +* We should consider special casing enum values in the analyzer and only + complain about assignments/passing to parameters). We can probably get away + with marking the constructors of the types that override with platform + specific implementations. +* We should consider how marking virtual methods work in the analyzer. +* We need to find a good code base for running this analyzer on as + dotnet/runtime, dotnet/roslyn are mostly not consuming platform-specific APIs. + ## Entire assemblies There is a set of assemblies that we can mark wholesale as being @@ -41,13 +66,13 @@ Windows-specific: * **System.IO.FileSystem.AccessControl.dll** * **System.IO.Pipes.AccessControl.dll** * **System.Management.dll** -* **System.Net.Http.WinHttpHandler.dll** (using an internal attribute within the assembly) +* **System.Net.Http.WinHttpHandler.dll** * **System.Security.AccessControl.dll** * **System.Security.Cryptography.Cng.dll** -* **System.Security.Cryptography.ProtectedData.dll** (using an internal attribute within the assembly) +* **System.Security.Cryptography.ProtectedData.dll** * **System.Security.Principal.Windows.dll** * **System.ServiceProcess.ServiceController.dll** -* **System.Threading.AccessControl.dll** (using an internal attribute within the assembly) +* **System.Threading.AccessControl.dll** * **System.Threading.Overlapped.dll** ## Specific APIs @@ -100,6 +125,11 @@ Windows-specific: - `set_PriorityLevel(ThreadPriorityLevel)` - `set_ProcessorAffinity(IntPtr)` +### System.IO + +* **DriveInfo** + - `set_VolumeLabel(String)` + ### System.IO.MemoryMappedFiles * **MemoryMappedFile** @@ -163,6 +193,7 @@ Windows-specific: - `DeleteMulticastGroupFromInterface` * **Socket** - `SetIPProtectionLevel(IPProtectionLevel)` + - `DuplicateAndClose` * **TcpListener** - `AllowNatTraversal(Boolean)` * **TransmitFileOptions** @@ -206,21 +237,8 @@ Windows-specific: ### System.Security.Cryptography * **CspKeyContainerInfo** - - `get_Accessible()` - - `get_Exportable()` - - `get_HardwareDevice()` - - `get_KeyContainerName()` - - `get_KeyNumber()` - - `get_MachineKeyStore()` - - `get_Protected()` - - `get_ProviderName()` - - `get_ProviderType()` - - `get_RandomlyGenerated()` - - `get_Removable()` - - `get_UniqueKeyContainerName()` * **DSACryptoServiceProvider** - `get_CspKeyContainerInfo()` - - `ImportCspBlob(Byte[])` * **PasswordDeriveBytes** - `CryptDeriveKey(String, String, Int32, Byte[])` * **RC2CryptoServiceProvider** @@ -229,7 +247,7 @@ Windows-specific: - `.ctor(CspParameters)` - `.ctor(Int32, CspParameters)` - `get_CspKeyContainerInfo()` - - `ImportCspBlob(Byte[])` +* **`CspParameters`** ### System.Security.Cryptography.X509Certificates From 95239be340d75c049b26caabde3c81b92161a6c9 Mon Sep 17 00:00:00 2001 From: Immo Landwerth Date: Tue, 14 Jul 2020 08:18:40 -0700 Subject: [PATCH 5/7] Add note about partially supported APIs --- .../windows-specific-apis/windows-specific-apis.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/accepted/2020/windows-specific-apis/windows-specific-apis.md b/accepted/2020/windows-specific-apis/windows-specific-apis.md index d9180e8b1..6c1c8a537 100644 --- a/accepted/2020/windows-specific-apis/windows-specific-apis.md +++ b/accepted/2020/windows-specific-apis/windows-specific-apis.md @@ -32,6 +32,16 @@ can simply check for the attribute by name. Thus, in order to mark .NET Standard 2.0 assemblies, we'll include an internal version of `MinimumOSPlatformAttribute` in those assemblies. +## Partially supported APIs + +We decided that APIs that are only platform-specific for a certain combinations +of arguments will not be marked as platform-specific. In other words, we'll +optimize for fewer false positives. + +In some cases, we get away with marking enum members as platform-specific. If +the API is popular enough, we may want to provide a custom analyzer that checks +for certain arguments. + ## Open Issues * We should run the tool again .NET 5 From fd6aba8563cdf2dfb5556a1fb1ef504c4d442f06 Mon Sep 17 00:00:00 2001 From: Immo Landwerth Date: Tue, 14 Jul 2020 08:33:57 -0700 Subject: [PATCH 6/7] Add APIs based on Adam's feedback --- .../windows-specific-apis/windows-specific-apis.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/accepted/2020/windows-specific-apis/windows-specific-apis.md b/accepted/2020/windows-specific-apis/windows-specific-apis.md index 6c1c8a537..34aa36524 100644 --- a/accepted/2020/windows-specific-apis/windows-specific-apis.md +++ b/accepted/2020/windows-specific-apis/windows-specific-apis.md @@ -118,6 +118,8 @@ Windows-specific: ### System.Diagnostics * **Process** + - `EnterDebugMode()` + - `LeaveDebugMode()` - `set_MaxWorkingSet(IntPtr)` - `set_MinWorkingSet(IntPtr)` - `Start(String, String, SecureString, String)` @@ -223,10 +225,14 @@ Windows-specific: - `ChangeWrapperHandleStrength(Object, Boolean)` - `CreateAggregatedObject(IntPtr, Object)` - `CreateAggregatedObject(IntPtr, T)` + - `CreateWrapperOfType(object, Type)` + - `CreateWrapperOfType(T)` - `FinalReleaseComObject(Object)` - `GetComInterfaceForObject(Object, Type)` - `GetComInterfaceForObject(Object, Type, CustomQueryInterfaceMode)` - `GetComInterfaceForObject(T)` + - `GetComObjectData(object,object)` + - `GetIDispatchForObject(object)` - `GetIUnknownForObject(Object)` - `GetNativeVariantForObject(Object, IntPtr)` - `GetNativeVariantForObject(T, IntPtr)` @@ -236,6 +242,7 @@ Windows-specific: - `GetObjectsForNativeVariants(IntPtr, Int32)` - `GetObjectsForNativeVariants(IntPtr, Int32)` - `GetStartComSlot(Type)` + - `GetEndComSlot(Type)` - `GetTypedObjectForIUnknown(IntPtr, Type)` - `GetTypeFromCLSID(Guid)` - `GetTypeInfoName(ITypeInfo)` @@ -243,11 +250,15 @@ Windows-specific: - `QueryInterface(IntPtr, Guid, IntPtr)` - `Release(IntPtr)` - `ReleaseComObject(Object)` + - `ReleaseComObject(Object)` + - `SetComObjectData(object,object,object)` ### System.Security.Cryptography * **CspKeyContainerInfo** * **DSACryptoServiceProvider** + - `.ctor(CspParameters)` + - `.ctor(int, CspParameters)` - `get_CspKeyContainerInfo()` * **PasswordDeriveBytes** - `CryptDeriveKey(String, String, Int32, Byte[])` From 242ba7b950e22a42bd20d3a4e326bc24fdd70ab1 Mon Sep 17 00:00:00 2001 From: Immo Landwerth Date: Tue, 14 Jul 2020 12:47:53 -0700 Subject: [PATCH 7/7] Add missing APIs from .NET 5 Preview 6 --- accepted/2020/windows-specific-apis/windows-specific-apis.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/accepted/2020/windows-specific-apis/windows-specific-apis.md b/accepted/2020/windows-specific-apis/windows-specific-apis.md index 34aa36524..5f1ad297a 100644 --- a/accepted/2020/windows-specific-apis/windows-specific-apis.md +++ b/accepted/2020/windows-specific-apis/windows-specific-apis.md @@ -155,7 +155,10 @@ Windows-specific: ### System.IO.Pipes * **NamedPipeClientStream** + - `Connect(Int32)` - `get_NumberOfServerInstances()` +* **NamedPipeServerStream** + - `WaitForConnection()` * **PipeStream** - `WaitForPipeDrain()` * **PipeTransmissionMode**