<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/72738>72738</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            [clang++] class template with char[] string-initializer miscompilation: segfault or compilation failure
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            clang
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          cjc25
      </td>
    </tr>
</table>

<pre>
    `g++` and `clang++` have different behavior, and I think the standard matches `g++` (but I'm not a language lawyer, and could be wrong). If it is a `clang++` miscompilation, it is the same in 11.0.1-2 and at a recent commit in 18.0 (0723d2496b107840fb812a9ae4420f327bb35ab7). The `g++` version is `(Debian 10.2.1-6) 10.2.1 20210110`. I didn't find an existing open issue for this. Only https://github.com/llvm/llvm-project/issues/66990 looked close.

`clang++` miscompiles: it seems to interpret a string-initializer for a char array member whose size depends on a class template parameter as having the longest size used in any template instantiation, whereas `g++` uses each instantiation's size as I'd expect.

---

The repro is as follows:
```c++
#include <cstdint>
#include <iostream>

template <size_t L> struct V {
 char rest[L] = "at least 18 bytes";
};

int main(int argc, char** argv) {
    V<1 << 20> v1;
    V<18> v2;
    std::cout << sizeof(decltype(v1)) << ", " << v1.rest << std::endl;
    std::cout << sizeof(decltype(v2)) << ", " << v2.rest << std::endl;
    return 0;
}
```

Output:
```
$ g++ -g -fsanitize=undefined,address main.cc
$ ./a.out 
1048576, at least 18 bytes
18, at least 18 bytes
$ clang++ -g -fsanitize=undefined,address main.cc
main.cc:5:20: error: initializer-string for char array is too long, array size is 18 but initializer has size 1048576 (including the null terminating character)
 5 |     char rest[L] = "at least 18 bytes";
      | ^~~~~~~~~~~~~~~~~~~
main.cc:4:28: note: in instantiation of default member initializer 'V<18>::rest' requested here
    4 | template <size_t L> struct V {
      |                            ^
main.cc:10:11: note: in evaluation of exception specification for 'V<18>::V' needed here
   10 | V<18> v2;
      |           ^
1 error generated.
```

If I switch the declaration order of `v1` and `v2` such that the 18-byte instantiation is first (N.B. I left the `std::cout` calls in the same order) I get:
```
$ g++ -g -fsanitize=undefined,address  main.cc
$ ./a.out 
1048576, at least 18 bytes
18, at least 18 bytes
$ clang++ -g -fsanitize=undefined,address main.cc
$ ./a.out 
=================================================================
==12385==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fffb5d51c72 at pc 0x556610e030a1 bp 0x7fffb5d51b70 sp 0x7fffb5d51330
WRITE of size 1048576 at 0x7fffb5d51c72 thread T0
<...snip...>
```

Without sanitizers, the `clang++` compilation segfaults.

---

The assembler shows that `clang++` is `memcpy`'ing 1MiB into the 18 byte array, whereas `g++` is only copying the 18 expected bytes (N.B. these are compiled with `-g` only, no sanitizers).

`clang++` (note the 1MiB immediate stored to edx in both cases before `memcpy`):
```
(gdb) disas _ZN1VILm18EEC2Ev
Dump of assembler code for function _ZN1VILm18EEC2Ev:
   0x0000555555555290 <+0>:     push   %rbp
   0x0000555555555291 <+1>:     mov    %rsp,%rbp
 0x0000555555555294 <+4>:     sub    $0x10,%rsp
   0x0000555555555298 <+8>:     mov    %rdi,-0x8(%rbp)
   0x000055555555529c <+12>:    mov -0x8(%rbp),%rdi
   0x00005555555552a0 <+16>:    lea    0xd60(%rip),%rsi # 0x555555556007
   0x00005555555552a7 <+23>:    mov $0x100000,%edx
   0x00005555555552ac <+28>:    call   0x555555555040 <memcpy@plt>
   0x00005555555552b1 <+33>:    add    $0x10,%rsp
 0x00005555555552b5 <+37>:    pop    %rbp
   0x00005555555552b6 <+38>: ret    
End of assembler dump.
(gdb) disas _ZN1VILm1048576EEC2Ev
Dump of assembler code for function _ZN1VILm1048576EEC2Ev:
   0x00005555555552c0 <+0>:     push   %rbp
 0x00005555555552c1 <+1>:     mov    %rsp,%rbp
   0x00005555555552c4 <+4>: sub    $0x10,%rsp
   0x00005555555552c8 <+8>:     mov %rdi,-0x8(%rbp)
   0x00005555555552cc <+12>:    mov    -0x8(%rbp),%rdi
 0x00005555555552d0 <+16>:    lea    0xd30(%rip),%rsi        # 0x555555556007
   0x00005555555552d7 <+23>:    mov    $0x100000,%edx
 0x00005555555552dc <+28>:    call   0x555555555040 <memcpy@plt>
 0x00005555555552e1 <+33>:    add    $0x10,%rsp
   0x00005555555552e5 <+37>:    pop    %rbp
   0x00005555555552e6 <+38>:    ret    
End of assembler dump.
```

In `g++`, the 18-byte store is inlined into `main`:
```
   0x000055555555519d <+24>:    movabs $0x747361656c207461,%rax
   0x00005555555551a7 <+34>:    movabs $0x6574796220383120,%rdx
   0x00005555555551b1 <+44>:    mov %rax,-0x20(%rbp)
   0x00005555555551b5 <+48>:    mov %rdx,-0x18(%rbp)
   0x00005555555551b9 <+52>:    movw $0x73,-0x10(%rbp)
```

The first two `movabs` and `mov` are 16 bytes of the store, and the `movw $0x0073` is the last 2 bytes.

The 1MiB initialization is a standard memcpy:
```
   0x00005555555551bf <+58>: lea    -0x100020(%rbp),%rax
   0x00005555555551c6 <+65>:    lea 0xe73(%rip),%rcx        # 0x555555556040
   0x00005555555551cd <+72>: mov    $0x100000,%edx
   0x00005555555551d2 <+77>:    mov    %rcx,%rsi
 0x00005555555551d5 <+80>:    mov    %rax,%rdi
   0x00005555555551d8 <+83>:    call   0x555555555040 <memcpy@plt>
``` 

---

I have not looked at `clang++` source to see where the issue is likely to lie.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzUWUtv4zgS_jXMpWCBpJ4-5JBO0kCA2Rmgd9AD7GVAiSWb05KoJSnH6cP-9gUpyW_nhTnsGoFjSeTHen6sEoW1atUh3pL0C0kfbsTg1trcVn9VPL0ptXy5JRldEf7F_2UURCeBZLRqRHdwdy02CFLVNRrsHJS4FhulDeH3YcITuLXqfoBbI1gnOimMhFa4ao0WjvEJL8rBwRPheQuddiDALzWIFUIjnl9wB1rpoZFQIjwb7WVZRvBUg3KgLIgLMrbKVrrtVSOc0p1HGccGoUSLoDpgLKIRW_CwgPCLG6y8RpVuWz-8A1ZEQUqa81jyZJmVjOZFQuuyYFwsBSYJp3XM87KMU1HmQbDf13ii5waNVbrzApCMEl48YKlEB4xGPGKLjPDl9Bs45YwyRklGI3gCqWRHeO6gVl7IDnCrrFPdCnSPHtAOCLU23uY2gt-65gXWzvWWxHeEfyX860q59VBGlW4J_9o0m_nfojf6L6wc4V8DiiX8a5YtlxQarX-ghKrRFiNCHwi9m76vmxn9gt7GFrG14DSozqHpDXq7WmdUt1qoTjklGvUTTZBZQLUWBoQx4gVabEs08LzWFsGqnwgSe-ykBd35kY2wFhy2fSMcQi-MaNGhAWF9QHqLeN82uluhdSPAYFF6L4ruZT9TdT4ondoFxvMaDYrT0BwsWkBRrU8n5HYEFzbErQTc9li5I0MtFovDSx8QBnujQ7RaqHXT6Ofgotmu4181rT_e5bHqqmaQCCS-r6yTqnMkfrz0VGnrDIp2_zh875Qm8b0X-k8Hv5D40ftjqBx8B5JPi42eMGgdSb_8QtIHIPEDEM6FgwaFdcAKKF-cDxNO4lnE_GH_O3yrzkErVEd44X8Ks6q8jT064XeE3_lbGx_v-6UB4DuJ75mXksT3wKmXccN20LsRRXjAjx5YJ70h47tKD26G8MrqmvBCYtW4lx4JLzaM8GVYeRzjFeHh33xnwyJvgR3IjIydbD65Jn9zTf7ONQ26wXRAj4x_HD6HjvhtcP3gzkNsjp4EpmCHxQoWtRU-N38iiR-GTmKtOpSE3wspDVobXBpV1X5yRPhXEQXtwz1GkyLNs0DXZxEzjiheeeghD6jl4zLNF_FdSuI7H0F3gMZoE2hpzzuLkYoC_RyQj98ZtA7sEaQMN0OaKxtEHdwhCqzFxAKT3hDi3afjTETd0DTg0LSqE4Gv_Wqicn5LW05eTYHk9963n8u-MDNAkPTxP2efU8Mk3jCFt0enHY52OSY30DVIrMXQuJmOD5UmPN9l4RikQWKeg8F_D2gdSvBcupcuCdJ9gIV2Gr3yIenjqWrM-5uxE91wI5phpxhuK-zDhe2xUrWqxkc-Es41--7V6hDlqU6MBvmu0tGp-Dtp2RiPsMIOjXAoo1ey96mGJ7DPylXrEE2eUoSZdDESjdeIZHTDDsq0DfcXdghzhAsTWbHwcXPiZ2WhVsazDi9-jb74QqPBepxBMnpEbx6zEk1jvUl35VMQwhPbE6zwb6OZ_32euSQTiR_-7_8OFGE8LtLx5-O3b79989l0N9rin5OlAqtaJ6ofi3LwfcBCb9DUjX4OxdpkOLrN67ouU5myKufeJX0FdJumWcYo0pgKBmV_OKzMKdijO3E8hdIf355-f_RRf0S7wp2u4tYGhYTf5wiM76Mosp3qoyjaV0eXcu4P5dbeqXM4GOsDaUqJk7r3oLcAi6tAmfatElBYi23ZoAG71s92TNJz7LFJaLGt-pfQLeR--2D_UF98Ta2ntA5RPW5U14tY5Yvn5gUq3b_MGxMrpooV5ZgZOxJwa7QeEif1UMKzcmuPuVh5OI_lF-v0kZGWbzQJhBeelcfVgxpti1L5HcE6bVD6dgHl1hNMqd0aKuGL7xJrbfDEFsvrVFOsZOkZSSorLPz5r1_Z96dfWlY8Pt7zx8046mFoex9Ee1dUWo4NVD10VfDn2cx5RQCgW0opTecPX9JQuPEvdNw5AuX3g1175uepKfvrU9k0lR1MbfUGpqm2J_z-COMMIZkQkgMEO5QjQkK3jE4Q9hUxigmkuCyGVITfL-i2ILyYpNnVLxfQqlkpvofzaGcIo2BSXYUSs2lZtodqUEAYK0Mb7SHUAZxVQHgcOGb8ZJTm11fIpxV4fCzsZDz_GYFRbq-jzCrzAwv6DTOM3Y2jSdBnCuWE9s2-l7uAWs7RER_IJqR8xbdnEOkMke8het3D27FZZvPUWSffx_t5YcZjJ4-TSA5tH72RhyNjfzoZj6a_kpHVezPybOKH8_HC4qcZ-dFsrK5l48dTsbqWigBvZuMplnw9F-MruTiXwO9PSXktJfdGvJSVZzB_Q06eYuLHM_JcP_x8TuJZTo4vBd6Zlhe7jO64XpjrnblpCLuzLyJU1_iieKw__IYsVOfHX9mLz6VnSzl7JDlyrCjtaL08yeOMZWlWcZonGZtsKa4SL9vRd3wFMkvzJF9mnNO4iBmf3XOdy9mOdZPkdEcIooT04_Q9-cd29JsU51hywmLvymVWLies9DiXnyfbxRPaBckuOt5Xo2MD6J5HhwazHfSSrd6EK4PAsqlO1PX0Tl8bnN_LT-XxXhZK83gqPcP7WN-D8REgOhVhqmmnNwy71lQcHBuMqfn-OCvr2VKz1SeaWozcceK8N4OsmrMuS4-Zj27Rm_2M9qrtNdpLrktdzdmRz_59m_POUSSfUfIL5OlF21HzZY5jco7Zgl5EENs36zYmd1tY_Fnu3bkZXumonsZzqE67-cDiYjdl9WAq9B2GRRzbpBCY48mJstCoH9i8-AGNwuhG3sZyGS_FDd6ynFKeLzO2vFnfikzKVNI0EbGgCcMYaZHXRV7JhPOMxzfqllMeM8YKGqdxvIx4kucyRVGmss7jQpKEYitUEzXNpo20Wd0EGW5znsfFTSNKbGw4mON80oGT9OHG3IbTmnJYWZLQRlln9whOuSac5h1qnT6cnpaENi68gw_nfpfOY04OzHztMvW1oM1Rv1sL1QwGbwbT3H7-qClo_d8AAAD__6UwwQ0">