Skip to content

Commit 821a5a9

Browse files
committed
FIX: better struct! initialization; empty struct not allowed
1 parent 7aaa058 commit 821a5a9

File tree

2 files changed

+40
-5
lines changed

2 files changed

+40
-5
lines changed

src/core/t-struct.c

+13-5
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,7 @@ static REBOOL parse_field_type(struct Struct_Field *field, REBVAL *spec, REBVAL
686686
/*
687687
* Format:
688688
* make struct! [
689-
* field1 [type1]
689+
* field1 [type1]
690690
* field2: [type2] field2-init-value
691691
* field3: [struct [field1 [type1]]] field3-init-struct-value
692692
* field4: [type1[3]] field4-init-block-value
@@ -695,10 +695,17 @@ static REBOOL parse_field_type(struct Struct_Field *field, REBVAL *spec, REBVAL
695695
***********************************************************************/
696696
{
697697
//RL_Print("%s\n", __func__);
698-
REBINT max_fields = 16;
698+
699699
if (!IS_BLOCK(data)) return FALSE; // validate early!
700-
701-
VAL_STRUCT_FIELDS(out) = Make_Series(max_fields, sizeof(struct Struct_Field), FALSE);
700+
701+
/* Using spec block length as a prediction of fields number
702+
(each field requires at least 2 spec values) */
703+
REBCNT num_spec_values = VAL_TAIL(data) - VAL_INDEX(data);
704+
REBCNT min_fileds = num_spec_values >> 1;
705+
/* Don't allow empty struct! */
706+
if (min_fileds == 0) Trap_Arg(data);
707+
708+
VAL_STRUCT_FIELDS(out) = Make_Series(min_fileds, sizeof(struct Struct_Field), FALSE);
702709
BARE_SERIES(VAL_STRUCT_FIELDS(out));
703710

704711
//Reduce_Block_No_Set(VAL_SERIES(data), 0, NULL);
@@ -718,7 +725,8 @@ static REBOOL parse_field_type(struct Struct_Field *field, REBVAL *spec, REBVAL
718725
EXPAND_SERIES_TAIL(VAL_STRUCT_DATA(out), 1);
719726
BARE_SERIES(VAL_STRUCT_DATA(out));
720727

721-
VAL_STRUCT_DATA_BIN(out) = Make_Series(max_fields << 2, 1, FALSE);
728+
/* one byte per field as a minimum (expands when needed) */
729+
VAL_STRUCT_DATA_BIN(out) = Make_Series(min_fileds, 1, FALSE);
722730
BARE_SERIES(VAL_STRUCT_DATA_BIN(out));
723731
VAL_STRUCT_OFFSET(out) = 0;
724732

src/tests/units/struct-test.r3

+27
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,15 @@ Rebol [
133133
--assert all [s2/a = 1 s2/b = 20]
134134
--assert all [s3/a = 10 s3/b = 20]
135135

136+
--test-- "Struct with many fields"
137+
blk: copy []
138+
repeat i 32 [repend blk [to word! join 'a i [int8!]]]
139+
--assert all [
140+
not error? try [s: make struct! blk]
141+
[a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20 a21 a22 a23 a24 a25 a26 a27 a28 a29 a30 a31 a32] = words-of s
142+
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] = values-of s
143+
]
144+
136145
===end-group===
137146

138147

@@ -177,6 +186,24 @@ s: make struct! spec: [a: [uint16!] 1 b: [int32!] -1 c: [word!] foo d [uint8! [2
177186
error? e: try [ make struct! [a: [int8! [2]] 1] ] ;- No crash!
178187
e/id = 'expect-val
179188
]
189+
190+
--test-- "Empty struct not allowed"
191+
--assert all [
192+
error? e: try [make struct! []]
193+
e/id = 'invalid-arg
194+
]
195+
--assert all [
196+
error? e: try [make struct! [a]]
197+
e/id = 'invalid-arg
198+
]
199+
--assert all [
200+
error? e: try [make struct! [[]]]
201+
e/id = 'invalid-arg
202+
]
203+
--assert all [
204+
error? e: try [make struct! [[] a]]
205+
e/id = 'invalid-arg
206+
]
180207
===end-group===
181208

182209

0 commit comments

Comments
 (0)