diff --git a/lib/std/core/bitorder.c3 b/lib/std/core/bitorder.c3 index 1aa2213db..5bfcfad96 100644 --- a/lib/std/core/bitorder.c3 +++ b/lib/std/core/bitorder.c3 @@ -90,33 +90,35 @@ bitstruct UInt128LE : uint128 @littleendian <* @require @is_array_or_slice_of_char(bytes) : "argument must be an array, a pointer to an array or a slice of char" @require is_bitorder($Type) : "type must be a bitorder integer" + @require $defined(*bytes) ||| $defined(bytes[:$Type.sizeof]) : "Data is too short to contain value" *> macro read(bytes, $Type) { - char[] s; + char *ptr; $switch $kindof(bytes): $case POINTER: - s = (*bytes)[:$Type.sizeof]; + ptr = bytes; $default: - s = bytes[:$Type.sizeof]; + ptr = bytes[..].ptr; $endswitch - return bitcast(*(char[$Type.sizeof]*)s.ptr, $Type).val; + return bitcast(@unaligned_load(*(char[$Type.sizeof]*)ptr, 1), $Type).val; } <* @require @is_arrayptr_or_slice_of_char(bytes) : "argument must be a pointer to an array or a slice of char" @require is_bitorder($Type) : "type must be a bitorder integer" + @require $defined(*bytes) ||| $defined(bytes[:$Type.sizeof]) : "Data is not sufficent to hold value" *> macro write(x, bytes, $Type) { - char[] s; + char *ptr; $switch $kindof(bytes): $case POINTER: - s = (*bytes)[:$Type.sizeof]; + ptr = bytes; $default: - s = bytes[:$Type.sizeof]; + ptr = bytes[..].ptr; $endswitch - *($typeof(x)*)s.ptr = bitcast(x, $Type).val; + @unaligned_store(*($typeof(x)*)ptr, bitcast(x, $Type).val, 1); } macro bool is_bitorder($Type) diff --git a/releasenotes.md b/releasenotes.md index 8444f198f..8001e9ff9 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -54,6 +54,7 @@ - Incorrect alignment on typedef and local variable debug info. - Assert on optional-returning-function in a comma expression. #2722 - Creating recursive debug info for functions could cause assertions. +- bitorder::read and bitorder::write may fail because of unaligned access #2734. ### Stdlib changes - Add `ThreadPool` join function to wait for all threads to finish in the pool without destroying the threads. diff --git a/test/unit/stdlib/core/bitorder.c3 b/test/unit/stdlib/core/bitorder.c3 index e6eb805a1..3c402cb75 100644 --- a/test/unit/stdlib/core/bitorder.c3 +++ b/test/unit/stdlib/core/bitorder.c3 @@ -1,5 +1,12 @@ module std::core::bitorder @test; +fn void test_unaligned() +{ + usz file_size; + char[64] response; + bitorder::write(file_size, response[9..], ULongLE); +} + fn void test_read() { char[*] bytes = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };