diff --git a/src/core/t-struct.c b/src/core/t-struct.c index 8c25b5bb77..c1b4a2ec69 100644 --- a/src/core/t-struct.c +++ b/src/core/t-struct.c @@ -686,7 +686,7 @@ static REBOOL parse_field_type(struct Struct_Field *field, REBVAL *spec, REBVAL /* * Format: * make struct! [ - * field1 [type1] + * field1 [type1] * field2: [type2] field2-init-value * field3: [struct [field1 [type1]]] field3-init-struct-value * field4: [type1[3]] field4-init-block-value @@ -695,10 +695,17 @@ static REBOOL parse_field_type(struct Struct_Field *field, REBVAL *spec, REBVAL ***********************************************************************/ { //RL_Print("%s\n", __func__); - REBINT max_fields = 16; + if (!IS_BLOCK(data)) return FALSE; // validate early! - - VAL_STRUCT_FIELDS(out) = Make_Series(max_fields, sizeof(struct Struct_Field), FALSE); + + /* Using spec block length as a prediction of fields number + (each field requires at least 2 spec values) */ + REBCNT num_spec_values = VAL_TAIL(data) - VAL_INDEX(data); + REBCNT min_fileds = num_spec_values >> 1; + /* Don't allow empty struct! */ + if (min_fileds == 0) Trap_Arg(data); + + VAL_STRUCT_FIELDS(out) = Make_Series(min_fileds, sizeof(struct Struct_Field), FALSE); BARE_SERIES(VAL_STRUCT_FIELDS(out)); //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 EXPAND_SERIES_TAIL(VAL_STRUCT_DATA(out), 1); BARE_SERIES(VAL_STRUCT_DATA(out)); - VAL_STRUCT_DATA_BIN(out) = Make_Series(max_fields << 2, 1, FALSE); + /* one byte per field as a minimum (expands when needed) */ + VAL_STRUCT_DATA_BIN(out) = Make_Series(min_fileds, 1, FALSE); BARE_SERIES(VAL_STRUCT_DATA_BIN(out)); VAL_STRUCT_OFFSET(out) = 0; diff --git a/src/tests/units/struct-test.r3 b/src/tests/units/struct-test.r3 index 31f9e22eeb..a17e083eb6 100644 --- a/src/tests/units/struct-test.r3 +++ b/src/tests/units/struct-test.r3 @@ -133,6 +133,15 @@ Rebol [ --assert all [s2/a = 1 s2/b = 20] --assert all [s3/a = 10 s3/b = 20] +--test-- "Struct with many fields" + blk: copy [] + repeat i 32 [repend blk [to word! join 'a i [int8!]]] + --assert all [ + not error? try [s: make struct! blk] + [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 + [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 + ] + ===end-group=== @@ -177,6 +186,24 @@ s: make struct! spec: [a: [uint16!] 1 b: [int32!] -1 c: [word!] foo d [uint8! [2 error? e: try [ make struct! [a: [int8! [2]] 1] ] ;- No crash! e/id = 'expect-val ] + +--test-- "Empty struct not allowed" + --assert all [ + error? e: try [make struct! []] + e/id = 'invalid-arg + ] + --assert all [ + error? e: try [make struct! [a]] + e/id = 'invalid-arg + ] + --assert all [ + error? e: try [make struct! [[]]] + e/id = 'invalid-arg + ] + --assert all [ + error? e: try [make struct! [[] a]] + e/id = 'invalid-arg + ] ===end-group===