1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-11-07 03:12:36 +01:00

Fix misaligned memory(UB)

X86 is able to deal with
misaligned memory, but it can hurt perf.
Other arch like for example mips
is not able to digest it.

So in order of portability we should get
rid of this UB.
This commit is contained in:
Filip Gawin 2017-12-21 21:37:58 +01:00 committed by Daniel Evans
parent 09b7ead012
commit a60bc20585
5 changed files with 60 additions and 31 deletions

View File

@ -6,6 +6,7 @@
#include <vector>
#include "script/ScriptTypes.hpp"
#include "rw/bit_cast.cpp"
/**
* @brief Handles in-memory SCM file data including section offsets.
@ -33,7 +34,7 @@ public:
template <class T>
T read(unsigned int offset) const {
return *(T*)(_data + offset);
return bit_cast<T>(*(_data + offset));
}
uint32_t getMainSize() const {

View File

@ -16,6 +16,7 @@ SET(RWLIB_SOURCES
source/gl/TextureData.cpp
source/rw/abort.cpp
source/rw/bit_cast.cpp
source/rw/filesystem.hpp
source/rw/forward.hpp
source/rw/types.hpp

View File

@ -124,7 +124,7 @@ LoaderDFF::GeometryList LoaderDFF::readGeometryList(const RWBStream &stream) {
char *headerPtr = listStream.getCursor();
unsigned int numGeometries = *(std::uint32_t *)headerPtr;
unsigned int numGeometries = bit_cast<std::uint32_t>(*headerPtr);
headerPtr += sizeof(std::uint32_t);
std::vector<GeometryPtr> geometrylist;
@ -156,19 +156,20 @@ GeometryPtr LoaderDFF::readGeometry(const RWBStream &stream) {
char *headerPtr = geomStream.getCursor();
geom->flags = *(std::uint16_t *)headerPtr;
geom->flags = bit_cast<std::uint16_t>(*headerPtr);
headerPtr += sizeof(std::uint16_t);
/*unsigned short numUVs = *(std::uint8_t*)headerPtr;*/
/*unsigned short numUVs = bit_cast<std::uint8_t>(*headerPtr);*/
headerPtr += sizeof(std::uint8_t);
/*unsigned short moreFlags = *(std::uint8_t*)headerPtr;*/
/*unsigned short moreFlags = bit_cast<std::uint8_t>(*headerPtr);*/
headerPtr += sizeof(std::uint8_t);
unsigned int numTris = *(std::uint32_t *)headerPtr;
unsigned int numTris = bit_cast<std::uint32_t>(*headerPtr);
headerPtr += sizeof(std::uint32_t);
unsigned int numVerts = *(std::uint32_t *)headerPtr;
unsigned int numVerts = bit_cast<std::uint32_t>(*headerPtr);
headerPtr += sizeof(std::uint32_t);
/*unsigned int numFrames = *(std::uint32_t*)headerPtr;*/
/*unsigned int numFrames = bit_cast<std::uint32_t>(*headerPtr);*/
headerPtr += sizeof(std::uint32_t);
std::vector<GeometryVertex> verts;
@ -182,7 +183,7 @@ GeometryPtr LoaderDFF::readGeometry(const RWBStream &stream) {
if ((geom->flags & 8) == 8) {
for (size_t v = 0; v < numVerts; ++v) {
verts[v].colour = *(glm::u8vec4 *)headerPtr;
verts[v].colour = bit_cast<glm::u8vec4>(*headerPtr);
headerPtr += sizeof(glm::u8vec4);
}
} else {
@ -193,27 +194,28 @@ GeometryPtr LoaderDFF::readGeometry(const RWBStream &stream) {
if ((geom->flags & 4) == 4 || (geom->flags & 128) == 128) {
for (size_t v = 0; v < numVerts; ++v) {
verts[v].texcoord = *(glm::vec2 *)headerPtr;
verts[v].texcoord = bit_cast<glm::vec2>(*headerPtr);
headerPtr += sizeof(glm::vec2);
}
}
// Grab indicies data to generate normals (if applicable).
RW::BSGeometryTriangle *triangles = (RW::BSGeometryTriangle *)headerPtr;
auto triangles = std::make_unique<RW::BSGeometryTriangle[]>(numTris);
memcpy(triangles.get(), headerPtr, sizeof(RW::BSGeometryTriangle) * numTris);
headerPtr += sizeof(RW::BSGeometryTriangle) * numTris;
geom->geometryBounds = *(RW::BSGeometryBounds *)headerPtr;
geom->geometryBounds = bit_cast<RW::BSGeometryBounds>(*headerPtr);
geom->geometryBounds.radius = std::abs(geom->geometryBounds.radius);
headerPtr += sizeof(RW::BSGeometryBounds);
for (size_t v = 0; v < numVerts; ++v) {
verts[v].position = *(glm::vec3 *)headerPtr;
verts[v].position = bit_cast<glm::vec3>(*headerPtr);
headerPtr += sizeof(glm::vec3);
}
if ((geom->flags & 16) == 16) {
for (size_t v = 0; v < numVerts; ++v) {
verts[v].normal = *(glm::vec3 *)headerPtr;
verts[v].normal = bit_cast<glm::vec3>(*headerPtr);
headerPtr += sizeof(glm::vec3);
}
} else {
@ -276,7 +278,7 @@ void LoaderDFF::readMaterialList(GeometryPtr &geom, const RWBStream &stream) {
throw DFFLoaderException("MaterialList missing struct chunk");
}
unsigned int numMaterials = *(std::uint32_t *)listStream.getCursor();
unsigned int numMaterials = bit_cast<std::uint32_t>(*listStream.getCursor());
geom->materials.reserve(numMaterials);
@ -306,18 +308,21 @@ void LoaderDFF::readMaterial(GeometryPtr &geom, const RWBStream &stream) {
// Unkown
matData += sizeof(std::uint32_t);
material.colour = *(glm::u8vec4 *)matData;
material.colour = bit_cast<glm::u8vec4>(*matData);
matData += sizeof(std::uint32_t);
// Unkown
matData += sizeof(std::uint32_t);
/*bool usesTexture = *(std::uint32_t*)matData;*/
/*bool usesTexture = bit_cast<std::uint32_t>(*matData);*/
matData += sizeof(std::uint32_t);
material.ambientIntensity = *(float *)matData;
material.ambientIntensity = bit_cast<float>(*matData);
matData += sizeof(float);
/*float specular = *(float*)matData;*/
/*float specular = bit_cast<float>(*matData);*/
matData += sizeof(float);
material.diffuseIntensity = *(float *)matData;
material.diffuseIntensity = bit_cast<float>(*matData);
matData += sizeof(float);
material.flags = 0;
@ -381,10 +386,10 @@ void LoaderDFF::readGeometryExtension(GeometryPtr &geom,
void LoaderDFF::readBinMeshPLG(GeometryPtr &geom, const RWBStream &stream) {
auto data = stream.getCursor();
geom->facetype = static_cast<Geometry::FaceType>(*(std::uint32_t *)data);
geom->facetype = static_cast<Geometry::FaceType>(bit_cast<std::uint32_t>(*data));
data += sizeof(std::uint32_t);
unsigned int numSplits = *(std::uint32_t *)data;
unsigned int numSplits = bit_cast<std::uint32_t>(*data);
data += sizeof(std::uint32_t);
// Number of triangles.
@ -396,9 +401,9 @@ void LoaderDFF::readBinMeshPLG(GeometryPtr &geom, const RWBStream &stream) {
for (size_t s = 0; s < numSplits; ++s) {
SubGeometry sg;
sg.numIndices = *(std::uint32_t *)data;
sg.numIndices = bit_cast<std::uint32_t>(*data);
data += sizeof(std::uint32_t);
sg.material = *(std::uint32_t *)data;
sg.material = bit_cast<std::uint32_t>(*data);
data += sizeof(std::uint32_t);
sg.start = start;
start += sg.numIndices;
@ -423,11 +428,13 @@ AtomicPtr LoaderDFF::readAtomic(FrameList &framelist,
}
auto data = atomicStream.getCursor();
auto frame = *(std::uint32_t *)data;
std::uint32_t frame = bit_cast<std::uint32_t>(*data);
data += sizeof(std::uint32_t);
auto geometry = *(std::uint32_t *)data;
std::uint32_t geometry = bit_cast<std::uint32_t>(*data);
data += sizeof(std::uint32_t);
auto flags = *(std::uint32_t *) data;
std::uint32_t flags = bit_cast<std::uint32_t>(*data);
// Verify the atomic's particulars
RW_CHECK(frame < framelist.size(), "atomic frame " << frame
@ -465,7 +472,7 @@ ClumpPtr LoaderDFF::loadFromMemory(FileHandle file) {
}
// There is only one value in the struct section.
auto numAtomics = *(std::uint32_t *)rootStream.getCursor();
std::uint32_t numAtomics = bit_cast<std::uint32_t>(*rootStream.getCursor());
RW_UNUSED(numAtomics);
GeometryList geometrylist;

View File

@ -2,10 +2,12 @@
#define _LIBRW_RWBINARYSTREAM_HPP_
#include <cstdint>
#include <glm/glm.hpp>
#include <cstring>
#include <cstddef>
#include "rw/defines.hpp"
#include "rw/bit_cast.cpp"
/**
* @brief Class for working with RenderWare binary streams.
@ -39,11 +41,13 @@ public:
// _nextChunk is initally = to _data, making this a non-op
_dataCur = _nextChunk;
ChunkID id = *(ChunkID*)(_dataCur);
ChunkID id = bit_cast<std::uint32_t>(*_dataCur);
_dataCur += sizeof(ChunkID);
_currChunkSz = *(std::uint32_t*)(_dataCur);
_currChunkSz = bit_cast<std::uint32_t>(*_dataCur);
_dataCur += sizeof(std::uint32_t);
_chunkVersion = *(std::uint32_t*)(_dataCur);
_chunkVersion = bit_cast<std::uint32_t>(*_dataCur);
_dataCur += sizeof(std::uint32_t);
_nextChunk = _dataCur + _currChunkSz;

View File

@ -0,0 +1,16 @@
#ifndef _LIBRW_BIT_CAST_CPP_
#define _LIBRW_BIT_CAST_CPP_
//Based on https://gist.github.com/socantre/3472964
#include <cstring> // memcpy
#include <type_traits> // is_trivially_copyable
#include "rw/defines.hpp" // RW_ASSERT
template <class Dest, class Source>
inline Dest bit_cast(Source const &source) {
Dest dest = Dest{};
std::memcpy(&dest, &source, sizeof(Dest));
return dest;
}
#endif