@@ -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,14 @@ 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
+ return length <= avail;
1044
+ }
1045
+
1034
1046
Result Thread::MemoryInit (const uint8_t ** pc) {
1035
1047
Memory* memory = ReadMemory (pc);
1036
1048
DataSegment* segment = ReadDataSegment (pc);
@@ -1039,22 +1051,20 @@ Result Thread::MemoryInit(const uint8_t** pc) {
1039
1051
uint32_t size = Pop<uint32_t >();
1040
1052
uint32_t src = Pop<uint32_t >();
1041
1053
uint32_t dst = Pop<uint32_t >();
1054
+ bool ok = CheckBounds (dst, size, memory_size);
1055
+ ok &= CheckBounds (src, size, segment_size);
1056
+ if (!ok) {
1057
+ TRAP_MSG (MemoryAccessOutOfBounds, " memory.init out of bounds" );
1058
+ }
1042
1059
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
1060
memcpy (memory->data .data () + dst, segment->data .data () + src, size);
1050
1061
}
1051
1062
return ResultType::Ok;
1052
1063
}
1053
1064
1054
1065
Result Thread::DataDrop (const uint8_t ** pc) {
1055
1066
DataSegment* segment = ReadDataSegment (pc);
1056
- TRAP_IF (segment->dropped , DataSegmentDropped);
1057
- segment->dropped = true ;
1067
+ segment->data .clear ();
1058
1068
return ResultType::Ok;
1059
1069
}
1060
1070
@@ -1064,12 +1074,12 @@ Result Thread::MemoryCopy(const uint8_t** pc) {
1064
1074
uint32_t size = Pop<uint32_t >();
1065
1075
uint32_t src = Pop<uint32_t >();
1066
1076
uint32_t dst = Pop<uint32_t >();
1077
+ bool ok = CheckBounds (dst, size, memory_size);
1078
+ ok &= CheckBounds (src, size, memory_size);
1079
+ if (!ok) {
1080
+ TRAP_MSG (MemoryAccessOutOfBounds, " memory.copy out of bound" );
1081
+ }
1067
1082
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
1083
char * data = memory->data .data ();
1074
1084
memmove (data + dst, data + src, size);
1075
1085
}
@@ -1082,11 +1092,10 @@ Result Thread::MemoryFill(const uint8_t** pc) {
1082
1092
uint32_t size = Pop<uint32_t >();
1083
1093
uint8_t value = static_cast <uint8_t >(Pop<uint32_t >());
1084
1094
uint32_t dst = Pop<uint32_t >();
1095
+ if (!CheckBounds (dst, size, memory_size)) {
1096
+ TRAP_MSG (MemoryAccessOutOfBounds, " memory.fill out of bounds" );
1097
+ }
1085
1098
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
1099
memset (memory->data .data () + dst, value, size);
1091
1100
}
1092
1101
return ResultType::Ok;
@@ -1099,13 +1108,12 @@ Result Thread::TableInit(const uint8_t** pc) {
1099
1108
uint32_t size = Pop<uint32_t >();
1100
1109
uint32_t src = Pop<uint32_t >();
1101
1110
uint32_t dst = Pop<uint32_t >();
1111
+ bool ok = CheckBounds (dst, size, table->size ());
1112
+ ok &= CheckBounds (src, size, segment_size);
1113
+ if (!ok) {
1114
+ TRAP_MSG (TableAccessOutOfBounds, " table.init out of bounds" );
1115
+ }
1102
1116
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
1117
memcpy (table->entries .data () + dst, segment->elems .data () + src,
1110
1118
size * sizeof (table->entries [0 ]));
1111
1119
}
@@ -1144,14 +1152,13 @@ Result Thread::TableFill(const uint8_t** pc) {
1144
1152
for (uint32_t i = 0 ; i < size; i++) {
1145
1153
table->entries [dst+i] = value;
1146
1154
}
1147
- TRAP_IF (!ok, MemoryAccessOutOfBounds );
1155
+ TRAP_IF (!ok, TableAccessOutOfBounds );
1148
1156
return ResultType::Ok;
1149
1157
}
1150
1158
1151
1159
Result Thread::ElemDrop (const uint8_t ** pc) {
1152
1160
ElemSegment* segment = ReadElemSegment (pc);
1153
- TRAP_IF (segment->dropped , ElemSegmentDropped);
1154
- segment->dropped = true ;
1161
+ segment->elems .clear ();
1155
1162
return ResultType::Ok;
1156
1163
}
1157
1164
@@ -1162,12 +1169,12 @@ Result Thread::TableCopy(const uint8_t** pc) {
1162
1169
uint32_t size = Pop<uint32_t >();
1163
1170
uint32_t src = Pop<uint32_t >();
1164
1171
uint32_t dst = Pop<uint32_t >();
1172
+ bool ok = CheckBounds (dst, size, dst_table->size ());
1173
+ ok &= CheckBounds (src, size, dst_table->size ());
1174
+ if (!ok) {
1175
+ TRAP_MSG (TableAccessOutOfBounds, " table.copy out of bounds" );
1176
+ }
1165
1177
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
1178
Ref* data_src = src_table->entries .data ();
1172
1179
Ref* data_dst = dst_table->entries .data ();
1173
1180
memmove (data_dst + dst, data_src + src, size * sizeof (Ref));
@@ -3755,40 +3762,36 @@ Result Executor::InitializeSegments(DefinedModule* module) {
3755
3762
uint32_t table_size = info.table ->size ();
3756
3763
uint32_t segment_size = info.src .size ();
3757
3764
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) {
3765
+ if (!CheckBounds (info.dst , copy_size, table_size)) {
3766
3766
TRAP_MSG (TableAccessOutOfBounds,
3767
3767
" elem segment is out of bounds: [%u, %" PRIu64
3768
3768
" ) >= max value %u" ,
3769
3769
info.dst , static_cast <uint64_t >(info.dst ) + segment_size,
3770
3770
table_size);
3771
3771
}
3772
+
3773
+ if (pass == Init && copy_size > 0 ) {
3774
+ std::copy (info.src .begin (), info.src .begin () + copy_size,
3775
+ info.table ->entries .begin () + info.dst );
3776
+ }
3772
3777
}
3773
3778
3774
3779
for (const DataSegmentInfo& info : module->active_data_segments_ ) {
3775
3780
uint32_t memory_size = info.memory ->data .size ();
3776
3781
uint32_t segment_size = info.data .size ();
3777
3782
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) {
3783
+ if (!CheckBounds (info.dst , copy_size, memory_size)) {
3786
3784
TRAP_MSG (MemoryAccessOutOfBounds,
3787
3785
" data segment is out of bounds: [%u, %" PRIu64
3788
3786
" ) >= max value %u" ,
3789
3787
info.dst , static_cast <uint64_t >(info.dst ) + segment_size,
3790
3788
memory_size);
3791
3789
}
3790
+
3791
+ if (pass == Init && copy_size > 0 ) {
3792
+ std::copy (info.data .begin (), info.data .begin () + copy_size,
3793
+ info.memory ->data .begin () + info.dst );
3794
+ }
3792
3795
}
3793
3796
}
3794
3797
0 commit comments