On Sat, Mar 04, 2017 at 09:08:40PM +0100, Vegard Nossum wrote: > > At a glance, looks like range_set_copy() is using > > sizeof(struct range_set) == 12, but > > range_set_init/range_set_grow/ALLOC_GROW/REALLOC_ARRAY is using > > sizeof(rs->range) == 8. > > Attached patch seems to fix it -- basically, range_set_copy() is trying > to copy more than it should. It was uncovered with the test case from > Allan's commit because it's creating enough ranges to overflow the > initial allocation on 32-bit. Ugh, yeah, that is definitely a bug. > diff --git a/line-log.c b/line-log.c > index 951029665..cb0dc1110 100644 > --- a/line-log.c > +++ b/line-log.c > @@ -43,7 +43,7 @@ void range_set_release(struct range_set *rs) > static void range_set_copy(struct range_set *dst, struct range_set *src) > { > range_set_init(dst, src->nr); > - memcpy(dst->ranges, src->ranges, src->nr*sizeof(struct range_set)); > + memcpy(dst->ranges, src->ranges, src->nr*sizeof(struct range)); I think "sizeof(*dst->ranges)" is probably an even better fix, as it infers the type of "dst". But these days we have COPY_ARRAY() to make it even harder to get this kind of thing wrong. I grepped for 'memcpy.*sizeof' and found one other case that's not a bug, but is questionable. Of the "good" cases, I think most of them could be converted into something more obviously-correct, which would make auditing easier. The three main cases I saw were: 1. Ones which can probably be converted to COPY_ARRAY(). 2. Ones which just copy a single object, like: memcpy(&dst, &src, sizeof(dst)); Perhaps we should be using struct assignment like: dst = src; here. It's safer and it should give the compiler more room to optimize. The only downside is that if you have pointers, it is easy to write "dst = src" when you meant "*dst = *src". 3. There were a number of alloc-and-copy instances. The copy part is the same as (2) above, but you have to repeat the size, which is potentially error-prone. I wonder if we would want something like: #define ALLOC_COPY(dst, src) do { \ (dst) = xmalloc(sizeof(*(dst))); \ COPY_ARRAY(dst, src, 1); \ while(0) That avoids having to specify the size at all, and triggers a compile-time error if "src" and "dst" point to objects of different sizes. I suspect our friendly neighborhood coccinelle wizards could cook up a conversion. -Peff