csi: avoid using memcmp() to compare timespec structs

This struct may contain padding bytes, whose values are indeterminate
after any store operation[1]. It may also contain unnamed members,
whose values are always indeterminate[2]. Using memcmp() isn't a
reliable way to compare structs where either of these may be present.

[1]: ISO/IEC 9899:1999 §6.2.6.1, paragraph 6
[2]: ISO/IEC 9899:1999 §6.7.8, paragraph 9

See also:

* https://wiki.sei.cmu.edu/confluence/display/c/EXP42-C.+Do+not+compare+padding+data
* https://sourceware.org/git/?p=glibc.git;a=blob;f=time/bits/types/struct_timespec.h;hb=756c306502498f9
This commit is contained in:
Craig Barnes 2020-08-23 03:08:35 +01:00
parent 82e197072b
commit 0e7723e75f

12
csi.c
View file

@ -544,6 +544,12 @@ decrst(struct terminal *term, unsigned param)
decset_decrst(term, param, false);
}
static bool
timespecs_equal(const struct timespec *a, const struct timespec *b)
{
return a->tv_sec == b->tv_sec && a->tv_nsec == b->tv_nsec;
}
static void
xtsave(struct terminal *term, unsigned param)
{
@ -561,10 +567,10 @@ xtsave(struct terminal *term, unsigned param)
if (timerfd_gettime(term->cursor_blink.fd, &current_value) < 0)
LOG_WARN("xtsave: failed to read cursor blink timer: %s", strerror(errno));
else {
const struct timespec zero = {};
const struct timespec zero = {.tv_sec = 0, .tv_nsec = 0};
term->xtsave.cursor_blink =
!(memcmp(&current_value.it_interval, &zero, sizeof(zero)) == 0 &&
memcmp(&current_value.it_value, &zero, sizeof(zero)) == 0);
!(timespecs_equal(&current_value.it_interval, &zero) &&
timespecs_equal(&current_value.it_value, &zero));
}
break;
}