On Sat, Aug 3, 2019 at 4:30 PM Sam Varshavchik <mrsam(a)courier-mta.com> wrote:
Tom Hughes writes:
> But I think upstream is giving very bad advice...
>
> That define does not "add extra crashes" in the way that they
> seem to think - well I mean it does literally but those crashes
> are reports of program errors on their part.
>
> Specifically in this case they appear to be accessing a
> std::vector at an index beyond the end, so they are accessing
> memory that may not be allocated at all, and if it is does
> not belong to the vector in question. So the program is quite
> likely to crash there one day anyway, the extra assertion just
> makes sure it always does.
I believe that the following construct trips this assertion:
# std::vector<int> foo;
#
# std::vector<int> bar;
#
# // Populate foo with something.
#
# std::copy(&foo[0], &foo[foo.size()], std::back_insert_iterator{bar});
There's nothing wrong with this. There is no out of bounds access.
You just formed a reference past the end of an array. I doubt that is
valid according to the standard. It certainly fails the smell test.
I *think* the standard defines &foo[foo.size] as being equivalent to
&*(foo.begin() + foo.size()), which certainly appears to be invalid.
On a cursory search of the standard, I couldn't find where it says
what operator* on this type of iterator does at all, let alone whether
it's valid for one-past-the-end iterators, but I'm pretty sure that
your code is, indeed, wrong.
I do not
believe that this is undefined behavior. The defined semantics of
std::vector, and its operator[], are well defined here.
I ran into these new assertions with my own code as well, after updating to
F28 (where they were enabled by default the first time, IIRC, not sure why
this shows up only now, for that package).
I ended up tweaking my code to avoid the assertions, rather than disabling
them. For this particular situation, my original change was to try
std::copy(&foo[0], &foo[0]+foo.size(), std::back_insert_iterator{bar});
What you want is foo.begin() and foo.end() or, if you really want to
play with pointers, foo.data().