Fixed, thanks! I did not see this because my memcpy() does not have the nonnull attribute.
Off-topic: the nonnull attribute has this speciality - the compiler assumes that the parameter will never be null and may eliminate branches in the function that check for that. For example:
0void func(char* buf) __nonnull(1)
1{
2    if (buf == nullptr) {
3        // take action
4        return;
5    }
6    buf[0] = 1;
7}
Compiler optimization may reduce this to:
0void func(char* buf) __nonnull(1)
1{
2    buf[0] = 1;
3}
It looks reasonable, given that code like func(nullptr); will not compile. However, if the value of the argument is determined at runtime and may still end up being nullptr, then the compiler has no way to detect this during compilation. So the line buf[0] = 1; may still be executed with buf being nullptr even though the source code checks for that just above, leading to some nice “wtf” moments.
Ubsan alleviates this.