Skip to content

Commit 5eaedae

Browse files
committed
Avoid throw/catch exceptions when requesting optional buffer through IBufferProtocol
1 parent 65a7afc commit 5eaedae

File tree

8 files changed

+42
-23
lines changed

8 files changed

+42
-23
lines changed

src/core/IronPython.Modules/_ctypes/CData.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ public void Dispose() {
125125

126126
private int _numExports;
127127

128-
IPythonBuffer IBufferProtocol.GetBuffer(BufferFlags flags) {
128+
IPythonBuffer IBufferProtocol.GetBuffer(BufferFlags flags, bool throwOnError) {
129129
if (_disposed) throw new ObjectDisposedException(GetType().Name);
130130
_ = MemHolder; // check if fully initialized
131131
Interlocked.Increment(ref _numExports);

src/core/IronPython.Modules/array.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1037,7 +1037,7 @@ bool ICollection<object>.Remove(object item) {
10371037

10381038
#region IBufferProtocol Members
10391039

1040-
IPythonBuffer IBufferProtocol.GetBuffer(BufferFlags flags) {
1040+
IPythonBuffer IBufferProtocol.GetBuffer(BufferFlags flags, bool throwOnError) {
10411041
return _data.GetBuffer(this, _typeCode.ToString(), flags);
10421042
}
10431043

src/core/IronPython.Modules/mmap.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,10 +1314,13 @@ void IWeakReferenceable.SetFinalizer(WeakRefTracker value) {
13141314

13151315
#endregion
13161316

1317-
public IPythonBuffer GetBuffer(BufferFlags flags = BufferFlags.Simple) {
1318-
if (flags.HasFlag(BufferFlags.Writable) && IsReadOnly)
1319-
throw PythonOps.BufferError("Object is not writable.");
1320-
1317+
public IPythonBuffer? GetBuffer(BufferFlags flags, bool throwOnError) {
1318+
if (flags.HasFlag(BufferFlags.Writable) && IsReadOnly) {
1319+
if (throwOnError) {
1320+
throw PythonOps.BufferError("Object is not writable.");
1321+
}
1322+
return null;
1323+
}
13211324
return new MmapBuffer(this, flags);
13221325
}
13231326

src/core/IronPython/Runtime/BufferProtocol.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace IronPython.Runtime {
1717
/// Equivalent functionality of CPython's <a href="https://docs.python.org/3/c-api/buffer.html">Buffer Protocol</a>.
1818
/// </summary>
1919
public interface IBufferProtocol {
20-
IPythonBuffer GetBuffer(BufferFlags flags = BufferFlags.Simple);
20+
IPythonBuffer? GetBuffer(BufferFlags flags, bool throwOnError);
2121
}
2222

2323
/// <summary>
@@ -120,9 +120,12 @@ public enum BufferFlags {
120120
}
121121

122122
internal static class BufferProtocolExtensions {
123+
internal static IPythonBuffer GetBuffer(this IBufferProtocol bufferProtocol, BufferFlags flags = BufferFlags.Simple)
124+
=> bufferProtocol.GetBuffer(flags, throwOnError: true) ?? throw new BufferException("Buffer type not supported");
125+
123126
internal static IPythonBuffer? GetBufferNoThrow(this IBufferProtocol bufferProtocol, BufferFlags flags = BufferFlags.Simple) {
124127
try {
125-
return bufferProtocol.GetBuffer(flags);
128+
return bufferProtocol.GetBuffer(flags, throwOnError: false);
126129
} catch (BufferException) {
127130
return null;
128131
}

src/core/IronPython/Runtime/ByteArray.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1584,7 +1584,7 @@ private bool Equals(ReadOnlySpan<byte> other) {
15841584

15851585
#region IBufferProtocol Members
15861586

1587-
IPythonBuffer IBufferProtocol.GetBuffer(BufferFlags flags) {
1587+
IPythonBuffer IBufferProtocol.GetBuffer(BufferFlags flags, bool throwOnError) {
15881588
return _bytes.GetBuffer(this, "B", flags);
15891589
}
15901590

src/core/IronPython/Runtime/Bytes.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,10 +1241,13 @@ Expression IExpressionSerializable.CreateExpression() {
12411241

12421242
#region IBufferProtocol Support
12431243

1244-
IPythonBuffer IBufferProtocol.GetBuffer(BufferFlags flags) {
1245-
if (flags.HasFlag(BufferFlags.Writable))
1246-
throw PythonOps.BufferError("Object is not writable.");
1247-
1244+
IPythonBuffer? IBufferProtocol.GetBuffer(BufferFlags flags, bool throwOnError) {
1245+
if (flags.HasFlag(BufferFlags.Writable)) {
1246+
if (throwOnError) {
1247+
throw PythonOps.TypeError("bytes object is not writable");
1248+
}
1249+
return null;
1250+
}
12481251
return new BytesView(this, flags);
12491252
}
12501253

src/core/IronPython/Runtime/ConversionWrappers.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,13 +436,16 @@ public MemoryBufferProtocolWrapper(Memory<byte> memory) {
436436
_memory = memory;
437437
}
438438

439-
public IPythonBuffer GetBuffer(BufferFlags flags) {
439+
public IPythonBuffer? GetBuffer(BufferFlags flags, bool throwOnError) {
440440
if (_memory.HasValue) {
441441
return new MemoryBufferWrapper(_memory.Value, flags);
442442
}
443443

444444
if (flags.HasFlag(BufferFlags.Writable)) {
445-
throw Operations.PythonOps.BufferError("ReadOnlyMemory is not writable.");
445+
if (throwOnError) {
446+
throw Operations.PythonOps.BufferError("ReadOnlyMemory is not writable.");
447+
}
448+
return null;
446449
}
447450

448451
return new MemoryBufferWrapper(_rom, flags);

src/core/IronPython/Runtime/MemoryView.cs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -963,32 +963,39 @@ void IWeakReferenceable.SetFinalizer(WeakRefTracker value) {
963963

964964
#region IBufferProtocol Members
965965

966-
IPythonBuffer IBufferProtocol.GetBuffer(BufferFlags flags) {
966+
IPythonBuffer? IBufferProtocol.GetBuffer(BufferFlags flags, bool throwOnError) {
967967
CheckBuffer();
968968

969969
if (flags.HasFlag(BufferFlags.Writable) && _isReadOnly)
970-
throw PythonOps.BufferError("memoryview: underlying buffer is not writable");
970+
return ReportError("memoryview: underlying buffer is not writable");
971971

972972
if (flags.HasFlag(BufferFlags.CContiguous) && !_isCContig)
973-
throw PythonOps.BufferError("memoryview: underlying buffer is not C-contiguous");
973+
return ReportError("memoryview: underlying buffer is not C-contiguous");
974974

975975
if (flags.HasFlag(BufferFlags.FContiguous) && !_isFContig)
976-
throw PythonOps.BufferError("memoryview: underlying buffer is not Fortran contiguous");
976+
return ReportError("memoryview: underlying buffer is not Fortran contiguous");
977977

978978
if (flags.HasFlag(BufferFlags.AnyContiguous) && !_isCContig && !_isFContig)
979-
throw PythonOps.BufferError("memoryview: underlying buffer is not contiguous");
979+
return ReportError("memoryview: underlying buffer is not contiguous");
980980

981981
// TODO: Support for suboffsets
982982
//if (!flags.HasFlag(!BufferFlags.Indirect) && _suboffsets != null)
983-
// throw PythonOps.BufferError("memoryview: underlying buffer requires suboffsets");
983+
// return ReportError("memoryview: underlying buffer requires suboffsets");
984984

985985
if (!flags.HasFlag(BufferFlags.Strides) && !_isCContig)
986-
throw PythonOps.BufferError("memoryview: underlying buffer is not C-contiguous");
986+
return ReportError("memoryview: underlying buffer is not C-contiguous");
987987

988988
if (!flags.HasFlag(BufferFlags.ND) && flags.HasFlag(BufferFlags.Format))
989-
throw PythonOps.BufferError("memoryview: cannot cast to unsigned bytes if the format flag is present");
989+
return ReportError("memoryview: cannot cast to unsigned bytes if the format flag is present");
990990

991991
return new MemoryView(this, flags);
992+
993+
IPythonBuffer? ReportError(string msg) {
994+
if (throwOnError) {
995+
throw PythonOps.BufferError(msg);
996+
}
997+
return null;
998+
}
992999
}
9931000

9941001
#endregion

0 commit comments

Comments
 (0)