The following code should work:
array a = constant(1.0f, 3, 5, f32);
array cond = constant(1, 5, b8);
auto X = a(span, cond);
array Y = X;
but it produces the error below:
terminate called after throwing an instance of 'af::exception'
what(): ArrayFire Exception (Unknown error:208):
In function const ArrayInfo& getInfo(af_array, bool, bool)
In file src/api/c/array.cpp:30
Input Array not created on current device
In function af::array::array_proxy::operator af::array() const
In file src/api/cpp/array.cpp:686
I think this is a bug in the way memory is managed for the af_index_t structure within the array_proxy.
Below is what I think happens:
- the
array::operator() is called to create the X proxy
- the
cond array is first converted to a temporary index object (since operator() can only take index)
- the
index constructor calls where which creates a new array that holds the indices (index.cpp:69)
- then the array created by
where is copied over into a new array (index.cpp:71), that's used as the arr member of the index (index.cpp:72)
- the
array::operator() calls gen_indexing array.cpp:350, which then just copies the indices into a local container array.cpp:312-316.
So at this point the pointer to the array allocated in step 4 within a temporary index is copied over into the index of the array_proxy. Then, once we exit the array::operator(), the temporary index is deleted, together with its arr: index.cpp:84. And we end-up with an array_proxy that's holding a dangling pointer in one if its indices. Because the ArrayInfo memory is now freed, it points to bad memory and we get the error above.
This analysis is confirmed by just making the automatic temporary index explicit, i.e. the following code works fine:
array a = constant(1.0f, 3, 5, f32);
array cond = constant(1, 5, b8);
index condIdx = cond; // explicitly create the index to keep it in scope
auto X = a(span, condIdx);
array Y = X;
Another way to confirm the problem is to run the first version under valgrind, where I get
==16825== Invalid read of size 1
==16825== at 0x79DB35F4: ArrayInfo::isSparse() const (ArrayInfo.cpp:172)
==16825== by 0x79DCAD81: getInfo(void*, bool, bool) (array.cpp:26)
==16825== by 0x7A00445C: af_index_gen (index.cpp:203)
==16825== by 0x4ED6E21: af_err unified::AFSymbolManager::call<void**, void*, long long, af_index_t const*>(char const*, void**, void*, long long, af_index_t const*) (symbol_manager.hpp:71)
==16825== by 0x4ED4782: af_index_gen (index.cpp:44)
==16825== by 0x4F23879: af::array::array_proxy::operator af::array() const (array.cpp:686)
==16825== by 0x400ED8: main (ArrayFireTest.cpp:111)
==16825== Address 0xb5b2fc70 is 80 bytes inside a block of size 160 free'd
==16825== at 0x4C2F24B: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==16825== by 0x79CDF4C2: void cuda::destroyArray<unsigned int>(cuda::Array<unsigned int>*) (Array.cpp:327)
==16825== by 0x79DD16D1: void releaseHandle<unsigned int>(void*) (handle.hpp:115)
==16825== by 0x79DCCCEA: af_release_array (array.cpp:216)
==16825== by 0x4E96E02: af_err unified::AFSymbolManager::call<void*>(char const*, void*) (symbol_manager.hpp:71)
==16825== by 0x4E8FB66: af_release_array (array.cpp:51)
==16825== by 0x4FD8839: af::index::~index() (index.cpp:84)
==16825== by 0x400EA7: main (ArrayFireTest.cpp:110)
==16825== Block was alloc'd at
==16825== at 0x4C2E0EF: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==16825== by 0x79CDF15F: cuda::Array<unsigned int>* cuda::initArray<unsigned int>() (Array.cpp:281)
==16825== by 0x79DD1816: void* retainHandle<unsigned int>(void*) (array.cpp:238)
==16825== by 0x79DCD22C: retain(void*) (array.cpp:261)
==16825== by 0x79DCD512: af_retain_array (array.cpp:278)
==16825== by 0x4E79E0F: af_err unified::AFSymbolManager::call<void**, void*>(char const*, void**, void*) (symbol_manager.hpp:71)
==16825== by 0x4E8FE7C: af_retain_array (array.cpp:59)
==16825== by 0x4FD8570: af::index::index(af::array const&) (index.cpp:71)
==16825== by 0x400E49: main (ArrayFireTest.cpp:110)
The following code should work:
but it produces the error below:
I think this is a bug in the way memory is managed for the
af_index_tstructure within thearray_proxy.Below is what I think happens:
array::operator()is called to create theXproxycondarray is first converted to a temporaryindexobject (sinceoperator()can only takeindex)indexconstructor callswherewhich creates a new array that holds the indices (index.cpp:69)whereis copied over into a new array (index.cpp:71), that's used as thearrmember of the index (index.cpp:72)array::operator()callsgen_indexingarray.cpp:350, which then just copies the indices into a local container array.cpp:312-316.So at this point the pointer to the array allocated in step 4 within a temporary
indexis copied over into the index of thearray_proxy. Then, once we exit thearray::operator(), the temporary index is deleted, together with itsarr: index.cpp:84. And we end-up with anarray_proxythat's holding a dangling pointer in one if its indices. Because theArrayInfomemory is now freed, it points to bad memory and we get the error above.This analysis is confirmed by just making the automatic temporary index explicit, i.e. the following code works fine:
Another way to confirm the problem is to run the first version under valgrind, where I get