Skip to content

Commit 4c537a4

Browse files
committed
Fix some struct issues
1 parent 6071a92 commit 4c537a4

File tree

3 files changed

+28
-33
lines changed

3 files changed

+28
-33
lines changed

Src/IronPython.Modules/_struct.cs

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -393,13 +393,13 @@ public void pack_into(CodeContext/*!*/ context, [NotNone] ByteArray/*!*/ buffer,
393393
}
394394

395395
[Documentation("iteratively unpack the current format from the specified array.")]
396-
public PythonUnpackIterator iter_unpack(CodeContext/*!*/ context, [BytesLike][NotNone] IList<byte>/*!*/ buffer, int offset = 0) {
397-
return new PythonUnpackIterator(this, context, buffer, offset);
396+
public PythonUnpackIterator iter_unpack(CodeContext/*!*/ context, [BytesLike][NotNone] IList<byte>/*!*/ buffer) {
397+
return new PythonUnpackIterator(this, context, buffer);
398398
}
399399

400400
[Documentation("iteratively unpack the current format from the specified array.")]
401-
public PythonUnpackIterator iter_unpack(CodeContext/*!*/ context, [NotNone] ArrayModule.array/*!*/ buffer, int offset = 0) {
402-
return new PythonUnpackIterator(this, context, buffer, offset);
401+
public PythonUnpackIterator iter_unpack(CodeContext/*!*/ context, [NotNone] ArrayModule.array/*!*/ buffer) {
402+
return new PythonUnpackIterator(this, context, buffer.ToByteArray());
403403
}
404404

405405
[Documentation("gets the number of bytes that the serialized string will occupy or are required to deserialize the data")]
@@ -559,14 +559,19 @@ private static Struct CompileAndCache(CodeContext/*!*/ context, string/*!*/ fmt)
559559
fLittleEndian = false;
560560
fStandardized = true;
561561
break;
562+
case '\x00':
563+
throw Error(context, "embedded null character");
562564
default:
563565
if (char.IsDigit(fmt[i])) {
564566
count = 0;
565567
while (char.IsDigit(fmt[i])) {
566568
count = count * 10 + (fmt[i] - '0');
567569
i++;
570+
if (i >= fmt.Length) {
571+
throw Error(context, "repeat count given without format specifier");
572+
}
568573
}
569-
if (char.IsWhiteSpace(fmt[i])) Error(context, "white space not allowed between count and format");
574+
if (char.IsWhiteSpace(fmt[i])) throw Error(context, "white space not allowed between count and format");
570575
i--;
571576
break;
572577
}
@@ -633,33 +638,24 @@ public class PythonUnpackIterator : System.Collections.IEnumerator, System.Colle
633638

634639
private readonly CodeContext _context;
635640
private readonly IList<byte> _buffer;
636-
private readonly int _start_offset;
637641
private readonly Struct _owner;
638642

639643
private PythonUnpackIterator() { }
640644

641-
internal PythonUnpackIterator(Struct/*!*/ owner, CodeContext/*!*/ context, IList<byte>/*!*/ buffer, int offset) {
645+
internal PythonUnpackIterator(Struct/*!*/ owner, CodeContext/*!*/ context, IList<byte>/*!*/ buffer) {
642646
_context = context;
643647
_buffer = buffer;
644-
_start_offset = offset;
645-
_owner = owner;
646-
647-
Reset();
648-
ValidateBufferLength();
649-
}
650-
651-
internal PythonUnpackIterator(Struct/*!*/ owner, CodeContext/*!*/ context, ArrayModule.array/*!*/ buffer, int offset) {
652-
_context = context;
653-
_buffer = buffer.ToByteArray();
654-
_start_offset = offset;
655648
_owner = owner;
656649

657650
Reset();
658651
ValidateBufferLength();
659652
}
660653

661654
private void ValidateBufferLength() {
662-
if (_buffer.Count - _start_offset < _owner.size) {
655+
if (_owner.size == 0) {
656+
throw Error(_context, "cannot iteratively unpack with a struct of length 0");
657+
}
658+
if (_buffer.Count % _owner.size != 0) {
663659
throw Error(_context, $"iterative unpacking requires a buffer of a multiple of {_owner.size} bytes");
664660
}
665661
}
@@ -689,7 +685,7 @@ public bool MoveNext() {
689685
[PythonHidden]
690686
public void Reset() {
691687
_iter_current = null;
692-
_next_offset = _start_offset;
688+
_next_offset = 0;
693689
}
694690
#endregion
695691

@@ -869,13 +865,13 @@ public static void pack_into(CodeContext/*!*/ context, object fmt, [NotNone] Byt
869865
}
870866

871867
[Documentation("Iteratively unpack the buffer, containing packed C structure data, according to\nfmt, starting at offset. Requires len(buffer[offset:]) >= calcsize(fmt).")]
872-
public static PythonUnpackIterator/*!*/ iter_unpack(CodeContext/*!*/ context, object fmt, [BytesLike][NotNone] IList<byte>/*!*/ buffer, int offset = 0) {
873-
return GetStructFromCache(context, fmt).iter_unpack(context, buffer, offset);
868+
public static PythonUnpackIterator/*!*/ iter_unpack(CodeContext/*!*/ context, object fmt, [BytesLike][NotNone] IList<byte>/*!*/ buffer) {
869+
return GetStructFromCache(context, fmt).iter_unpack(context, buffer);
874870
}
875871

876872
[Documentation("Iteratively unpack the buffer, containing packed C structure data, according to\nfmt, starting at offset. Requires len(buffer[offset:]) >= calcsize(fmt).")]
877-
public static PythonUnpackIterator/*!*/ iter_unpack(CodeContext/*!*/ context, object fmt, [NotNone] ArrayModule.array/*!*/ buffer, int offset = 0) {
878-
return GetStructFromCache(context, fmt).iter_unpack(context, buffer, offset);
873+
public static PythonUnpackIterator/*!*/ iter_unpack(CodeContext/*!*/ context, object fmt, [NotNone] ArrayModule.array/*!*/ buffer) {
874+
return GetStructFromCache(context, fmt).iter_unpack(context, buffer);
879875
}
880876
#endregion
881877

@@ -1361,6 +1357,7 @@ internal static Bytes CreateString(CodeContext/*!*/ context, ref int index, int
13611357

13621358
internal static Bytes CreatePascalString(CodeContext/*!*/ context, ref int index, int count, IList<byte> data) {
13631359
int realLen = (int)data[index++];
1360+
if (realLen > count) realLen = count;
13641361
using var res = new MemoryStream();
13651362
for (int i = 0; i < realLen; i++) {
13661363
res.WriteByte(data[index++]);

Src/StdLib/Lib/test/test_struct.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -542,13 +542,13 @@ def test_trailing_counter(self):
542542

543543
# format lists containing only count spec should result in an error
544544
self.assertRaises(struct.error, struct.pack, '12345')
545-
self.assertRaises(struct.error, struct.unpack, '12345', '')
545+
self.assertRaises(struct.error, struct.unpack, '12345', b'')
546546
self.assertRaises(struct.error, struct.pack_into, '12345', store, 0)
547547
self.assertRaises(struct.error, struct.unpack_from, '12345', store, 0)
548548

549549
# Format lists with trailing count spec should result in an error
550550
self.assertRaises(struct.error, struct.pack, 'c12345', 'x')
551-
self.assertRaises(struct.error, struct.unpack, 'c12345', 'x')
551+
self.assertRaises(struct.error, struct.unpack, 'c12345', b'x')
552552
self.assertRaises(struct.error, struct.pack_into, 'c12345', store, 0,
553553
'x')
554554
self.assertRaises(struct.error, struct.unpack_from, 'c12345', store,
@@ -557,7 +557,7 @@ def test_trailing_counter(self):
557557
# Mixed format tests
558558
self.assertRaises(struct.error, struct.pack, '14s42', 'spam and eggs')
559559
self.assertRaises(struct.error, struct.unpack, '14s42',
560-
'spam and eggs')
560+
b'spam and eggs')
561561
self.assertRaises(struct.error, struct.pack_into, '14s42', store, 0,
562562
'spam and eggs')
563563
self.assertRaises(struct.error, struct.unpack_from, '14s42', store, 0)

Tests/test_struct_stdlib.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,10 @@ def load_tests(loader, standard_tests, pattern):
1515

1616
if is_ironpython:
1717
failing_tests = [
18-
test.test_struct.StructTest('test_705836'), # TODO: figure out
19-
test.test_struct.StructTest('test_bool'), # TODO: figure out
20-
test.test_struct.StructTest('test_calcsize'), # TODO: figure out
21-
test.test_struct.StructTest('test_count_overflow'), # TODO: figure out
22-
test.test_struct.StructTest('test_trailing_counter'), # TODO: figure out
23-
test.test_struct.UnpackIteratorTest('test_construct'), # TODO: figure out
18+
test.test_struct.StructTest('test_705836'), # AssertionError: OverflowError not raised by pack
19+
test.test_struct.StructTest('test_bool'), # struct.error: expected bool value got IronPython.NewTypes.System.Object_1$1
20+
test.test_struct.StructTest('test_calcsize'), # AssertionError: 4 not greater than or equal to 8
21+
test.test_struct.StructTest('test_count_overflow'), # AssertionError: error not raised by calcsize
2422
]
2523

2624
return generate_suite(tests, failing_tests)

0 commit comments

Comments
 (0)