<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/86895>86895</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
Segfault due to apparent unaligned movaps instructions generated to initialize instance char array member
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
clipcarl
</td>
</tr>
</table>
<pre>
I've come across a C++ issue where instantiating some objects in programs compiled by Clang segfaults.
Debugging suggests that Clang is generating SSE `movaps` instructions to initialize some char arrays and it's these instructions that appear to cause segfaults in some circumstances. I see on the issue tracker that somewhat similar issues with unaligned movaps instructions causing segfaults have been reported many times over the years but it doesn't look like this particular version has been reported or fixed yet.
I've tested on multiple x86-64 Linux systems with the GNU binutils linker with both Clang 16 and Clang 17 with the same results. The problem also occurs when using LLVM's own LLD linker. I don't know if the same problem occurs under other x86-64 operating systems or with other linkers. The problem does **not** occur when using versions of the GCC compiler instead of Clang.
The segfaults occur for some objects under the following minimum set of conditions:
- x86-64 code generation
- Optimization is enabled (-O1 or above)
- Binary built without Clang's default startup code and without the standard C library (`-nstdlib` option to Clang) and of course also without the standard C++ library. (Use of the `-fno-builtin` option makes no difference. I provide my own well-tested memcpy(), memset(), etc. when compiling with `-fno-builtin`.)
Here is minimal code to reproduce. Compile with the following on an x86-64 Linux system:
```
$ clang -O1 -nostdlib -fno-stack-protector -static clang_segv.s clang_segv.cc -o clang_segv
```
clang_segv.cc:
```
struct SegV
{
void set(const char *s) { char *b = buf; while ( *s ) { *b++ = *s++; } *b = '\0'; }
char buf[128] = "";
char *cursor = buf; // needed for segfault
};
int
main()
{
SegV v;
v.set("aa");
return 0;
}
```
clang_segv.s:
```
.intel_syntax noprefix
.global _start
_start:
xor rbp,rbp # Zero stack base pointer
xor r9,r9
pop rdi # Pop argc off stack -> rdi for 1st arg to main()
mov rsi,rsp # Argv @top of stack -> rsi for 2nd arg to main()
call main # Call main()... return result ends up in rax
xor r9,r9
mov rdi,rax # Move main()'s return to 1st argument for exit()
mov rax,231 # exit_group() syscall
syscall # Tell kernel to exit program
```
This example is the minimum reproducer I could come up with and has no resemblance to the original code where I noticed the problem save that both have objects with char arrays. Changing the code around can mask or unmask the issue which usually suggests a coding error but that does not appear to be the case here.
My debugger seems to think that the problems are the instructions that Clang is generating to initialize the 'buf' char array.
Here is the code the debugger says that Clang generates for the initialization of `char buf[128]`:
```
0x400171 xorps %xmm0,%xmm0
0x400174 movaps %xmm0,-0x10(%rsp)
0x400179 movaps %xmm0,-0x20(%rsp)
0x40017e movaps %xmm0,-0x30(%rsp)
0x400183 movaps %xmm0,-0x40(%rsp)
0x400188 movaps %xmm0,-0x50(%rsp)
0x40018d movaps %xmm0,-0x60(%rsp)
0x400192 movaps %xmm0,-0x70(%rsp)
0x400197 movaps %xmm0,-0x80(%rsp)
0x40019c lea -0x80(%rsp),%rax
```
The segfault is apparently generated by the first movaps instruction.
Obviously, I expect that the initialization of the array shouldn't segfault.
It doesn't matter if in-class initialization is used as I do here in this example or if initializer-list initialization is used. Both methods suffer from the same problem. It also doesn't matter if the initialization is done with a different construct such as `char buf[128] = {0};` (which fixes a different Clang bug).
I believe this is an alignment issue with the movaps instructions. If I add alignas(32) to the structure or to the char array the problem goes away. I don't know why I'd need to align at 32 bytes. Perplexingly (to me), aligning at 16 bytes does not mask the problem.
The problem also goes away if I just tell Clang not to generate any SSE instructions with `-mno-sse` but I'd rather not lose those optimizations. In this case Clang uses `movq` instructions to initialize the array instead of `movaps`.
The problem also goes away if I forgo initialization of the char array member and do it manually in the constructor but of course that is less efficient.
Thanks for your help! Please let me know if there's any other information I can provide.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJyUWFtv6zYS_jXKy8CGTN8f8pA4PV0Dp9sCp-3DvhxQ0thmQ5FaDuVLf_1iSMqSE7sHGwSyLpxvhnMfSiK1N4jP2fw1m789ydYfrHsutWpK6fRTYavL8zYTyyNCaWsEWTpLBBI2mXjNxCsoohbhdECHoAx5abySXpk9EK-3xV9YegJloHF272RNDNQojRUUF9hoyUtxv5Ot9jTO8rcsf4nXNyza_T5Atfs9kifwB-kTjSLYo0EXmX379hNki7y2R9lQtsiDLK4tvbKGwFtQRnkltfobo2DlQTqQzskLgTQVKJ-JJTNAwg_EzFM2DUrHQKVsCXuJeWcRULmyrVkBJdIYYAuECNYwZNKSd7J8RxcRmegUblSttHRxDcFJ-QO0Rmo2TAVxR7cSsQhqqDY4yCNCgWjAYWOdZ0JpLuBVjQT2GJgiXFA6gqL1oDxUFslkYulBW_sOWr0j-IMiaKTzqmxZpiM6UtbAQdIHeOtgp85YwQX9jdWSt3iksMxA3WqvGo1wXi1Gixl8VaY9A13IY522y7L9_O8_oFCm9UoTaGVYUeFjYf0h2XyyCLZKD8uemGSN4JCCD8HvB2RvKzTWIDVZsGXZOmIvNRBV9_Xrn78Eg9uTga9f3xLHMWyhslEr78aeQO16_A4yobWmQgfWH9B1W7NN54_d9mzaRFwWmXyQkO0AmXjJxIuxPt5EHkOBkyUIbJTo582mCyQXvANlxd-Cbm4Mwrx6T4nAO-tu4zNuhoF3Vmt7Ypa1MqpuayD0jFxaU6nggNk0QY-6jZe2wms4WtN9_bXxqlZ_h3ccsGhkwYGfidXo1wkrRxb2iJlYdxSvykh3gaJV2gfN2TYFfLBWhWEbQF463zaRL7tEtzQYy0tTSVfBBrQqHONlYpUt8pEhX2lVcH6wTRDK2w59HXDCPltHGB3nPmxKfQl8zOh_EHaWYUY7Y0dhD8oMmNXyHQmMhUrtdujQlMgO1zh7VBVCfQneeEKtRyl8aqzL5sLSi3UmNvxM6Ptn9OU4ekn0BTZb8LfPQoyvWo7Xf4WMTdHKUkdVessR7mzVsmib6F99mPW-YQ1Icy-ir76RLfL0Hx_FDMoQt2z5kbHRFBCkJC_L91HjrMfSWwf8wqsyEnwn3B_HNHwoSxjZwYv7HMP1huqRcDG3wjfc_5m-L1_jDRytqiDqvLSGfCwcmXghdpls-Xp9UUA2fYOi3WXTVzgdWHGZWIWl0K3lZcl7eHGE4UemyZZvPU4mltl8k_NP_JTkAYgMA6P560SssvlbohD8P339sDITL5yvrAMYSpiJL5n4AgaxwiomhJQkOhW8XbHiVZn0qZbKJB_8oC2AoEQ49mIcx53HCimDjOsbGR361hnIe2bdXn9kT3pkzrEyHvV3uhgvz2Bs43CnzkOU8V7bQmr4HhJJfJfuO0yW7WwduKLJxMYVDQz_MjGF_6CzEFwXCkkIjWW-bsjnCsLR6tb9y8Y24CoFH_8Y9zfbgHT7Euxul_BH2fSnsJ7tNCHP3zlYP1qCIWp7BEeKGVITAF_c_gjZLPe24SQ1hKQIKUz1T5Cl1Dp8CHCb7ikuG4_HnRFjBQY0FUHbcGvk5PnH-ggSV0Fief6kjl_sEYdScR1I_LztlNHWaHzYCp6Vv5E_oMtzJjZiOvmEzsu_751tm0jEaYy328ubXoTVv6PW8I7OoGbmTNz1tf_gs79zV4VnWXMXpEKTeS2u13TrYMulR1ex0W6bmHa5KHH3ZTgzE9aF5gaTmTOKdWqvTJe9Yxe-BWO9KrEKK7oug7hDDI1n6KdCw9gV_8Bo0BCPYXOQJnTeDBGLrLOtqaCUXMbonWt3a8Jd39-eDqo8QEut1PrSN-2SERgMnbMutJ9BkND4GDtsrguMHDmceDM3jcwvF6jCSICcq7i7ClpQ5j3iDbZLIF2E-tzK3xsfbgeEUMXFkhOlWA4UM76tnFfd8E0vGU8UA0aJC1LwzihS4hT7Irvjah24DHM6-9CD_JafZ3k-WU44lBpiP56f6zrPxKa7Gy6bdTNEv2yUnyd58Pe5o-YaKolgfZdAPCbAuwTThwSr6V2C2WOC1V2C-WOC6i7B4iHBWtwlWD4mWN4lWD0mKEGjhM9rgtX6PHlr6mHzzj4nm0Y6NF5fro4V5ujQnSlH_s7AeBNEvxZHZVvSF24ft4DnBkvfx89n3-S3wfuBDpye4nDUyXQ7-g2Hylp6z6PJDpQZlVoSfQRXBC1hBZLC1AXpDCEOoV26tAmiC0430or8A6gxvHJyq9EfbEVALbfZsHO2_jTFjWHrY49_T-Q7qlDEk2FqhuW1hfcQ2sLQP1JbHng398I5tmjL1zz1VYucu8OYMXmQphvMmDqKlueSWxVDgVrhMY3q7BEGwllBKIApD3f9-p3DgzFsd7AFWVWRTFImVlPuyrqaEte2Lug-vetz4E1R2XMGlyd5-TQ3nw4X2GZiWYUGk2ECN5AepgKKi0caw2_oGo1nZfY6jGjcfWCabMJyTs3S89gfKPqKcS08nTU_Drw34_9VTDbtFv5qyYPnSh7VzIDeXuMJpLmE86Sb0nGdqmqeVwjZgFzJ4iadDPM9I2lLbBy-2sH4y4pPrh2qW2TdElI6t_rvD06t-jgcTPvDI6__Swc76_b2QbQPjF1jXaALTUhlQbHiTazuyqT6lyROhb2fn0NKUQQaiQB3O1UqNP6DkNK8x7p4sa2DA-omExP4TSOrSKOHGofnMA5D98cGigcqyuysq6P029CcpGE68XmqnqfVerqWT_g8WU4m89ViOV0-HZ6XxTTHybyYlZNKLspiOdlJ3E13MynKKU5WT-pZ5GKWT8Uqz2fz6XJclZOJyPNpISeLxXotslmOtVR6rPWxHlu3fwrB97xarNbzJy0L1BSOVYUweIqRyePP_O3JPTPNqGj3lM1yzmfUo3jlNT5_63J-1YZmr8v7PzgZ7GvCrfPEk9nyjm2fWqefD943YZoKM-Fe-UNbjEtbZ-ILy5V-eEDnhjETX-JZZSa-hN3-LwAA__9yEjej">