lib/nbt: Fix memory leak in case of parsing error

Soda
BodgeMaster 2022-10-17 16:01:57 +02:00
parent 6e57a86338
commit 25d7806f6d
1 changed files with 35 additions and 18 deletions

View File

@ -1176,6 +1176,7 @@ namespace NBT {
// FIXME: memory leak when returning errors
ErrorOr<std::vector<Tag::Generic*>> deserializeRawListContents(uint8_t data[], uint64_t dataSize, uint64_t initialPosition, uint64_t* processedDataSize) {
std::vector<Tag::Generic*> contents;
ErrorOr<std::vector<Tag::Generic*>> returnValue;
// get contained data length by reading it manually because
// the function that does it normally can't deal with
// headerless tags
@ -1183,6 +1184,8 @@ namespace NBT {
// add one byte to position to skip the type byte
ErrorOr<int32_t> elementCount = Helper::readInt32(data, dataSize, initialPosition+1);
if (elementCount.isError) {
// this is before the creation of any pointers so we can just return
// without using the returnError label at the end of this function
return ErrorOr<std::vector<Tag::Generic*>>(true, elementCount.errorCode);
}
@ -1202,14 +1205,10 @@ namespace NBT {
for (int32_t i=0; i<elementCount.value; i++) {
ErrorOr<int8_t> nextInt = Helper::readInt8(data, dataSize, initialPosition+*processedDataSize);
if (nextInt.isError) {
return ErrorOr<std::vector<Tag::Generic*>>(true, nextInt.errorCode);
returnValue = ErrorOr<std::vector<Tag::Generic*>>(true, nextInt.errorCode);
goto returnError;
}
contents.push_back(new Tag::Int8("", nextInt.value));
// The below code would produce a warning on GCC and Clang
// about the computed value not being used. While this does
// apply inside this function, it is ultimately not true
// as the pointer is used both inside and outside of the
// function.
*processedDataSize += 1;
}
break;
@ -1218,7 +1217,8 @@ namespace NBT {
for (int32_t i=0; i<elementCount.value; i++) {
ErrorOr<int16_t> nextInt = Helper::readInt16(data, dataSize, initialPosition+*processedDataSize);
if (nextInt.isError) {
return ErrorOr<std::vector<Tag::Generic*>>(true, nextInt.errorCode);
returnValue = ErrorOr<std::vector<Tag::Generic*>>(true, nextInt.errorCode);
goto returnError;
}
contents.push_back(new Tag::Int16("", nextInt.value));
*processedDataSize += 2;
@ -1229,7 +1229,8 @@ namespace NBT {
for (int32_t i=0; i<elementCount.value; i++) {
ErrorOr<int32_t> nextInt = Helper::readInt32(data, dataSize, initialPosition+*processedDataSize);
if (nextInt.isError) {
return ErrorOr<std::vector<Tag::Generic*>>(true, nextInt.errorCode);
returnValue = ErrorOr<std::vector<Tag::Generic*>>(true, nextInt.errorCode);
goto returnError;
}
contents.push_back(new Tag::Int32("", nextInt.value));
*processedDataSize += 4;
@ -1240,7 +1241,8 @@ namespace NBT {
for (int32_t i=0; i<elementCount.value; i++) {
ErrorOr<float> nextFloat = Helper::readFloat(data, dataSize, initialPosition+*processedDataSize);
if (nextFloat.isError) {
return ErrorOr<std::vector<Tag::Generic*>>(true, nextFloat.errorCode);
returnValue = ErrorOr<std::vector<Tag::Generic*>>(true, nextFloat.errorCode);
goto returnError;
}
contents.push_back(new Tag::Float("", nextFloat.value));
*processedDataSize += 4;
@ -1251,7 +1253,8 @@ namespace NBT {
for (int32_t i=0; i<elementCount.value; i++) {
ErrorOr<int64_t> nextInt = Helper::readInt64(data, dataSize, initialPosition+*processedDataSize);
if (nextInt.isError) {
return ErrorOr<std::vector<Tag::Generic*>>(true, nextInt.errorCode);
returnValue = ErrorOr<std::vector<Tag::Generic*>>(true, nextInt.errorCode);
goto returnError;
}
contents.push_back(new Tag::Int64("", nextInt.value));
*processedDataSize += 8;
@ -1262,7 +1265,8 @@ namespace NBT {
for (int32_t i=0; i<elementCount.value; i++) {
ErrorOr<double> nextDouble = Helper::readDouble(data, dataSize, initialPosition+*processedDataSize);
if (nextDouble.isError) {
return ErrorOr<std::vector<Tag::Generic*>>(true, nextDouble.errorCode);
returnValue = ErrorOr<std::vector<Tag::Generic*>>(true, nextDouble.errorCode);
goto returnError;
}
contents.push_back(new Tag::Double("", nextDouble.value));
*processedDataSize += 8;
@ -1273,7 +1277,8 @@ namespace NBT {
for (int32_t i=0; i<elementCount.value; i++) {
ErrorOr<std::vector<int8_t>> nextArray = Helper::readInt8Array(data, dataSize, initialPosition+*processedDataSize);
if (nextArray.isError) {
return ErrorOr<std::vector<Tag::Generic*>>(true, nextArray.errorCode);
returnValue = ErrorOr<std::vector<Tag::Generic*>>(true, nextArray.errorCode);
goto returnError;
}
contents.push_back(new Tag::Int8Array("", nextArray.value));
*processedDataSize += (uint64_t) nextArray.value.size();
@ -1284,7 +1289,8 @@ namespace NBT {
for (int32_t i=0; i<elementCount.value; i++) {
ErrorOr<tiny_utf8::string> nextString = Helper::readString(data, dataSize, initialPosition+*processedDataSize);
if (nextString.isError) {
return ErrorOr<std::vector<Tag::Generic*>>(true, nextString.errorCode);
returnValue = ErrorOr<std::vector<Tag::Generic*>>(true, nextString.errorCode);
goto returnError;
}
contents.push_back(new Tag::String("", nextString.value));
// this cannot be an error because it just got read
@ -1301,7 +1307,8 @@ namespace NBT {
ErrorOr<std::vector<Tag::Generic*>> nextListContents = deserializeRawListContents(data, dataSize, initialPosition+*processedDataSize, containedDataSize);
if (nextListContents.isError) {
delete containedDataSize;
return ErrorOr<std::vector<Tag::Generic*>>(true, nextListContents.errorCode);
returnValue = ErrorOr<std::vector<Tag::Generic*>>(true, nextListContents.errorCode);
goto returnError;
}
contents.push_back(new Tag::List("", nextListContents.value));
*processedDataSize += *containedDataSize;
@ -1316,7 +1323,8 @@ namespace NBT {
ErrorOr<std::vector<Tag::Generic*>> nextCompoundData = deserialize(data, dataSize, initialPosition+*processedDataSize, containedDataSize);
if (nextCompoundData.isError) {
delete containedDataSize;
return ErrorOr<std::vector<Tag::Generic*>>(true, nextCompoundData.errorCode);
returnValue = ErrorOr<std::vector<Tag::Generic*>>(true, nextCompoundData.errorCode);
goto returnError;
}
contents.push_back(new Tag::Compound("", nextCompoundData.value));
*processedDataSize += *containedDataSize;
@ -1328,7 +1336,8 @@ namespace NBT {
for (int32_t i=0; i<elementCount.value; i++) {
ErrorOr<std::vector<int32_t>> nextArray = Helper::readInt32Array(data, dataSize, initialPosition+*processedDataSize);
if (nextArray.isError) {
return ErrorOr<std::vector<Tag::Generic*>>(true, nextArray.errorCode);
returnValue = ErrorOr<std::vector<Tag::Generic*>>(true, nextArray.errorCode);
goto returnError;
}
contents.push_back(new Tag::Int32Array("", nextArray.value));
*processedDataSize += (uint64_t) nextArray.value.size() * 4;
@ -1339,7 +1348,8 @@ namespace NBT {
for (int32_t i=0; i<elementCount.value; i++) {
ErrorOr<std::vector<int64_t>> nextArray = Helper::readInt64Array(data, dataSize, initialPosition+*processedDataSize);
if (nextArray.isError) {
return ErrorOr<std::vector<Tag::Generic*>>(true, nextArray.errorCode);
returnValue = ErrorOr<std::vector<Tag::Generic*>>(true, nextArray.errorCode);
goto returnError;
}
contents.push_back(new Tag::Int64Array("", nextArray.value));
*processedDataSize += (uint64_t) nextArray.value.size() * 8;
@ -1347,9 +1357,16 @@ namespace NBT {
break;
}
default:
return ErrorOr<std::vector<Tag::Generic*>>(true, ErrorCodes::INVALID_TYPE);
returnValue = ErrorOr<std::vector<Tag::Generic*>>(true, ErrorCodes::INVALID_TYPE);
goto returnError;
}
return ErrorOr<std::vector<Tag::Generic*>>(contents);
returnError:
for (uint64_t i=0; i<contents.size(); i++) {
delete contents.at(i);
}
return returnValue;
}
// comment about blindly passing up error codes applies here