Avoiding temporary fails with xt::concatenate
When using -DXTENSOR_FORCE_TEMPORARY_MEMORY_IN_ASSIGNMENTS=Off, the following simple test fails:
TEST(xbuilder, concatenate_assign_to_argument)
{
xt::xarray<int> a = xt::ones<int>({ 4 });
xt::xarray<int> b = xt::ones<int>({ 3 });
a = xt::concatenate(xt::xtuple(a, b));
ASSERT_EQ(a, xt::ones<int>({7}));
}
Instead of containing 7 ones, a will contain garbage.
I have searched for the root cause of the issue, and found the following:
-
Changing
overlapping_memory_checker_traitsforxgenerator, socheck_overlapreturnstrueinstead offalse, solves the issue. The change is in line 90 of xgenerator.hpp. -
The problem occurs because of an assumption that an xgenerator always generates fresh values using some generator function. In this case, memory overlap indeed never occurs.
-
xt::concatenatecreates an xgenerator that reads values from the arrays in its input tuple, which may overlap with the output array.
The following happens in the test:
xgenerator::assign_toresizesa, so it can hold seven elements. It re-allocates memory for a, without initializing the elements.- The function in the xgenerator, which has type
concatenate_access, still wants to concatenateaandb. It uses the new value fora. - Since
anow has length 7,concatenate_access::accessonly uses values froma. It thus copies the uninitialized values fromatoa.
Although patching xgenerator works around the issue, a proper fix would be calling check_overlap on the functor inside the xgenerator, and then calling check_overlap on the tuples inside the functor, in case the functor holds a tuple.
@vakokako Since you created the optimization of avoiding temporaries, you're probably interested in this issue.
I just got bitten by the same behavior when migrating from xtensor-0.24.0 to xtensor-0.26.0, where it seems the define XTENSOR_FORCE_TEMPORARY_MEMORY_IN_ASSIGNMENTS is by default undefined.
Falling back to xtensor-0.25.0 seems to work fine.
I wonder if it would not be safer to have this defined (or use an inverse logic) instead of forcing this on users and breaking existing code silently.
Been debugging the exact same issue now for a couple of hours, after I was forced to migrate by clang incompatibility.