#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define BUFFER_SIZE 40

int main(void) {
time_t t;
char array_buffer[BUFFER_SIZE];
char *ctime_buffer;

time(&t);
ctime_buffer = ctime(&t);

snprintf(array_buffer, BUFFER_SIZE, ctime_buffer);
printf("Current time in array_buffer: %s", array_buffer);

sprintf(array_buffer, "%s", ctime_buffer); // segfault
printf("Current time in array_buffer: %s", array_buffer);
return EXIT_SUCCESS;
}


The above is a redux of the rcunit crash. For some reason, the output of ctime() causes the crash if the bounds aren't checked. It does not matter how large the buffer is.

If the "%s" in the faulting statement is changed to "%.26s" (or if "%s" is simply omitted), then the crash no longer occurs. The implication is that ctime() does not return a 0 terminated string, but it does. I had a check loop in between the two sections, and the 0 is exactly where it needs to be, at byte 26.

The catch is that the crashing statement results in

sprintf(array_buffer, "%s", ctime(&t));
<main+30>: lea -0x10(%rbp),%rdi
<main+34>: callq 0x400478 <ctime@plt>
<main+39>: mov %rax,%rsi
<main+42>: lea -0x40(%rbp),%rdi
<main+46>: callq 0x600a00 <strcpy@@GLIBC_2.2.5>


while the other forms result in

sprintf(array_buffer, "%.26s", ctime(&t));
<main+30>: lea -0x10(%rbp),%rdi
<main+34>: callq 0x400468 <ctime@plt>
<main+39>: lea -0x40(%rbp),%rdi
<main+43>: mov %rax,%rdx
<main+46>: mov $0x400700,%esi
<main+51>: mov $0x0,%eax
<main+56>: callq 0x400498 <sprintf@plt>


So even with -O0, the first case degenerates to a strcpy() call. Which means all the crashes are caused by strcpy() (already knew that was the case with check.) At least it looks like there is a way around it, but this is just plain weird...