@@ -495,9 +495,21 @@ fn setupMemory(self: *Wasm) !void {
495
495
log .debug ("Setting up memory layout" , .{});
496
496
const page_size = 64 * 1024 ;
497
497
const stack_size = self .base .options .stack_size_override orelse page_size * 1 ;
498
- const stack_alignment = 16 ;
499
- var memory_ptr : u64 = self .base .options .global_base orelse 1024 ;
500
- memory_ptr = std .mem .alignForwardGeneric (u64 , memory_ptr , stack_alignment );
498
+ const stack_alignment = 16 ; // wasm's stack alignment as specified by tool-convention
499
+ // Always place the stack at the start by default
500
+ // unless the user specified the global-base flag
501
+ var place_stack_first = true ;
502
+ var memory_ptr : u64 = if (self .base .options .global_base ) | base | blk : {
503
+ place_stack_first = false ;
504
+ break :blk base ;
505
+ } else 0 ;
506
+
507
+ if (place_stack_first ) {
508
+ memory_ptr = std .mem .alignForwardGeneric (u64 , memory_ptr , stack_alignment );
509
+ memory_ptr += stack_size ;
510
+ // We always put the stack pointer global at index 0
511
+ self .globals .items [0 ].init .i32_const = @bitCast (i32 , @intCast (u32 , memory_ptr ));
512
+ }
501
513
502
514
var offset : u32 = @intCast (u32 , memory_ptr );
503
515
for (self .segments .items ) | * segment , i | {
@@ -511,8 +523,11 @@ fn setupMemory(self: *Wasm) !void {
511
523
offset += segment .size ;
512
524
}
513
525
514
- memory_ptr = std .mem .alignForwardGeneric (u64 , memory_ptr , stack_alignment );
515
- memory_ptr += stack_size ;
526
+ if (! place_stack_first ) {
527
+ memory_ptr = std .mem .alignForwardGeneric (u64 , memory_ptr , stack_alignment );
528
+ memory_ptr += stack_size ;
529
+ self .globals .items [0 ].init .i32_const = @bitCast (i32 , @intCast (u32 , memory_ptr ));
530
+ }
516
531
517
532
// Setup the max amount of pages
518
533
// For now we only support wasm32 by setting the maximum allowed memory size 2^32-1
@@ -555,9 +570,6 @@ fn setupMemory(self: *Wasm) !void {
555
570
self .memories .limits .max = @intCast (u32 , max_memory / page_size );
556
571
log .debug ("Maximum memory pages: {d}" , .{self .memories .limits .max });
557
572
}
558
-
559
- // We always put the stack pointer global at index 0
560
- self .globals .items [0 ].init .i32_const = @bitCast (i32 , @intCast (u32 , memory_ptr ));
561
573
}
562
574
563
575
fn resetState (self : * Wasm ) void {
@@ -1105,6 +1117,12 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
1105
1117
if (self .base .options .global_base ) | global_base | {
1106
1118
const arg = try std .fmt .allocPrint (arena , "--global-base={d}" , .{global_base });
1107
1119
try argv .append (arg );
1120
+ } else {
1121
+ // We prepend it by default, so when a stack overflow happens the runtime will trap correctly,
1122
+ // rather than silently overwrite all global declarations. See https://github.com/ziglang/zig/issues/4496
1123
+ //
1124
+ // The user can overwrite this behavior by setting the global-base
1125
+ try argv .append ("--stack-first" );
1108
1126
}
1109
1127
1110
1128
// Users are allowed to specify which symbols they want to export to the wasm host.
@@ -1125,10 +1143,6 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
1125
1143
const arg = try std .fmt .allocPrint (arena , "stack-size={d}" , .{stack_size });
1126
1144
try argv .append (arg );
1127
1145
1128
- // Put stack before globals so that stack overflow results in segfault immediately
1129
- // before corrupting globals. See https://github.com/ziglang/zig/issues/4496
1130
- try argv .append ("--stack-first" );
1131
-
1132
1146
if (self .base .options .wasi_exec_model == .reactor ) {
1133
1147
// Reactor execution model does not have _start so lld doesn't look for it.
1134
1148
try argv .append ("--no-entry" );
0 commit comments