Many pieces of code have these sorts of "bugs", but in practice no one cares, because the input required, while theoretically possible, physically is not.
It does something unexpected if size is SIZE_T_MAX-1, too. And it's also undefined if input is null and size is zero, which seems more likely to surprise that function's author. This is because memcpy requires valid pointer arguments even if the size is zero.
In particular, this usage invokes UB:
const char *input = "";
size_t len = strlen(input);
char *buf = malloc(len); // may return null if len is zero
if (len) memcpy(buf, input, len);
char \*buf2 = strappend(buf, len);
Many pieces of code have these sorts of "bugs", but in practice no one cares, because the input required, while theoretically possible, physically is not.