Now, 5 months later, I experience a similar problem and looked into it, the actual source code of that part seems to be from 2014.
question A:
"gmtime uses malloc to allocate some ram, but never ever free that memory again"
answer:
in "time_c" of newlib there is one function (except of strftime) calling malloc: tzset_r.c. malloc calls tzset and tzset calls ztset_r. It is about the timezone. At this place the time zone is stored in order to detect a change (the timezone is also read from environment and GMT ist used if none is found). It is unclear for me, why a pointer to allocated memory with that timezone is stored statically and not the timezone string itself is stored statically. Maybe the reason is because that string is of variable length and that was not possible in earlier language versions of "C". It is freed, it the timezone changed but allocated again.
question B: "mktime on the otherhand does not ever invoke malloc (or sbrk) to allocate memory, but calles free() 4 times by passing a nullptr"
answer: strftime and tz_set call both malloc and free. The old pointer is initially set to zero. Before a new timezone is detected and stored in a newly allocated memory, the old is freed without any check. Therefore free without malloc will appear. It is valid to call free(0).
I have just problems with (A) because it calls malloc and I use STM32/FreeRTOS/TouchGFX which seems to have some issues with newlib combined with FreeRTOS and malloc. Therefore I am also looking for a replacement of "localtime" which also makes the alloc.
(B) should not make problems according to actual C++ standards, but I am not sure if this was always true.