More GLTF loading hardening (#5415)
Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>pull/5431/head^2
parent
b7b6601a75
commit
f59a5fab1a
|
@ -547,7 +547,7 @@ struct BufferView : public Object {
|
||||||
BufferViewTarget target; //! The target that the WebGL buffer should be bound to.
|
BufferViewTarget target; //! The target that the WebGL buffer should be bound to.
|
||||||
|
|
||||||
void Read(Value &obj, Asset &r);
|
void Read(Value &obj, Asset &r);
|
||||||
uint8_t *GetPointer(size_t accOffset);
|
uint8_t *GetPointerAndTailSize(size_t accOffset, size_t& outTailSize);
|
||||||
};
|
};
|
||||||
|
|
||||||
//! A typed view into a BufferView. A BufferView contains raw binary data.
|
//! A typed view into a BufferView. A BufferView contains raw binary data.
|
||||||
|
@ -629,7 +629,7 @@ struct Accessor : public Object {
|
||||||
|
|
||||||
std::vector<uint8_t> data; //!< Actual data, which may be defaulted to an array of zeros or the original data, with the sparse buffer view applied on top of it.
|
std::vector<uint8_t> data; //!< Actual data, which may be defaulted to an array of zeros or the original data, with the sparse buffer view applied on top of it.
|
||||||
|
|
||||||
void PopulateData(size_t numBytes, uint8_t *bytes);
|
void PopulateData(size_t numBytes, const uint8_t *bytes);
|
||||||
void PatchData(unsigned int elementSize);
|
void PatchData(unsigned int elementSize);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -785,12 +785,14 @@ inline void BufferView::Read(Value &obj, Asset &r) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint8_t *BufferView::GetPointer(size_t accOffset) {
|
inline uint8_t *BufferView::GetPointerAndTailSize(size_t accOffset, size_t& outTailSize) {
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
|
outTailSize = 0;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
uint8_t *basePtr = buffer->GetPointer();
|
uint8_t * const basePtr = buffer->GetPointer();
|
||||||
if (!basePtr) {
|
if (!basePtr) {
|
||||||
|
outTailSize = 0;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -799,17 +801,25 @@ inline uint8_t *BufferView::GetPointer(size_t accOffset) {
|
||||||
const size_t begin = buffer->EncodedRegion_Current->Offset;
|
const size_t begin = buffer->EncodedRegion_Current->Offset;
|
||||||
const size_t end = begin + buffer->EncodedRegion_Current->DecodedData_Length;
|
const size_t end = begin + buffer->EncodedRegion_Current->DecodedData_Length;
|
||||||
if ((offset >= begin) && (offset < end)) {
|
if ((offset >= begin) && (offset < end)) {
|
||||||
|
outTailSize = end - offset;
|
||||||
return &buffer->EncodedRegion_Current->DecodedData[offset - begin];
|
return &buffer->EncodedRegion_Current->DecodedData[offset - begin];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (offset >= buffer->byteLength)
|
||||||
|
{
|
||||||
|
outTailSize = 0;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
outTailSize = buffer->byteLength - offset;
|
||||||
return basePtr + offset;
|
return basePtr + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// struct Accessor
|
// struct Accessor
|
||||||
//
|
//
|
||||||
inline void Accessor::Sparse::PopulateData(size_t numBytes, uint8_t *bytes) {
|
inline void Accessor::Sparse::PopulateData(size_t numBytes, const uint8_t *bytes) {
|
||||||
if (bytes) {
|
if (bytes) {
|
||||||
data.assign(bytes, bytes + numBytes);
|
data.assign(bytes, bytes + numBytes);
|
||||||
} else {
|
} else {
|
||||||
|
@ -818,11 +828,21 @@ inline void Accessor::Sparse::PopulateData(size_t numBytes, uint8_t *bytes) {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Accessor::Sparse::PatchData(unsigned int elementSize) {
|
inline void Accessor::Sparse::PatchData(unsigned int elementSize) {
|
||||||
uint8_t *pIndices = indices->GetPointer(indicesByteOffset);
|
size_t indicesTailDataSize;
|
||||||
|
uint8_t *pIndices = indices->GetPointerAndTailSize(indicesByteOffset, indicesTailDataSize);
|
||||||
const unsigned int indexSize = int(ComponentTypeSize(indicesType));
|
const unsigned int indexSize = int(ComponentTypeSize(indicesType));
|
||||||
uint8_t *indicesEnd = pIndices + count * indexSize;
|
uint8_t *indicesEnd = pIndices + count * indexSize;
|
||||||
|
|
||||||
uint8_t *pValues = values->GetPointer(valuesByteOffset);
|
if ((uint64_t)indicesEnd > (uint64_t)pIndices + indicesTailDataSize) {
|
||||||
|
throw DeadlyImportError("Invalid sparse accessor. Indices outside allocated memory.");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t valuesTailDataSize;
|
||||||
|
uint8_t* pValues = values->GetPointerAndTailSize(valuesByteOffset, valuesTailDataSize);
|
||||||
|
|
||||||
|
if (elementSize * count > valuesTailDataSize) {
|
||||||
|
throw DeadlyImportError("Invalid sparse accessor. Indices outside allocated memory.");
|
||||||
|
}
|
||||||
while (pIndices != indicesEnd) {
|
while (pIndices != indicesEnd) {
|
||||||
size_t offset;
|
size_t offset;
|
||||||
switch (indicesType) {
|
switch (indicesType) {
|
||||||
|
@ -894,6 +914,9 @@ inline void Accessor::Read(Value &obj, Asset &r) {
|
||||||
if (Value *indicesValue = FindObject(*sparseValue, "indices")) {
|
if (Value *indicesValue = FindObject(*sparseValue, "indices")) {
|
||||||
//indices bufferView
|
//indices bufferView
|
||||||
Value *indiceViewID = FindUInt(*indicesValue, "bufferView");
|
Value *indiceViewID = FindUInt(*indicesValue, "bufferView");
|
||||||
|
if (!indiceViewID) {
|
||||||
|
throw DeadlyImportError("A bufferView value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
|
||||||
|
}
|
||||||
sparse->indices = r.bufferViews.Retrieve(indiceViewID->GetUint());
|
sparse->indices = r.bufferViews.Retrieve(indiceViewID->GetUint());
|
||||||
//indices byteOffset
|
//indices byteOffset
|
||||||
sparse->indicesByteOffset = MemberOrDefault(*indicesValue, "byteOffset", size_t(0));
|
sparse->indicesByteOffset = MemberOrDefault(*indicesValue, "byteOffset", size_t(0));
|
||||||
|
@ -909,6 +932,9 @@ inline void Accessor::Read(Value &obj, Asset &r) {
|
||||||
if (Value *valuesValue = FindObject(*sparseValue, "values")) {
|
if (Value *valuesValue = FindObject(*sparseValue, "values")) {
|
||||||
//value bufferView
|
//value bufferView
|
||||||
Value *valueViewID = FindUInt(*valuesValue, "bufferView");
|
Value *valueViewID = FindUInt(*valuesValue, "bufferView");
|
||||||
|
if (!valueViewID) {
|
||||||
|
throw DeadlyImportError("A bufferView value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
|
||||||
|
}
|
||||||
sparse->values = r.bufferViews.Retrieve(valueViewID->GetUint());
|
sparse->values = r.bufferViews.Retrieve(valueViewID->GetUint());
|
||||||
//value byteOffset
|
//value byteOffset
|
||||||
sparse->valuesByteOffset = MemberOrDefault(*valuesValue, "byteOffset", size_t(0));
|
sparse->valuesByteOffset = MemberOrDefault(*valuesValue, "byteOffset", size_t(0));
|
||||||
|
@ -918,8 +944,18 @@ inline void Accessor::Read(Value &obj, Asset &r) {
|
||||||
|
|
||||||
const unsigned int elementSize = GetElementSize();
|
const unsigned int elementSize = GetElementSize();
|
||||||
const size_t dataSize = count * elementSize;
|
const size_t dataSize = count * elementSize;
|
||||||
sparse->PopulateData(dataSize, bufferView ? bufferView->GetPointer(byteOffset) : nullptr);
|
if (bufferView) {
|
||||||
sparse->PatchData(elementSize);
|
size_t bufferViewTailSize;
|
||||||
|
const uint8_t* bufferViewPointer = bufferView->GetPointerAndTailSize(byteOffset, bufferViewTailSize);
|
||||||
|
if (dataSize > bufferViewTailSize) {
|
||||||
|
throw DeadlyImportError("Invalid buffer when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
|
||||||
|
}
|
||||||
|
sparse->PopulateData(dataSize, bufferViewPointer);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sparse->PopulateData(dataSize, nullptr);
|
||||||
|
}
|
||||||
|
sparse->PatchData(elementSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue