c++11 - mmap and C++ strict aliasing rules -
consider posix.1-2008 compliant operating system, , let fd valid file descriptor (to open file, read mode, enough data...). following code adheres c++11 standard* (ignore error checking):
void* map = mmap(null, sizeof(int)*10, prot_read, map_private, fd, 0); int* foo = static_cast<int*>(map);
now, following instruction break strict aliasing rules?
int bar = *foo;
according standard:
if program attempts access stored value of object through glvalue of other 1 of following types behavior undefined:
- the dynamic type of object,
- a cv-qualified version of dynamic type of object,
- a type similar (as defined in 4.4) dynamic type of object,
- a type signed or unsigned type corresponding dynamic type of object,
- a type signed or unsigned type corresponding cv-qualified version of dynamic type of object,
- an aggregate or union type includes 1 of aforementioned types among elements or non-static data members (including, recursively, element or non-static data member of subaggregate or contained union),
- a type (possibly cv-qualified) base class type of dynamic type of object,
- a char or unsigned char type.
what's dynamic type of object pointed map / foo ? object? standard says:
the lifetime of object of type t begins when: storage proper alignment , size type t obtained, , if object has non-trivial initialization, initialization complete.
does mean mapped memory contains 10 int objects (suppose initial address aligned)? if true, wouldn't apply code (which breaks strict aliasing)?
char baz[sizeof(int)]; int* p=reinterpret_cast<int*>(&baz); *p=5;
even oddly, mean declaring baz starts lifetime of (properly aligned) object of size 4?
some context: mmap-ing file contains chunk of data wish directly access. since chunk large i'd avoid memcpy-ing temporary object.
*can nullptr instead of null here, implicitly casted null? reference standard?
i believe casting violate strict aliasing. arguing convincingly above paygrade, here attempt @ workaround:
template<class t> t* launder_raw_pod_at( void* ptr ) { static_assert( std::is_pod<t>::value, "this works plain old data" ); char buff[sizeof(t)]; std::memcpy( buff, ptr, sizeof(t) ); t* r = ::new(ptr) t; std::memcpy( ptr, buff, sizeof(t) ); return r; }
i believe above code has 0 observable side effects on memory , returns pointer legal t*
@ location ptr
.
check if compiler optimizes above code noop. so, has understand memcpy
@ fundamental level, , constructing t
has nothing memory there.
at least clang 4.0.0 can optimize operation away.
what we first copy bytes away. use placement new create t
there. finally, copy bytes back.
we have legally created t
bytes want in it.
but copy away , local buffer, has no observable effect.
the construction of object, if pod, doesn't have touch bytes either; technically bytes undefined. compilers smart "do nothing".
so compiler can work out manipulation can skipped at runtime. @ same time, have in abstract machine created object proper bytes @ location. (assuming has valid alignment! isn't code's problem.)
Comments
Post a Comment