alpaka: alpaka buffers do not respect `const` correctness ?
As we try to use alpaka Buffer objects in the CMS software, we are facing a problem with const
correctness due to the way the buffers are implemented.
Here is a sample program, compiled with g++ -std=c++17 -O3 -Wall -I/home/fwyzard/src/alpaka-group/alpaka/include -DALPAKA_ACC_CPU_B_SEQ_T_SEQ_ENABLED test.cc -o test
:
#include <alpaka/alpaka.hpp>
template <typename TBuf>
void modify_const_buffer(TBuf buffer) {
// buffer is not const, and can be used to modify the contents of the originally const buffer:
buffer[42] = 0;
}
int main(void) {
using Dim = alpaka::DimInt<1u>;
using Idx = std::size_t;
using Host = alpaka::AccCpuSerial<Dim, Idx>;
const auto host = alpaka::getDevByIdx<Host>(0u);
const auto buffer = alpaka::allocBuf<int, Idx>(host, alpaka::Vec<Dim, Idx>(64u));
// buffer is const, so it's not possible to write into it:
/*
test.cc: In function ‘int main()’:
test.cc:22:14: error: assignment of read-only location ‘((const alpaka::internal::ViewAccessOps<alpaka::BufCpu<int, std::integral_constant<long unsigned int, 1>, long unsigned int> >*)(& buffer))->alpaka::internal::ViewAccessOps<alpaka::BufCpu<int, std::integral_constant<long unsigned int, 1>, long unsigned int> >::operator[](42)’
22 | buffer[42] = 0;
*/
//buffer[42] = 0;
modify_const_buffer(buffer);
return 0;
}
The issue is that the original buffer
is const
, but any non-const
copy of buffer
can be used to modify the same data.
Is this the expected behaviour ?
About this issue
- Original URL
- State: open
- Created 2 years ago
- Comments: 24 (24 by maintainers)
Just thinking aloud: if we have a
std::shared_ptr<T>
, we can automatically convert it to astd::shared_ptr<const T>
:With this code we can be reasonably sure that
dump_buffer(...)
will not modify the content ofbuffer
(i.e., not without using astatic_cast
).Unfortunately, an alpaka buffer
TBuf<T, TDim, TIdx>
cannot be converted to aTBuf<const T, TDim, TIdx>
, so we cannot use the same approach.(please note, I’m not saying that having an automatic conversion from
TBuf<T>
toTBuf<const T>
would solve all theconst
-ness problems, but it could help address some of them; we can try to come up with a more concrete case by next week)No, the problem is that also a function declared like
can modify the contents of the buffer:
So, the summary is that alpaka buffers can never give any
const
guarantee.I quickly prototyped a
ViewConst
here: https://github.com/alpaka-group/alpaka/pull/1746.This could work, together with a change to the
Buffer
copy constructor: a non-const
Buffer can be used to construct aBuffer
, while aconst
Buffer can only be used to construct aConstBuffer
.I’m actually considering the other approach we discussed this morning: to make the interface of the object that holds the buffer expose only
const
access to the data contained in the buffer, rather than to the buffer itself.Okay, maybe now i realized what was missing in all my posts in this issue. What i express is of course how alpaka works as of now, and so how a user code should be written for as-is alpaka. Basically, with understanding that
auto copy = buffer;
is unsafe and generally should be avoided forconst Buf
, withconst auto copy = buffer;
as a safe version. I am not saying alpaka should be working like this, as it’s extremely confusing indeed, and I thought i expressed it in most my messages but then probably did it poorlyI even agree with your last point. E.g. especially with writing templated code, or being far away from alpaka. So i’m now just puzzled what we are arguing about at all
So yes, i very much agree alapka should not allow this code to work, as it’s very easy to write and make a mistake without realizing it. And it can probably be solved simply by having a function with explicit name instead of
operator =
, one for a “safe copy” const to const, and another one for unsafe const to non-constYes, I understand this.
What you are saying is that a
Buf
containing anint
should be considered like anint*
or ashared_ptr<int>
:const Buf
is just like aint * const
: the pointer itself cannot be modified, but it can be copied to aint *
, and the pointed-to data can always be modifiedconst Buf
is not like aconst int*
, that is, aconst
buffer is not like a pointer toconst
objectThis is not a cast, it’s a copy:
copy
andbuffer
are two different objects, that point to the same data.