3131#include "erl_unicode.h"
3232#include "erl_binary.h"
3333#include "erl_global_literals.h"
34+ #include "erl_struct.h"
3435
3536#define LoadError (Expr ) \
3637 do { \
@@ -874,6 +875,247 @@ static int parse_debug_chunk(BeamFile *beam, IFF_Chunk *chunk) {
874875 }
875876}
876877
878+ struct erl_record_field {
879+ int order ;
880+ Eterm key ;
881+ Eterm value ;
882+ };
883+
884+ static int record_compare (const struct erl_record_field * a , const struct erl_record_field * b ) {
885+ Sint res = erts_cmp_flatmap_keys (a -> key , b -> key );
886+
887+ if (res < 0 ) {
888+ return -1 ;
889+ } else if (res > 0 ) {
890+ return 1 ;
891+ }
892+
893+ return 0 ;
894+ }
895+
896+ static int parse_record_chunk_data (BeamFile * beam , BeamReader * p_reader ) {
897+ Sint32 record_count ;
898+ Sint32 total_field_count ;
899+ BeamOpAllocator op_allocator ;
900+ BeamCodeReader * op_reader ;
901+ BeamOp * op = NULL ;
902+ BeamFile_RecordTable * rec = & beam -> record ;
903+ struct erl_record_field * fields = NULL ;
904+
905+ LoadAssert (beamreader_read_i32 (p_reader , & record_count ));
906+ LoadAssert (beamreader_read_i32 (p_reader , & total_field_count ));
907+
908+ beamopallocator_init (& op_allocator );
909+
910+ op_reader = erts_alloc (ERTS_ALC_T_PREPARED_CODE , sizeof (BeamCodeReader ));
911+
912+ op_reader -> allocator = & op_allocator ;
913+ op_reader -> file = beam ;
914+ op_reader -> pending = NULL ;
915+ op_reader -> first = 1 ;
916+ op_reader -> reader = * p_reader ;
917+
918+ if (record_count < 0 ) {
919+ goto error ;
920+ }
921+
922+ rec -> record_count = record_count ;
923+ rec -> total_field_count = 2 * total_field_count ;
924+ rec -> records = erts_alloc (ERTS_ALC_T_PREPARED_CODE ,
925+ record_count * sizeof (BeamFile_Record ));
926+
927+ for (Sint32 i = 0 ; i < record_count ; i ++ ) {
928+ BeamOpArg * arg ;
929+ int extra_args ;
930+ int field_index ;
931+ Uint tmp_size ;
932+ Uint struct_def_size ;
933+ Uint num_fields ;
934+ Eterm * order_tuple ;
935+ ErtsStructDefinition * tmp_def ;
936+ Eterm is_exported ;
937+
938+ if (!beamcodereader_next (op_reader , & op )) {
939+ goto error ;
940+ }
941+ if (op -> op != genop_call_last_3 ) {
942+ goto error ;
943+ }
944+
945+ arg = op -> a ;
946+
947+ /* Process name. */
948+ switch (arg -> type ) {
949+ case TAG_a :
950+ if (is_atom (arg -> val )) {
951+ rec -> records [i ].name = arg -> val ;
952+ } else {
953+ goto error ;
954+ }
955+ break ;
956+ default :
957+ goto error ;
958+ }
959+
960+ arg ++ ;
961+
962+ /* Process exported flag. */
963+ switch (arg -> type ) {
964+ case TAG_a :
965+ if (arg -> val == am_true || arg -> val == am_false ) {
966+ is_exported = arg -> val ;
967+ } else {
968+ goto error ;
969+ }
970+ break ;
971+ default :
972+ goto error ;
973+ }
974+
975+ arg ++ ;
976+
977+ /* Get and check the number of extra arguments. */
978+ if (arg -> type != TAG_u ) {
979+ goto error ;
980+ }
981+
982+ extra_args = arg -> val ;
983+
984+ arg ++ ;
985+
986+ if (extra_args % 2 != 0 ) {
987+ goto error ;
988+ }
989+
990+ rec -> records [i ].num_fields = num_fields = extra_args / 2 ;
991+
992+ /* Collect field names and default values. Put it into an
993+ * array of erl_record_fields structs, which are suitable for
994+ * sorting. */
995+ fields = erts_alloc (ERTS_ALC_T_TMP , num_fields * sizeof (struct erl_record_field ));
996+ field_index = 0 ;
997+ while (extra_args > 0 ) {
998+ fields [field_index ].order = field_index ;
999+
1000+ switch (arg [0 ].type ) {
1001+ case TAG_a :
1002+ fields [field_index ].key = arg [0 ].val ;
1003+ break ;
1004+ default :
1005+ goto error ;
1006+ }
1007+
1008+ switch (arg [1 ].type ) {
1009+ case TAG_u :
1010+ fields [field_index ].value = make_catch (0 );
1011+ break ;
1012+ case TAG_a :
1013+ case TAG_n :
1014+ fields [field_index ].value = arg [1 ].val ;
1015+ break ;
1016+ case TAG_i :
1017+ fields [field_index ].value = make_small (arg [1 ].val );
1018+ break ;
1019+ case TAG_q :
1020+ fields [field_index ].value = beamfile_get_literal (beam , arg [1 ].val );
1021+ break ;
1022+ default :
1023+ goto error ;
1024+ }
1025+
1026+ field_index ++ ;
1027+ arg += 2 ;
1028+ extra_args -= 2 ;
1029+ }
1030+
1031+ qsort ((void * ) fields , num_fields , sizeof (struct erl_record_field ),
1032+ (int (* )(const void * , const void * )) record_compare );
1033+
1034+ /* Separate the fields into an array of field names and default values,
1035+ * and a tuple mapping from original position to current position. */
1036+
1037+ tmp_size = sizeof (ErtsStructDefinition );
1038+ tmp_size += 2 * num_fields * sizeof (Eterm ); /* Fields & default values */
1039+
1040+ struct_def_size = tmp_size ;
1041+ tmp_size += (num_fields + 1 ) * sizeof (Eterm ); /* Order tuple */
1042+
1043+ tmp_def = (ErtsStructDefinition * ) erts_alloc (ERTS_ALC_T_TMP , tmp_size );
1044+ tmp_def -> thing_word = make_arityval (struct_def_size /sizeof (Eterm ) - 1 );
1045+ tmp_def -> entry = NIL ;
1046+ tmp_def -> module = beam -> module ;
1047+ tmp_def -> name = rec -> records [i ].name ;
1048+ tmp_def -> is_exported = is_exported ;
1049+
1050+ order_tuple = & tmp_def -> fields [num_fields ].key ;
1051+
1052+ if (rec -> records [i ].num_fields == 0 ) {
1053+ * order_tuple = NIL ;
1054+ tmp_def -> field_order = ERTS_GLOBAL_LIT_EMPTY_TUPLE ;
1055+ } else {
1056+ tmp_def -> field_order = make_tuple (order_tuple );
1057+ * order_tuple ++ = make_arityval (num_fields );
1058+ }
1059+
1060+ for (field_index = 0 ; field_index < num_fields ; field_index ++ ) {
1061+ tmp_def -> fields [field_index ].key = fields [field_index ].key ;
1062+ tmp_def -> fields [field_index ].value = fields [field_index ].value ;
1063+ order_tuple [fields [field_index ].order ] = make_small (field_index );
1064+ }
1065+
1066+ /* Save everything into a literal. */
1067+ rec -> records [i ].def_literal =
1068+ beamfile_add_literal (beam , make_tuple ((Eterm * )tmp_def ), 0 );
1069+
1070+ erts_free (ERTS_ALC_T_TMP , tmp_def );
1071+
1072+ erts_free (ERTS_ALC_T_TMP , fields );
1073+ fields = NULL ;
1074+
1075+ beamopallocator_free_op (& op_allocator , op );
1076+ op = NULL ;
1077+ }
1078+
1079+ beamcodereader_close (op_reader );
1080+ beamopallocator_dtor (& op_allocator );
1081+
1082+ return 1 ;
1083+
1084+ error :
1085+ if (op != NULL ) {
1086+ beamopallocator_free_op (& op_allocator , op );
1087+ }
1088+
1089+ if (fields != NULL ) {
1090+ erts_free (ERTS_ALC_T_TMP , fields );
1091+ }
1092+
1093+ beamcodereader_close (op_reader );
1094+ beamopallocator_dtor (& op_allocator );
1095+
1096+ if (rec -> records ) {
1097+ erts_free (ERTS_ALC_T_PREPARED_CODE , rec -> records );
1098+ rec -> records = NULL ;
1099+ }
1100+
1101+ return 0 ;
1102+ }
1103+
1104+ static int parse_record_chunk (BeamFile * beam , IFF_Chunk * chunk ) {
1105+ BeamReader reader ;
1106+ Sint32 version ;
1107+
1108+ beamreader_init (chunk -> data , chunk -> size , & reader );
1109+
1110+ LoadAssert (beamreader_read_i32 (& reader , & version ));
1111+
1112+ if (version == 0 ) {
1113+ return parse_record_chunk_data (beam , & reader );
1114+ } else {
1115+ return 0 ;
1116+ }
1117+ }
1118+
8771119static ErlHeapFragment * new_literal_fragment (Uint size )
8781120{
8791121 ErlHeapFragment * bp ;
@@ -1128,6 +1370,7 @@ beamfile_read(const byte *data, size_t size, BeamFile *beam) {
11281370 MakeIffId ('T' , 'y' , 'p' , 'e' ), /* 12 */
11291371 MakeIffId ('M' , 'e' , 't' , 'a' ), /* 13 */
11301372 MakeIffId ('D' , 'b' , 'g' , 'B' ), /* 14 */
1373+ MakeIffId ('R' , 'e' , 'c' , 's' ), /* 15 */
11311374 };
11321375
11331376 static const int UTF8_ATOM_CHUNK = 0 ;
@@ -1147,6 +1390,7 @@ beamfile_read(const byte *data, size_t size, BeamFile *beam) {
11471390 static const int TYPE_CHUNK = 12 ;
11481391 static const int META_CHUNK = 13 ;
11491392 static const int DEBUG_CHUNK = 14 ;
1393+ static const int RECORD_CHUNK = 15 ;
11501394
11511395 static const int NUM_CHUNKS = sizeof (chunk_iffs ) / sizeof (chunk_iffs [0 ]);
11521396
@@ -1251,6 +1495,13 @@ beamfile_read(const byte *data, size_t size, BeamFile *beam) {
12511495 }
12521496 }
12531497
1498+ if (chunks [RECORD_CHUNK ].size > 0 ) {
1499+ if (!parse_record_chunk (beam , & chunks [RECORD_CHUNK ])) {
1500+ error = BEAMFILE_READ_CORRUPT_RECORD_TABLE ;
1501+ goto error ;
1502+ }
1503+ }
1504+
12541505 beam -> strings .data = chunks [STR_CHUNK ].data ;
12551506 beam -> strings .size = chunks [STR_CHUNK ].size ;
12561507
@@ -1326,6 +1577,12 @@ beamfile_read(const byte *data, size_t size, BeamFile *beam) {
13261577 chunks [META_CHUNK ].size );
13271578 }
13281579
1580+ if (chunks [RECORD_CHUNK ].size > 0 ) {
1581+ MD5Update (& md5 ,
1582+ (byte * )chunks [RECORD_CHUNK ].data ,
1583+ chunks [RECORD_CHUNK ].size );
1584+ }
1585+
13291586 MD5Final (beam -> checksum , & md5 );
13301587 }
13311588
0 commit comments