64-bit memory access alignment issues leading to segfault on sparc64
Downstream issue: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=945414
gcr is currently unavailable for the Debian port to sparc64 due to memory alignment issues. These stem from pointer aliasing issues when accessing attributes, where pointers are not 64-bit aligned, but the attribute is 64 bits wide. This leads to a bus error (segfault) on sparc64. It is apparently not an issue on other architectures.
The Linux kernel has some documentation on why unaligned memory access is a problem: https://www.kernel.org/doc/Documentation/unaligned-memory-access.txt
The Debian package builder runs all unit tests before creating the packages and fails at the end: https://buildd.debian.org/status/fetch.php?pkg=gcr&arch=sparc64&ver=3.34.0-1&stamp=1574705913&raw=0
I tracked the issues down to _gck_format_attributes and gck_value_to_ulong, plus some of the unit tests. A merge request is included.
FWIW, the memcpy
doesn't have an impact on amd64/gcc9 with -O2. The generated assembly is identical, because the compiler optimises the memcpy
out.
On sparc64, the memcpy
for CK_ULONG
is kept as a function call, but it is also optimised out for CK_BBOOL
due to natural 8-bit alignment of the type.
Assembly results are as follows:
amd64 gck_value_to_ulong with pointer aliasing:
Dump of assembler code for function gck_value_to_ulong:
0x0000000000013700 <+0>: test %rdi,%rdi
0x0000000000013703 <+3>: je 0x13720 <gck_value_to_ulong+32>
0x0000000000013705 <+5>: cmp $0x8,%rsi
0x0000000000013709 <+9>: jne 0x13720 <gck_value_to_ulong+32>
0x000000000001370b <+11>: mov $0x1,%eax
0x0000000000013710 <+16>: test %rdx,%rdx
0x0000000000013713 <+19>: je 0x13722 <gck_value_to_ulong+34>
0x0000000000013715 <+21>: mov (%rdi),%rcx
0x0000000000013718 <+24>: mov %rcx,(%rdx)
0x000000000001371b <+27>: retq
0x000000000001371c <+28>: nopl 0x0(%rax)
0x0000000000013720 <+32>: xor %eax,%eax
0x0000000000013722 <+34>: retq
amd64 gck_value_to_ulong with memcpy:
Dump of assembler code for function gck_value_to_ulong:
0x0000000000013730 <+0>: test %rdi,%rdi
0x0000000000013733 <+3>: je 0x13750 <gck_value_to_ulong+32>
0x0000000000013735 <+5>: cmp $0x8,%rsi
0x0000000000013739 <+9>: jne 0x13750 <gck_value_to_ulong+32>
0x000000000001373b <+11>: mov $0x1,%eax
0x0000000000013740 <+16>: test %rdx,%rdx
0x0000000000013743 <+19>: je 0x13752 <gck_value_to_ulong+34>
0x0000000000013745 <+21>: mov (%rdi),%rcx
0x0000000000013748 <+24>: mov %rcx,(%rdx)
0x000000000001374b <+27>: retq
0x000000000001374c <+28>: nopl 0x0(%rax)
0x0000000000013750 <+32>: xor %eax,%eax
0x0000000000013752 <+34>: retq
amd64 gck_value_to_boolean with pointer aliasing:
Dump of assembler code for function gck_value_to_boolean:
0x0000000000013730 <+0>: test %rdi,%rdi
0x0000000000013733 <+3>: je 0x13750 <gck_value_to_boolean+32>
0x0000000000013735 <+5>: cmp $0x1,%rsi
0x0000000000013739 <+9>: jne 0x13750 <gck_value_to_boolean+32>
0x000000000001373b <+11>: mov $0x1,%eax
0x0000000000013740 <+16>: test %rdx,%rdx
0x0000000000013743 <+19>: je 0x13752 <gck_value_to_boolean+34>
0x0000000000013745 <+21>: xor %ecx,%ecx
0x0000000000013747 <+23>: cmpb $0x0,(%rdi)
0x000000000001374a <+26>: setne %cl
0x000000000001374d <+29>: mov %ecx,(%rdx)
0x000000000001374f <+31>: retq
0x0000000000013750 <+32>: xor %eax,%eax
0x0000000000013752 <+34>: retq
amd64 gck_value_to_boolean with memcpy:
Dump of assembler code for function gck_value_to_boolean:
0x0000000000013760 <+0>: test %rdi,%rdi
0x0000000000013763 <+3>: je 0x13780 <gck_value_to_boolean+32>
0x0000000000013765 <+5>: cmp $0x1,%rsi
0x0000000000013769 <+9>: jne 0x13780 <gck_value_to_boolean+32>
0x000000000001376b <+11>: mov $0x1,%eax
0x0000000000013770 <+16>: test %rdx,%rdx
0x0000000000013773 <+19>: je 0x13782 <gck_value_to_boolean+34>
0x0000000000013775 <+21>: xor %ecx,%ecx
0x0000000000013777 <+23>: cmpb $0x0,(%rdi)
0x000000000001377a <+26>: setne %cl
0x000000000001377d <+29>: mov %ecx,(%rdx)
0x000000000001377f <+31>: retq
0x0000000000013780 <+32>: xor %eax,%eax
0x0000000000013782 <+34>: retq
On sparc64, gck_value_to_boolean doesn't change, but gck_value_to_ulong gets a memcpy call to avoid the misaligned memory access:
Dump of assembler code for function gck_value_to_ulong:
0x0000000000016338 <+0>: save %sp, -176, %sp
0x000000000001633c <+4>: xor %i1, 8, %i1
0x0000000000016340 <+8>: clr %g2
0x0000000000016344 <+12>: clr %g1
0x0000000000016348 <+16>: movre %i0, 1, %g2
0x000000000001634c <+20>: movrne %i1, 1, %g1
0x0000000000016350 <+24>: orcc %g2, %g1, %g0
0x0000000000016354 <+28>: bne,pn %icc, 0x16374 <gck_value_to_ulong+60>
0x0000000000016358 <+32>: clr %i5
0x000000000001635c <+36>: brz,pn %i2, 0x16374 <gck_value_to_ulong+60>
0x0000000000016360 <+40>: mov 1, %i5
0x0000000000016364 <+44>: mov 8, %o2
0x0000000000016368 <+48>: mov %i0, %o1
0x000000000001636c <+52>: call 0x134780 <memcpy@got.plt>
0x0000000000016370 <+56>: mov %i2, %o0
0x0000000000016374 <+60>: return %i7 + 8
0x0000000000016378 <+64>: sra %o5, 0, %o0