@samitouri / QOSamiQemu / commits / 11b01d307b

tests/tcg/plugins/mem: Don't access unaligned memory

In commit eb3f69cac62670 we removed the dependency of this mem plugin on the QEMU headers, but in doing that we introduced undefined behaviour when the plugin accesses unaligned memory. This shows up if you build with the gcc or clang undefined behaviour sanitizer (--enable-ubsan) and run 'make check-tcg', in numerous warnings like: ../../tests/tcg/plugins/mem.c:167:27: runtime error: load of misaligned address 0x7f1f300354b1 for type 'uint16_t' (aka 'unsigned short'), which requires 2 byte alignment 0x7f1f300354b1: note: pointer points here 00 00 00 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c ^ SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior ../../tests/tcg/plugins/mem.c:167:27 Fix this by rearranging the data reads and writes to use memcpy() instead. Fixes: eb3f69cac62670 ("tests/tcg/plugins/mem.c: remove dependency on qemu headers") Tested-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Link: https://lore.kernel.org/qemu-devel/20260305161531.1774895-2-peter.maydell@linaro.org Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>

Peter Maydell committed Mar 5, 2026 at 16:15 UTC 11b01d307b796c94d51ffd7ab7bf488282ca63da
1 file changed +30 -41
tests/tcg/plugins/mem.c
+30 -41
@@ -123,6 +123,9 @@ static void update_region_info(uint64_t region, uint64_t offset,
123 bool is_store = qemu_plugin_mem_is_store(meminfo);
124 RegionInfo *ri;
125 bool unseen_data = false;
126 + void *val_ptr;
127 + unsigned int val_size;
128 + qemu_plugin_mem_value swapped_value;
129
130 g_assert(offset + size <= region_size);
131
@@ -144,61 +147,46 @@ static void update_region_info(uint64_t region, uint64_t offset,
147 }
148
149 void *ri_data = &ri->data[offset];
150 +
151 + swapped_value.type = value.type;
152 switch (value.type) {
153 case QEMU_PLUGIN_MEM_VALUE_U8:
149 - {
150 - uint8_t val = value.data.u8;
151 - uint8_t *p = ri_data;
152 - if (is_store) {
153 - *p = val;
154 - } else {
155 - unseen_data = *p != val;
156 - }
154 + swapped_value.data.u8 = value.data.u8;
155 + val_ptr = &swapped_value.data.u8;
156 + val_size = 1;
157 break;
158 - }
158 case QEMU_PLUGIN_MEM_VALUE_U16:
160 - {
161 - uint16_t val = be ? GUINT16_FROM_BE(value.data.u16) :
162 - GUINT16_FROM_LE(value.data.u16);
163 - uint16_t *p = ri_data;
164 - if (is_store) {
165 - *p = val;
166 - } else {
167 - unseen_data = *p != val;
168 - }
159 + swapped_value.data.u16 = be ? GUINT16_FROM_BE(value.data.u16) :
160 + GUINT16_FROM_LE(value.data.u16);
161 + val_ptr = &swapped_value.data.u16;
162 + val_size = 2;
163 break;
170 - }
164 case QEMU_PLUGIN_MEM_VALUE_U32:
172 - {
173 - uint32_t val = be ? GUINT32_FROM_BE(value.data.u32) :
174 - GUINT32_FROM_LE(value.data.u32);
175 - uint32_t *p = ri_data;
176 - if (is_store) {
177 - *p = val;
178 - } else {
179 - unseen_data = *p != val;
180 - }
165 + swapped_value.data.u32 = be ? GUINT32_FROM_BE(value.data.u32) :
166 + GUINT32_FROM_LE(value.data.u32);
167 + val_ptr = &swapped_value.data.u32;
168 + val_size = 4;
169 break;
182 - }
170 case QEMU_PLUGIN_MEM_VALUE_U64:
184 - {
185 - uint64_t val = be ? GUINT64_FROM_BE(value.data.u64) :
186 - GUINT64_FROM_LE(value.data.u64);
187 - uint64_t *p = ri_data;
188 - if (is_store) {
189 - *p = val;
190 - } else {
191 - unseen_data = *p != val;
192 - }
171 + swapped_value.data.u64 = be ? GUINT64_FROM_BE(value.data.u64) :
172 + GUINT64_FROM_LE(value.data.u64);
173 + val_ptr = &swapped_value.data.u64;
174 + val_size = 8;
175 break;
194 - }
176 case QEMU_PLUGIN_MEM_VALUE_U128:
196 - /* non in test so skip */
197 - break;
177 + /* none in test so skip */
178 + goto done;
179 default:
180 g_assert_not_reached();
181 }
182
183 + /* ri_data may not be aligned, so we use memcpy/memcmp */
184 + if (is_store) {
185 + memcpy(ri_data, val_ptr, val_size);
186 + } else {
187 + unseen_data = memcmp(ri_data, val_ptr, val_size) != 0;
188 + }
189 +
190 /*
191 * This is expected for regions initialised by QEMU (.text etc) but we
192 * expect to see all data read and written to the test_data region
@@ -213,6 +201,7 @@ static void update_region_info(uint64_t region, uint64_t offset,
201 ri->seen_all = false;
202 }
203
204 +done:
205 g_mutex_unlock(&lock);
206 }
207