Add memcpy_safe

ISO/IEC 9899:1999 §7.21.1/2 says:
Where an argument declared as size_t n specifies the length of the array
for a function, n can have the value zero on a call to that
function. Unless explicitly stated otherwise in the description of a
particular function in this subclause, pointer arguments on such a call
shall still have valid values, as described in 7.1.4.

In base64_append_width memcpy was called as memcpy(x, NULL, 0).  GCC 4.9
started making use of this and assumes This worked fine under -O0, but
does something strange under -O3.

This patch fixes a bug in base64_append_width(), fixes a possible bug in
journal_file_append_entry_internal(), and makes use of the new function
to simplify the code in other places.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2016-02-01 21:57:41 -05:00
parent 8cd095cc27
commit 75f32f047c
12 changed files with 32 additions and 38 deletions

View File

@ -27,6 +27,7 @@
#include "alloc-util.h"
#include "hexdecoct.h"
#include "macro.h"
#include "util.h"
char octchar(int x) {
return '0' + (x & 7);
@ -574,7 +575,7 @@ static int base64_append_width(char **prefix, int plen,
if (!t)
return -ENOMEM;
memcpy(t + plen, sep, slen);
memcpy_safe(t + plen, sep, slen);
for (line = 0, s = t + plen + slen, avail = len; line < lines; line++) {
int act = MIN(width, avail);

View File

@ -104,6 +104,16 @@ static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_
qsort(base, nmemb, size, compar);
}
/**
* Normal memcpy requires src to be nonnull. We do nothing if n is 0.
*/
static inline void memcpy_safe(void *dst, const void *src, size_t n) {
if (n == 0)
return;
assert(src);
memcpy(dst, src, n);
}
int on_ac_power(void);
#define memzero(x,l) (memset((x), 0, (l)))

View File

@ -1110,8 +1110,8 @@ static int journal_file_append_data(
}
#endif
if (compression == 0 && size > 0)
memcpy(o->data.payload, data, size);
if (compression == 0)
memcpy_safe(o->data.payload, data, size);
r = journal_file_link_data(f, o, p, hash);
if (r < 0)
@ -1373,7 +1373,7 @@ static int journal_file_append_entry_internal(
return r;
o->entry.seqnum = htole64(journal_file_entry_seqnum(f, seqnum));
memcpy(o->entry.items, items, n_items * sizeof(EntryItem));
memcpy_safe(o->entry.items, items, n_items * sizeof(EntryItem));
o->entry.realtime = htole64(ts->realtime);
o->entry.monotonic = htole64(ts->monotonic);
o->entry.xor_hash = htole64(xor_hash);

View File

@ -56,12 +56,7 @@ static int option_append(uint8_t options[], size_t size, size_t *offset,
options[*offset] = code;
options[*offset + 1] = optlen;
if (optlen) {
assert(optval);
memcpy(&options[*offset + 2], optval, optlen);
}
memcpy_safe(&options[*offset + 2], optval, optlen);
*offset += optlen + 2;
break;

View File

@ -73,8 +73,7 @@ int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
if (r < 0)
return r;
if (optval)
memcpy(*buf, optval, optlen);
memcpy_safe(*buf, optval, optlen);
*buf += optlen;
*buflen -= optlen;

View File

@ -112,14 +112,9 @@ static DHCPMessage *create_message(uint8_t *options, uint16_t optlen,
message = malloc0(len);
assert_se(message);
if (options && optlen)
memcpy(&message->options, options, optlen);
if (file && filelen <= 128)
memcpy(&message->file, file, filelen);
if (sname && snamelen <= 64)
memcpy(&message->sname, sname, snamelen);
memcpy_safe(&message->options, options, optlen);
memcpy_safe(&message->file, file, filelen);
memcpy_safe(&message->sname, sname, snamelen);
return message;
}

View File

@ -1133,8 +1133,7 @@ static int add_name_change_match(sd_bus *bus,
item->name_change.old_id.id = old_owner_id;
item->name_change.new_id.id = new_owner_id;
if (name)
memcpy(item->name_change.name, name, l);
memcpy_safe(item->name_change.name, name, l);
/* If the old name is unset or empty, then
* this can match against added names */

View File

@ -2633,8 +2633,7 @@ _public_ int sd_bus_message_append_array(
if (r < 0)
return r;
if (size > 0)
memcpy(p, ptr, size);
memcpy_safe(p, ptr, size);
return 0;
}

View File

@ -352,7 +352,7 @@ static int bus_socket_auth_write(sd_bus *b, const char *t) {
if (!p)
return -ENOMEM;
memcpy(p, b->auth_iovec[0].iov_base, b->auth_iovec[0].iov_len);
memcpy_safe(p, b->auth_iovec[0].iov_base, b->auth_iovec[0].iov_len);
memcpy(p + b->auth_iovec[0].iov_len, t, l);
b->auth_iovec[0].iov_base = p;
@ -789,7 +789,7 @@ int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) {
n = m->n_iovec * sizeof(struct iovec);
iov = alloca(n);
memcpy(iov, m->iovec, n);
memcpy_safe(iov, m->iovec, n);
j = 0;
iovec_advance(iov, &j, *idx);
@ -1000,7 +1000,7 @@ int bus_socket_read_message(sd_bus *bus) {
return -ENOMEM;
}
memcpy(f + bus->n_fds, CMSG_DATA(cmsg), n * sizeof(int));
memcpy_safe(f + bus->n_fds, CMSG_DATA(cmsg), n * sizeof(int));
bus->fds = f;
bus->n_fds += n;
} else

View File

@ -219,9 +219,8 @@ static void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *leng
memcpy((uint8_t*) p, &s, sizeof(AddrInfoSerialization));
memcpy((uint8_t*) p + sizeof(AddrInfoSerialization), ai->ai_addr, ai->ai_addrlen);
if (ai->ai_canonname)
memcpy((char*) p + sizeof(AddrInfoSerialization) + ai->ai_addrlen, ai->ai_canonname, cnl);
memcpy_safe((char*) p + sizeof(AddrInfoSerialization) + ai->ai_addrlen,
ai->ai_canonname, cnl);
*length += l;
return (uint8_t*) p + l;

View File

@ -2580,12 +2580,10 @@ static int inner_child(
/* Automatically search for the init system */
m = 1 + strv_length(arg_parameters);
a = newa(char*, m + 1);
if (strv_isempty(arg_parameters))
a[1] = NULL;
else
memcpy(a + 1, arg_parameters, m * sizeof(char*));
m = strv_length(arg_parameters);
a = newa(char*, m + 2);
memcpy_safe(a + 1, arg_parameters, m * sizeof(char*));
a[1 + m] = NULL;
a[0] = (char*) "/usr/lib/systemd/systemd";
execve(a[0], a, env_use);

View File

@ -433,8 +433,7 @@ int dns_packet_append_raw_string(DnsPacket *p, const void *s, size_t size, size_
((uint8_t*) d)[0] = (uint8_t) size;
if (size > 0)
memcpy(((uint8_t*) d) + 1, s, size);
memcpy_safe(((uint8_t*) d) + 1, s, size);
return 0;
}