@@ -153,7 +153,7 @@ private static extern int _ioctl_arm64(int fd, ulong request,
153153
154154
155155 // request will be int, uint or BigInteger, and in Python is limited to values that can fit in 32 bits (unchecked)
156- // long should capture all allowed values
156+ // long should capture all allowed request values
157157 // return value is int, bytes, or LightException
158158 [ LightThrowing ]
159159 public static object ioctl ( int fd , long request , [ NotNone ] IBufferProtocol arg , bool mutate_flag = true ) {
@@ -169,7 +169,7 @@ public static object ioctl(int fd, long request, [NotNone] IBufferProtocol arg,
169169 buf = arg . GetBufferNoThrow ( BufferFlags . Writable ) ;
170170 }
171171 if ( buf is not null ) {
172- bufSize = buf . AsReadOnlySpan ( ) . Length ;
172+ bufSize = buf . AsSpan ( ) . Length ; // check early if buf is indeed writable
173173 } else {
174174 buf = arg . GetBuffer ( BufferFlags . Simple ) ;
175175 bufSize = buf . AsReadOnlySpan ( ) . Length ;
@@ -180,32 +180,25 @@ public static object ioctl(int fd, long request, [NotNone] IBufferProtocol arg,
180180 mutate_flag = false ; // return a buffer, not integer
181181 }
182182 bool in_place = bufSize > defaultBufSize ; // only large buffers are mutated in place
183- Debug . Assert ( ! in_place || mutate_flag ) ; // in_place implies mutate_flag
184183
185184#if ! NETCOREAPP
186185 throw new PlatformNotSupportedException ( "ioctl is not supported on Mono" ) ;
187186#else
188187 try {
188+ Debug . Assert ( ! in_place || mutate_flag ) ; // in_place implies mutate_flag
189+
190+ Span < byte > workSpan ;
191+ if ( in_place ) {
192+ workSpan = buf . AsSpan ( ) ;
193+ } else {
194+ workSpan = new byte [ defaultBufSize + 1 ] ; // +1 for extra NUL byte
195+ Debug . Assert ( bufSize <= defaultBufSize ) ;
196+ buf . AsReadOnlySpan ( ) . CopyTo ( workSpan ) ;
197+ }
198+ int result ;
199+ Errno errno ;
189200 unsafe {
190- MemoryHandle hmem = default ;
191- void * ptr = null ;
192- if ( in_place ) {
193- hmem = buf . Pin ( ) ;
194- } else {
195- ptr = NativeMemory . AllocZeroed ( defaultBufSize + 1 ) ; // +1 for extra nul byte
196- }
197- try {
198- if ( in_place ) {
199- ptr = hmem . Pointer ;
200- } else {
201- Debug . Assert ( bufSize <= defaultBufSize ) ;
202- var dest = new Span < byte > ( ( byte * ) ptr , bufSize ) ;
203- buf . AsReadOnlySpan ( ) . CopyTo ( dest ) ;
204- }
205- Debug . Assert ( ptr != null ) ;
206-
207- int result ;
208- Errno errno ;
201+ fixed ( byte * ptr = workSpan ) {
209202 do {
210203 if ( RuntimeInformation . ProcessArchitecture == Architecture . Arm64 ) {
211204 // workaround for Arm64 vararg calling convention (but not for ARM64EC on Windows)
@@ -214,30 +207,22 @@ public static object ioctl(int fd, long request, [NotNone] IBufferProtocol arg,
214207 result = _ioctl ( fd , cmd , ptr ) ;
215208 }
216209 } while ( UnixMarshal . ShouldRetrySyscall ( result , out errno ) ) ;
210+ }
211+ }
217212
218- if ( result == - 1 ) {
219- return LightExceptions . Throw ( PythonNT . GetOsError ( NativeConvert . FromErrno ( errno ) ) ) ;
220- }
221- if ( mutate_flag ) {
222- if ( ! in_place ) {
223- var src = new Span < byte > ( ( byte * ) ptr , bufSize ) ;
224- src . CopyTo ( buf . AsSpan ( ) ) ;
225- }
226- return ScriptingRuntimeHelpers . Int32ToObject ( result ) ;
227- } else {
228- Debug . Assert ( ! in_place ) ;
229- byte [ ] response = new byte [ bufSize ] ;
230- var src = new Span < byte > ( ( byte * ) ptr , bufSize ) ;
231- src . CopyTo ( response ) ;
232- return Bytes . Make ( response ) ;
233- }
234- } finally {
235- if ( in_place ) {
236- hmem . Dispose ( ) ;
237- } else {
238- NativeMemory . Free ( ptr ) ;
239- }
213+ if ( result == - 1 ) {
214+ return LightExceptions . Throw ( PythonNT . GetOsError ( NativeConvert . FromErrno ( errno ) ) ) ;
215+ }
216+ if ( mutate_flag ) {
217+ if ( ! in_place ) {
218+ workSpan . Slice ( 0 , bufSize ) . CopyTo ( buf . AsSpan ( ) ) ;
240219 }
220+ return ScriptingRuntimeHelpers . Int32ToObject ( result ) ;
221+ } else {
222+ Debug . Assert ( ! in_place ) ;
223+ byte [ ] response = new byte [ bufSize ] ;
224+ workSpan . Slice ( 0 , bufSize ) . CopyTo ( response ) ;
225+ return Bytes . Make ( response ) ;
241226 }
242227 } finally {
243228 buf . Dispose ( ) ;
0 commit comments