Skip to content

Commit eb0aefe

Browse files
authored
[html5] Align event_data in callback_args_t to max_align_t (#27450)
Align `event_data` flexible array member in `callback_args_t` to `max_align_t` so that structure members requiring 8-byte alignment (e.g., doubles in `EmscriptenWheelEvent`) do not cause misaligned reads and trigger alignment faults under `-sSAFE_HEAP=1`. Fixes: #27447
1 parent f4509e4 commit eb0aefe

3 files changed

Lines changed: 68 additions & 1 deletion

File tree

system/lib/html5/callback.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
* found in the LICENSE file.
66
*/
77
#include <assert.h>
8+
#include <stdalign.h>
9+
#include <stddef.h>
810
#include <string.h>
911
#include <emscripten/html5.h>
1012

@@ -16,7 +18,10 @@ typedef struct callback_args_t {
1618
event_callback callback;
1719
int event_type;
1820
void *user_data;
19-
uint8_t event_data[];
21+
// Since we cast this to various event types it needs to be at aligned to the
22+
// to the same level as any the event types. The simplest way to achieve
23+
// this is with max_align-t.
24+
alignas(max_align_t) uint8_t event_data[];
2025
} callback_args_t;
2126

2227
static void do_callback(void* arg) {
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright 2026 The Emscripten Authors. All rights reserved.
3+
* Emscripten is available under two separate licenses, the MIT license and the
4+
* University of Illinois/NCSA Open Source License. Both these licenses can be
5+
* found in the LICENSE file.
6+
*/
7+
8+
#include <assert.h>
9+
#include <emscripten.h>
10+
#include <emscripten/html5.h>
11+
#include <emscripten/threading.h>
12+
#include <pthread.h>
13+
#include <stdbool.h>
14+
#include <stdint.h>
15+
#include <stdio.h>
16+
#include <stdlib.h>
17+
#include <string.h>
18+
19+
typedef bool (*event_callback)(int event_type, void *event_data, void *user_data);
20+
extern void _emscripten_run_callback_on_thread(pthread_t t,
21+
event_callback f,
22+
int event_type,
23+
void *event_data,
24+
size_t event_data_size,
25+
void *user_data);
26+
27+
static bool on_wheel(int event_type, void *event_data, void *user_data) {
28+
const EmscriptenWheelEvent *e = (const EmscriptenWheelEvent *)event_data;
29+
// Test that the event_data contents are properly aligned. These accesses
30+
// will fail under SAFE_HEAP if they are not.
31+
assert(e->deltaX == 1.0);
32+
assert(e->deltaY == 2.0);
33+
assert(e->deltaZ == 3.0);
34+
printf("done\n");
35+
emscripten_force_exit(0);
36+
return true;
37+
}
38+
39+
static void *sender(void *arg) {
40+
pthread_t target = (pthread_t)arg;
41+
EmscriptenWheelEvent ev;
42+
memset(&ev, 0, sizeof(ev));
43+
ev.deltaX = 1.0;
44+
ev.deltaY = 2.0;
45+
ev.deltaZ = 3.0;
46+
_emscripten_run_callback_on_thread(target, on_wheel, EMSCRIPTEN_EVENT_WHEEL,
47+
&ev, sizeof(ev), NULL);
48+
return NULL;
49+
}
50+
51+
static void dummy(void) {}
52+
53+
int main(void) {
54+
pthread_t t;
55+
pthread_create(&t, NULL, sender, (void *)pthread_self());
56+
emscripten_set_main_loop(dummy, 1, 0);
57+
}

test/test_other.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13448,6 +13448,11 @@ def test_pthread_growth_mainthread(self, cflags):
1344813448
self.cflags.append('-Wno-pthreads-mem-growth')
1344913449
self.do_runf('pthread/test_pthread_memory_growth_mainthread.c', cflags=['-pthread', '-sALLOW_MEMORY_GROWTH', '-sINITIAL_MEMORY=32MB', '-sMAXIMUM_MEMORY=256MB'] + cflags)
1345013450

13451+
@requires_pthreads
13452+
def test_pthread_callback_alignment(self):
13453+
# Use `SAFE_HEAP` here so that incorrect alignment will trap.
13454+
self.do_runf('pthread/test_pthread_callback_alignment.c', 'done\n', cflags=['-sSAFE_HEAP'])
13455+
1345113456
@requires_pthreads
1345213457
def test_pthread_join_interrupted(self):
1345313458
self.do_runf('pthread/test_pthread_join_interrupted.c', cflags=['-pthread'])

0 commit comments

Comments
 (0)