@@ -1018,7 +1018,11 @@ Result Thread::AtomicRmwCmpxchg(const uint8_t** pc) {
1018
1018
return Push<ResultValueType>(static_cast <ExtendedType>(read ));
1019
1019
}
1020
1020
1021
- bool ClampToBounds (uint32_t start, uint32_t * length, uint32_t max) {
1021
+ // This function is used to clanp the bound for table.fill operations. This
1022
+ // can be removed once the behaviour of table.fill is updated to match the
1023
+ // new bulk meory semantics, which is to trap early on OOB.
1024
+ // See: https://github.com/webassembly/bulk-memory-operations/issues/111
1025
+ static bool ClampToBounds (uint32_t start, uint32_t * length, uint32_t max) {
1022
1026
if (start > max) {
1023
1027
*length = 0 ;
1024
1028
return false ;
@@ -1031,6 +1035,17 @@ bool ClampToBounds(uint32_t start, uint32_t* length, uint32_t max) {
1031
1035
return true ;
1032
1036
}
1033
1037
1038
+ static bool CheckBounds (uint32_t start, uint32_t length, uint32_t max) {
1039
+ if (start > max) {
1040
+ return false ;
1041
+ }
1042
+ uint32_t avail = max - start;
1043
+ if (length > avail) {
1044
+ return false ;
1045
+ }
1046
+ return true ;
1047
+ }
1048
+
1034
1049
Result Thread::MemoryInit (const uint8_t ** pc) {
1035
1050
Memory* memory = ReadMemory (pc);
1036
1051
DataSegment* segment = ReadDataSegment (pc);
@@ -1039,22 +1054,20 @@ Result Thread::MemoryInit(const uint8_t** pc) {
1039
1054
uint32_t size = Pop<uint32_t >();
1040
1055
uint32_t src = Pop<uint32_t >();
1041
1056
uint32_t dst = Pop<uint32_t >();
1057
+ bool ok = CheckBounds (dst, size, memory_size);
1058
+ ok &= CheckBounds (src, size, segment_size);
1059
+ if (!ok) {
1060
+ TRAP_MSG (MemoryAccessOutOfBounds, " memory.init out of bounds" );
1061
+ }
1042
1062
if (size > 0 ) {
1043
- TRAP_IF (segment->dropped , DataSegmentDropped);
1044
- bool ok = ClampToBounds (dst, &size, memory_size);
1045
- ok &= ClampToBounds (src, &size, segment_size);
1046
- if (!ok) {
1047
- TRAP_MSG (MemoryAccessOutOfBounds, " memory.init out of bounds" );
1048
- }
1049
1063
memcpy (memory->data .data () + dst, segment->data .data () + src, size);
1050
1064
}
1051
1065
return ResultType::Ok;
1052
1066
}
1053
1067
1054
1068
Result Thread::DataDrop (const uint8_t ** pc) {
1055
1069
DataSegment* segment = ReadDataSegment (pc);
1056
- TRAP_IF (segment->dropped , DataSegmentDropped);
1057
- segment->dropped = true ;
1070
+ segment->data .clear ();
1058
1071
return ResultType::Ok;
1059
1072
}
1060
1073
@@ -1064,12 +1077,12 @@ Result Thread::MemoryCopy(const uint8_t** pc) {
1064
1077
uint32_t size = Pop<uint32_t >();
1065
1078
uint32_t src = Pop<uint32_t >();
1066
1079
uint32_t dst = Pop<uint32_t >();
1080
+ bool ok = CheckBounds (dst, size, memory_size);
1081
+ ok &= CheckBounds (src, size, memory_size);
1082
+ if (!ok) {
1083
+ TRAP_MSG (MemoryAccessOutOfBounds, " memory.copy out of bound" );
1084
+ }
1067
1085
if (size > 0 ) {
1068
- bool ok = ClampToBounds (dst, &size, memory_size);
1069
- ok &= ClampToBounds (src, &size, memory_size);
1070
- if (!ok) {
1071
- TRAP_MSG (MemoryAccessOutOfBounds, " memory.copy out of bound" );
1072
- }
1073
1086
char * data = memory->data .data ();
1074
1087
memmove (data + dst, data + src, size);
1075
1088
}
@@ -1082,11 +1095,10 @@ Result Thread::MemoryFill(const uint8_t** pc) {
1082
1095
uint32_t size = Pop<uint32_t >();
1083
1096
uint8_t value = static_cast <uint8_t >(Pop<uint32_t >());
1084
1097
uint32_t dst = Pop<uint32_t >();
1098
+ if (!CheckBounds (dst, size, memory_size)) {
1099
+ TRAP_MSG (MemoryAccessOutOfBounds, " memory.fill out of bounds" );
1100
+ }
1085
1101
if (size > 0 ) {
1086
- bool ok = ClampToBounds (dst, &size, memory_size);
1087
- if (!ok) {
1088
- TRAP_MSG (MemoryAccessOutOfBounds, " memory.fill out of bounds" );
1089
- }
1090
1102
memset (memory->data .data () + dst, value, size);
1091
1103
}
1092
1104
return ResultType::Ok;
@@ -1099,13 +1111,12 @@ Result Thread::TableInit(const uint8_t** pc) {
1099
1111
uint32_t size = Pop<uint32_t >();
1100
1112
uint32_t src = Pop<uint32_t >();
1101
1113
uint32_t dst = Pop<uint32_t >();
1114
+ bool ok = CheckBounds (dst, size, table->size ());
1115
+ ok &= CheckBounds (src, size, segment_size);
1116
+ if (!ok) {
1117
+ TRAP_MSG (TableAccessOutOfBounds, " table.init out of bounds" );
1118
+ }
1102
1119
if (size > 0 ) {
1103
- TRAP_IF (segment->dropped , ElemSegmentDropped);
1104
- bool ok = ClampToBounds (dst, &size, table->size ());
1105
- ok &= ClampToBounds (src, &size, segment_size);
1106
- if (!ok) {
1107
- TRAP_MSG (TableAccessOutOfBounds, " table.init out of bounds" );
1108
- }
1109
1120
memcpy (table->entries .data () + dst, segment->elems .data () + src,
1110
1121
size * sizeof (table->entries [0 ]));
1111
1122
}
@@ -1144,14 +1155,13 @@ Result Thread::TableFill(const uint8_t** pc) {
1144
1155
for (uint32_t i = 0 ; i < size; i++) {
1145
1156
table->entries [dst+i] = value;
1146
1157
}
1147
- TRAP_IF (!ok, MemoryAccessOutOfBounds );
1158
+ TRAP_IF (!ok, TableAccessOutOfBounds );
1148
1159
return ResultType::Ok;
1149
1160
}
1150
1161
1151
1162
Result Thread::ElemDrop (const uint8_t ** pc) {
1152
1163
ElemSegment* segment = ReadElemSegment (pc);
1153
- TRAP_IF (segment->dropped , ElemSegmentDropped);
1154
- segment->dropped = true ;
1164
+ segment->elems .clear ();
1155
1165
return ResultType::Ok;
1156
1166
}
1157
1167
@@ -1162,12 +1172,12 @@ Result Thread::TableCopy(const uint8_t** pc) {
1162
1172
uint32_t size = Pop<uint32_t >();
1163
1173
uint32_t src = Pop<uint32_t >();
1164
1174
uint32_t dst = Pop<uint32_t >();
1175
+ bool ok = CheckBounds (dst, size, dst_table->size ());
1176
+ ok &= CheckBounds (src, size, dst_table->size ());
1177
+ if (!ok) {
1178
+ TRAP_MSG (TableAccessOutOfBounds, " table.copy out of bounds" );
1179
+ }
1165
1180
if (size > 0 ) {
1166
- bool ok = ClampToBounds (dst, &size, dst_table->size ());
1167
- ok &= ClampToBounds (src, &size, dst_table->size ());
1168
- if (!ok) {
1169
- TRAP_MSG (TableAccessOutOfBounds, " table.copy out of bounds" );
1170
- }
1171
1181
Ref* data_src = src_table->entries .data ();
1172
1182
Ref* data_dst = dst_table->entries .data ();
1173
1183
memmove (data_dst + dst, data_src + src, size * sizeof (Ref));
@@ -3755,40 +3765,36 @@ Result Executor::InitializeSegments(DefinedModule* module) {
3755
3765
uint32_t table_size = info.table ->size ();
3756
3766
uint32_t segment_size = info.src .size ();
3757
3767
uint32_t copy_size = segment_size;
3758
- bool ok = ClampToBounds (info.dst , ©_size, table_size);
3759
-
3760
- if (pass == Init && copy_size > 0 ) {
3761
- std::copy (info.src .begin (), info.src .begin () + copy_size,
3762
- info.table ->entries .begin () + info.dst );
3763
- }
3764
-
3765
- if (!ok) {
3768
+ if (!CheckBounds (info.dst , copy_size, table_size)) {
3766
3769
TRAP_MSG (TableAccessOutOfBounds,
3767
3770
" elem segment is out of bounds: [%u, %" PRIu64
3768
3771
" ) >= max value %u" ,
3769
3772
info.dst , static_cast <uint64_t >(info.dst ) + segment_size,
3770
3773
table_size);
3771
3774
}
3775
+
3776
+ if (pass == Init && copy_size > 0 ) {
3777
+ std::copy (info.src .begin (), info.src .begin () + copy_size,
3778
+ info.table ->entries .begin () + info.dst );
3779
+ }
3772
3780
}
3773
3781
3774
3782
for (const DataSegmentInfo& info : module->active_data_segments_ ) {
3775
3783
uint32_t memory_size = info.memory ->data .size ();
3776
3784
uint32_t segment_size = info.data .size ();
3777
3785
uint32_t copy_size = segment_size;
3778
- bool ok = ClampToBounds (info.dst , ©_size, memory_size);
3779
-
3780
- if (pass == Init && copy_size > 0 ) {
3781
- std::copy (info.data .begin (), info.data .begin () + copy_size,
3782
- info.memory ->data .begin () + info.dst );
3783
- }
3784
-
3785
- if (!ok) {
3786
+ if (!CheckBounds (info.dst , copy_size, memory_size)) {
3786
3787
TRAP_MSG (MemoryAccessOutOfBounds,
3787
3788
" data segment is out of bounds: [%u, %" PRIu64
3788
3789
" ) >= max value %u" ,
3789
3790
info.dst , static_cast <uint64_t >(info.dst ) + segment_size,
3790
3791
memory_size);
3791
3792
}
3793
+
3794
+ if (pass == Init && copy_size > 0 ) {
3795
+ std::copy (info.data .begin (), info.data .begin () + copy_size,
3796
+ info.memory ->data .begin () + info.dst );
3797
+ }
3792
3798
}
3793
3799
}
3794
3800
0 commit comments