diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 94f81908da..dfdaca6d3f 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -1084,7 +1084,7 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo { std.macho.LC_SYMTAB => break @ptrCast(*std.macho.symtab_command, ptr), else => {}, } - ptr += lc.cmdsize; // TODO https://github.com/ziglang/zig/issues/1403 + ptr = @alignCast(@alignOf(std.macho.load_command), ptr + lc.cmdsize); } else { return error.MissingDebugInfo; }; @@ -2129,7 +2129,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u std.macho.LC_SEGMENT_64 => break @ptrCast(*const std.macho.segment_command_64, @alignCast(@alignOf(std.macho.segment_command_64), ptr)), else => {}, } - ptr += lc.cmdsize; // TODO https://github.com/ziglang/zig/issues/1403 + ptr = @alignCast(@alignOf(std.macho.load_command), ptr + lc.cmdsize); } else { return error.MissingDebugInfo; }; diff --git a/lib/std/event/fs.zig b/lib/std/event/fs.zig index 5986f07ad3..ce88ac4dc4 100644 --- a/lib/std/event/fs.zig +++ b/lib/std/event/fs.zig @@ -1263,7 +1263,7 @@ pub fn Watch(comptime V: type) type { var ptr = event_buf[0..].ptr; const end_ptr = ptr + event_buf.len; var ev: *os.linux.inotify_event = undefined; - while (@ptrToInt(ptr) < @ptrToInt(end_ptr)) : (ptr += @sizeOf(os.linux.inotify_event) + ev.len) { + while (@ptrToInt(ptr) < @ptrToInt(end_ptr)) { ev = @ptrCast(*os.linux.inotify_event, ptr); if (ev.mask & os.linux.IN_CLOSE_WRITE == os.linux.IN_CLOSE_WRITE) { const basename_ptr = ptr + @sizeOf(os.linux.inotify_event); @@ -1287,6 +1287,8 @@ pub fn Watch(comptime V: type) type { }); } } + + ptr = @alignCast(@alignOf(os.linux.inotify_event), ptr + @sizeOf(os.linux.inotify_event) + ev.len); } }, os.linux.EINTR => continue, diff --git a/lib/std/start.zig b/lib/std/start.zig index b982692a08..c3844e4d1e 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -142,14 +142,14 @@ fn posixCallMainAndExit() noreturn { const argc = starting_stack_ptr[0]; const argv = @ptrCast([*][*:0]u8, starting_stack_ptr + 1); - const envp_optional = @ptrCast([*:null]?[*:0]u8, argv + argc + 1); + const envp_optional = @ptrCast([*:null]?[*:0]u8, @alignCast(@alignOf(usize), argv + argc + 1)); var envp_count: usize = 0; while (envp_optional[envp_count]) |_| : (envp_count += 1) {} const envp = @ptrCast([*][*:0]u8, envp_optional)[0..envp_count]; if (builtin.os == .linux) { // Find the beginning of the auxiliary vector - const auxv = @ptrCast([*]std.elf.Auxv, envp.ptr + envp_count + 1); + const auxv = @ptrCast([*]std.elf.Auxv, @alignCast(@alignOf(usize), envp.ptr + envp_count + 1)); std.os.linux.elf_aux_maybe = auxv; // Initialize the TLS area const gnu_stack_phdr = std.os.linux.tls.initTLS() orelse @panic("ELF missing stack size"); diff --git a/src/ir.cpp b/src/ir.cpp index 24e930eb99..9f45ff5b2f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -15783,19 +15783,51 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp return ir_const_undef(ira, &instruction->base, op1->value->type); } + ZigType *elem_type = op1->value->type->data.pointer.child_type; + if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown))) + return ira->codegen->invalid_instruction; + + // NOTE: this variable is meaningful iff op2_val is not null! + uint64_t byte_offset; + if (op2_val != nullptr) { + uint64_t elem_offset; + if (!ir_resolve_usize(ira, casted_op2, &elem_offset)) + return ira->codegen->invalid_instruction; + + byte_offset = type_size(ira->codegen, elem_type) * elem_offset; + } + + // Fast path for cases where the RHS is zero + if (op2_val != nullptr && byte_offset == 0) { + return op1; + } + + ZigType *result_type = op1->value->type; + // Calculate the new alignment of the pointer + { + uint32_t align_bytes; + if ((err = resolve_ptr_align(ira, op1->value->type, &align_bytes))) + return ira->codegen->invalid_instruction; + + // If the addend is not a comptime-known value we can still count on + // it being a multiple of the type size + uint32_t addend = op2_val ? byte_offset : type_size(ira->codegen, elem_type); + + // The resulting pointer is aligned to the lcd between the + // offset (an arbitrary number) and the alignment factor (always + // a power of two, non zero) + uint32_t new_align = 1 << ctzll(addend | align_bytes); + // Rough guard to prevent overflows + assert(new_align); + result_type = adjust_ptr_align(ira->codegen, result_type, new_align); + } + if (op2_val != nullptr && op1_val != nullptr && (op1->value->data.x_ptr.special == ConstPtrSpecialHardCodedAddr || op1->value->data.x_ptr.special == ConstPtrSpecialNull)) { uint64_t start_addr = (op1_val->data.x_ptr.special == ConstPtrSpecialNull) ? 0 : op1_val->data.x_ptr.data.hard_coded_addr.addr; - uint64_t elem_offset; - if (!ir_resolve_usize(ira, casted_op2, &elem_offset)) - return ira->codegen->invalid_instruction; - ZigType *elem_type = op1_val->type->data.pointer.child_type; - if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_instruction; - uint64_t byte_offset = type_size(ira->codegen, elem_type) * elem_offset; uint64_t new_addr; if (op_id == IrBinOpAdd) { new_addr = start_addr + byte_offset; @@ -15804,7 +15836,7 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp } else { zig_unreachable(); } - IrInstruction *result = ir_const(ira, &instruction->base, op1_val->type); + IrInstruction *result = ir_const(ira, &instruction->base, result_type); result->value->data.x_ptr.special = ConstPtrSpecialHardCodedAddr; result->value->data.x_ptr.mut = ConstPtrMutRuntimeVar; result->value->data.x_ptr.data.hard_coded_addr.addr = new_addr; @@ -15813,7 +15845,7 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp IrInstruction *result = ir_build_bin_op(&ira->new_irb, instruction->base.scope, instruction->base.source_node, op_id, op1, casted_op2, true); - result->value->type = op1->value->type; + result->value->type = result_type; return result; } diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig index e1004243fc..fdaa5867d7 100644 --- a/test/stage1/behavior/pointers.zig +++ b/test/stage1/behavior/pointers.zig @@ -288,3 +288,33 @@ test "pointer to array at fixed address" { // Silly check just to reference `array` expect(@ptrToInt(&array[0]) == 0x10); } + +test "pointer arithmetic affects the alignment" { + { + var ptr: [*]align(8) u32 = undefined; + var x: usize = 1; + + expect(@typeInfo(@TypeOf(ptr)).Pointer.alignment == 8); + const ptr1 = ptr + 1; // 1 * 4 = 4 -> lcd(4,8) = 4 + expect(@typeInfo(@TypeOf(ptr1)).Pointer.alignment == 4); + const ptr2 = ptr + 4; // 4 * 4 = 16 -> lcd(16,8) = 8 + expect(@typeInfo(@TypeOf(ptr2)).Pointer.alignment == 8); + const ptr3 = ptr + 0; // no-op + expect(@typeInfo(@TypeOf(ptr3)).Pointer.alignment == 8); + const ptr4 = ptr + x; // runtime-known addend + expect(@typeInfo(@TypeOf(ptr4)).Pointer.alignment == 4); + } + { + var ptr: [*]align(8) [3]u8 = undefined; + var x: usize = 1; + + const ptr1 = ptr + 17; // 3 * 17 = 51 + expect(@typeInfo(@TypeOf(ptr1)).Pointer.alignment == 1); + const ptr2 = ptr + x; // runtime-known addend + expect(@typeInfo(@TypeOf(ptr2)).Pointer.alignment == 1); + const ptr3 = ptr + 8; // 3 * 8 = 24 -> lcd(8,24) = 8 + expect(@typeInfo(@TypeOf(ptr3)).Pointer.alignment == 8); + const ptr4 = ptr + 4; // 3 * 4 = 12 -> lcd(8,12) = 4 + expect(@typeInfo(@TypeOf(ptr4)).Pointer.alignment == 4); + } +}