88#include " MapBuffer.h"
99#include < react/renderer/mapbuffer/MapBufferBuilder.h>
1010
11+ #include < cstring>
12+
1113namespace facebook ::react {
1214
15+ namespace {
16+ // Reads a value of type T from a (possibly unaligned) offset in the buffer.
17+ // MapBuffer's packed layout places multi-byte values at offsets that are not
18+ // naturally aligned for their type (e.g. an 8-byte value at a 2-byte boundary),
19+ // so dereferencing a reinterpret_cast pointer there is undefined behavior and
20+ // can fault on 32-bit ARM. memcpy compiles to a single unaligned load on
21+ // arm64/x86 and to alignment-safe loads on armv7.
22+ template <typename T>
23+ inline T readUnaligned (const uint8_t * data, int32_t offset) {
24+ T value;
25+ std::memcpy (&value, data + offset, sizeof (T));
26+ return value;
27+ }
28+ } // namespace
29+
1330static inline int32_t bucketOffset (int32_t index) {
1431 return sizeof (MapBuffer::Header) + sizeof (MapBuffer::Bucket) * index;
1532}
@@ -18,17 +35,19 @@ static inline int32_t valueOffset(int32_t bucketIndex) {
1835 return bucketOffset (bucketIndex) + offsetof (MapBuffer::Bucket, data);
1936}
2037
38+ // Dynamic-data entries pack [offset (low 32 bits)][byteLength (high 32 bits)]
39+ // into the bucket's 8-byte value, so the payload in the dynamic data section
40+ // carries no in-band length prefix. This returns the position of the high
41+ // 32 bits (the length).
42+ static inline int32_t lengthOffset (int32_t bucketIndex) {
43+ return valueOffset (bucketIndex) + static_cast <int32_t >(sizeof (int32_t ));
44+ }
45+
2146// TODO T83483191: Extend MapBuffer C++ implementation to support basic random
2247// access
2348MapBuffer::MapBuffer (std::vector<uint8_t > data) : bytes_(std::move(data)) {
2449 auto header = reinterpret_cast <const Header*>(bytes_.data ());
2550 count_ = header->count ;
26-
27- if (header->bufferSize != bytes_.size ()) {
28- LOG (ERROR ) << " Error: Data size does not match, expected "
29- << header->bufferSize << " found: " << bytes_.size ();
30- abort ();
31- }
3251}
3352
3453int32_t MapBuffer::getKeyBucket (Key key) const {
@@ -37,8 +56,7 @@ int32_t MapBuffer::getKeyBucket(Key key) const {
3756 while (lo <= hi) {
3857 int32_t mid = (lo + hi) >> 1 ;
3958
40- Key midVal =
41- *reinterpret_cast <const Key*>(bytes_.data () + bucketOffset (mid));
59+ Key midVal = readUnaligned<Key>(bytes_.data (), bucketOffset (mid));
4260
4361 if (midVal < key) {
4462 lo = mid + 1 ;
@@ -53,8 +71,7 @@ int32_t MapBuffer::getKeyBucket(Key key) const {
5371}
5472
5573inline int32_t MapBuffer::getIntAtBucket (int32_t bucketIndex) const {
56- return *reinterpret_cast <const int32_t *>(
57- bytes_.data () + valueOffset (bucketIndex));
74+ return readUnaligned<int32_t >(bytes_.data (), valueOffset (bucketIndex));
5875}
5976
6077int32_t MapBuffer::getInt (Key key) const {
@@ -74,8 +91,7 @@ int64_t MapBuffer::getLong(Key key) const {
7491 return 0 ;
7592 }
7693
77- return *reinterpret_cast <const int64_t *>(
78- bytes_.data () + valueOffset (bucketIndex));
94+ return readUnaligned<int64_t >(bytes_.data (), valueOffset (bucketIndex));
7995}
8096
8197bool MapBuffer::getBool (Key key) const {
@@ -89,8 +105,7 @@ double MapBuffer::getDouble(Key key) const {
89105 return 0 ;
90106 }
91107
92- return *reinterpret_cast <const double *>(
93- bytes_.data () + valueOffset (bucketIndex));
108+ return readUnaligned<double >(bytes_.data (), valueOffset (bucketIndex));
94109}
95110
96111int32_t MapBuffer::getDynamicDataOffset () const {
@@ -108,8 +123,8 @@ std::string MapBuffer::getString(Key key) const {
108123
109124 int32_t offset = getDynamicDataOffset () + getIntAtBucket (bucketIndex);
110125 int32_t stringLength =
111- * reinterpret_cast < const int32_t * >(bytes_.data () + offset );
112- const uint8_t * stringPtr = bytes_.data () + offset + sizeof ( int ) ;
126+ readUnaligned< int32_t >(bytes_.data (), lengthOffset (bucketIndex) );
127+ const uint8_t * stringPtr = bytes_.data () + offset;
113128
114129 return {stringPtr, stringPtr + stringLength};
115130}
@@ -123,16 +138,15 @@ MapBuffer MapBuffer::getMapBuffer(Key key) const {
123138
124139 int32_t offset = getDynamicDataOffset () + getIntAtBucket (bucketIndex);
125140 int32_t mapBufferLength =
126- * reinterpret_cast < const int32_t * >(bytes_.data () + offset );
127- size_t maxLength = bytes_.size () - offset - sizeof ( int32_t ) ;
128- if (mapBufferLength > maxLength) {
129- mapBufferLength = maxLength;
141+ readUnaligned< int32_t >(bytes_.data (), lengthOffset (bucketIndex) );
142+ size_t maxLength = bytes_.size () - offset;
143+ if (static_cast < size_t >( mapBufferLength) > maxLength) {
144+ mapBufferLength = static_cast < int32_t >( maxLength) ;
130145 }
131146
132147 std::vector<uint8_t > value (mapBufferLength);
133148
134- memcpy (
135- value.data (), bytes_.data () + offset + sizeof (int32_t ), mapBufferLength);
149+ memcpy (value.data (), bytes_.data () + offset, mapBufferLength);
136150
137151 return MapBuffer (std::move (value));
138152}
@@ -147,13 +161,12 @@ std::vector<MapBuffer> MapBuffer::getMapBufferList(MapBuffer::Key key) const {
147161 std::vector<MapBuffer> mapBufferList;
148162 int32_t offset = getDynamicDataOffset () + getIntAtBucket (bucketIndex);
149163 int32_t mapBufferListLength =
150- *reinterpret_cast <const int32_t *>(bytes_.data () + offset);
151- offset = offset + sizeof (uint32_t );
164+ readUnaligned<int32_t >(bytes_.data (), lengthOffset (bucketIndex));
152165
153166 int32_t curLen = 0 ;
154167 while (curLen < mapBufferListLength) {
155168 int32_t mapBufferLength =
156- * reinterpret_cast < const int32_t * >(bytes_.data () + offset + curLen);
169+ readUnaligned< int32_t >(bytes_.data (), offset + curLen);
157170 curLen = curLen + sizeof (uint32_t );
158171 std::vector<uint8_t > value (mapBufferLength);
159172 memcpy (value.data (), bytes_.data () + offset + curLen, mapBufferLength);
@@ -171,14 +184,14 @@ std::vector<int32_t> MapBuffer::getIntBuffer(MapBuffer::Key key) const {
171184 }
172185
173186 int32_t offset = getDynamicDataOffset () + getIntAtBucket (bucketIndex);
174- int32_t count = *reinterpret_cast <const int32_t *>(bytes_.data () + offset);
187+ int32_t byteLength =
188+ readUnaligned<int32_t >(bytes_.data (), lengthOffset (bucketIndex));
189+ int32_t count = byteLength / static_cast <int32_t >(sizeof (int32_t ));
175190
176191 std::vector<int32_t > result (count);
177- if (count > 0 ) {
192+ if (byteLength > 0 ) {
178193 memcpy (
179- result.data (),
180- bytes_.data () + offset + sizeof (int32_t ),
181- static_cast <size_t >(count) * sizeof (int32_t ));
194+ result.data (), bytes_.data () + offset, static_cast <size_t >(byteLength));
182195 }
183196 return result;
184197}
@@ -191,14 +204,14 @@ std::vector<double> MapBuffer::getDoubleBuffer(MapBuffer::Key key) const {
191204 }
192205
193206 int32_t offset = getDynamicDataOffset () + getIntAtBucket (bucketIndex);
194- int32_t count = *reinterpret_cast <const int32_t *>(bytes_.data () + offset);
207+ int32_t byteLength =
208+ readUnaligned<int32_t >(bytes_.data (), lengthOffset (bucketIndex));
209+ int32_t count = byteLength / static_cast <int32_t >(sizeof (double ));
195210
196211 std::vector<double > result (count);
197- if (count > 0 ) {
212+ if (byteLength > 0 ) {
198213 memcpy (
199- result.data (),
200- bytes_.data () + offset + sizeof (int32_t ),
201- static_cast <size_t >(count) * sizeof (double ));
214+ result.data (), bytes_.data () + offset, static_cast <size_t >(byteLength));
202215 }
203216 return result;
204217}
0 commit comments