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 // FIXME: memory leak when returning errors
ErrorOr<std::vector<Tag::Generic*>> deserializeRawListContents(uint8_t data[], uint64_t dataSize, uint64_t initialPosition, uint64_t* processedDataSize) { ErrorOr<std::vector<Tag::Generic*>> deserializeRawListContents(uint8_t data[], uint64_t dataSize, uint64_t initialPosition, uint64_t* processedDataSize) {
std::vector<Tag::Generic*> contents; std::vector<Tag::Generic*> contents;
ErrorOr<std::vector<Tag::Generic*>> returnValue;
// get contained data length by reading it manually because // get contained data length by reading it manually because
// the function that does it normally can't deal with // the function that does it normally can't deal with
// headerless tags // headerless tags
@ -1183,6 +1184,8 @@ namespace NBT {
// add one byte to position to skip the type byte // add one byte to position to skip the type byte
ErrorOr<int32_t> elementCount = Helper::readInt32(data, dataSize, initialPosition+1); ErrorOr<int32_t> elementCount = Helper::readInt32(data, dataSize, initialPosition+1);
if (elementCount.isError) { 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); return ErrorOr<std::vector<Tag::Generic*>>(true, elementCount.errorCode);
} }
@ -1202,14 +1205,10 @@ namespace NBT {
for (int32_t i=0; i<elementCount.value; i++) { for (int32_t i=0; i<elementCount.value; i++) {
ErrorOr<int8_t> nextInt = Helper::readInt8(data, dataSize, initialPosition+*processedDataSize); ErrorOr<int8_t> nextInt = Helper::readInt8(data, dataSize, initialPosition+*processedDataSize);
if (nextInt.isError) { 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)); 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; *processedDataSize += 1;
} }
break; break;
@ -1218,7 +1217,8 @@ namespace NBT {
for (int32_t i=0; i<elementCount.value; i++) { for (int32_t i=0; i<elementCount.value; i++) {
ErrorOr<int16_t> nextInt = Helper::readInt16(data, dataSize, initialPosition+*processedDataSize); ErrorOr<int16_t> nextInt = Helper::readInt16(data, dataSize, initialPosition+*processedDataSize);
if (nextInt.isError) { 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)); contents.push_back(new Tag::Int16("", nextInt.value));
*processedDataSize += 2; *processedDataSize += 2;
@ -1229,7 +1229,8 @@ namespace NBT {
for (int32_t i=0; i<elementCount.value; i++) { for (int32_t i=0; i<elementCount.value; i++) {
ErrorOr<int32_t> nextInt = Helper::readInt32(data, dataSize, initialPosition+*processedDataSize); ErrorOr<int32_t> nextInt = Helper::readInt32(data, dataSize, initialPosition+*processedDataSize);
if (nextInt.isError) { 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)); contents.push_back(new Tag::Int32("", nextInt.value));
*processedDataSize += 4; *processedDataSize += 4;
@ -1240,7 +1241,8 @@ namespace NBT {
for (int32_t i=0; i<elementCount.value; i++) { for (int32_t i=0; i<elementCount.value; i++) {
ErrorOr<float> nextFloat = Helper::readFloat(data, dataSize, initialPosition+*processedDataSize); ErrorOr<float> nextFloat = Helper::readFloat(data, dataSize, initialPosition+*processedDataSize);
if (nextFloat.isError) { 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)); contents.push_back(new Tag::Float("", nextFloat.value));
*processedDataSize += 4; *processedDataSize += 4;
@ -1251,7 +1253,8 @@ namespace NBT {
for (int32_t i=0; i<elementCount.value; i++) { for (int32_t i=0; i<elementCount.value; i++) {
ErrorOr<int64_t> nextInt = Helper::readInt64(data, dataSize, initialPosition+*processedDataSize); ErrorOr<int64_t> nextInt = Helper::readInt64(data, dataSize, initialPosition+*processedDataSize);
if (nextInt.isError) { 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)); contents.push_back(new Tag::Int64("", nextInt.value));
*processedDataSize += 8; *processedDataSize += 8;
@ -1262,7 +1265,8 @@ namespace NBT {
for (int32_t i=0; i<elementCount.value; i++) { for (int32_t i=0; i<elementCount.value; i++) {
ErrorOr<double> nextDouble = Helper::readDouble(data, dataSize, initialPosition+*processedDataSize); ErrorOr<double> nextDouble = Helper::readDouble(data, dataSize, initialPosition+*processedDataSize);
if (nextDouble.isError) { 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)); contents.push_back(new Tag::Double("", nextDouble.value));
*processedDataSize += 8; *processedDataSize += 8;
@ -1273,7 +1277,8 @@ namespace NBT {
for (int32_t i=0; i<elementCount.value; i++) { for (int32_t i=0; i<elementCount.value; i++) {
ErrorOr<std::vector<int8_t>> nextArray = Helper::readInt8Array(data, dataSize, initialPosition+*processedDataSize); ErrorOr<std::vector<int8_t>> nextArray = Helper::readInt8Array(data, dataSize, initialPosition+*processedDataSize);
if (nextArray.isError) { 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)); contents.push_back(new Tag::Int8Array("", nextArray.value));
*processedDataSize += (uint64_t) nextArray.value.size(); *processedDataSize += (uint64_t) nextArray.value.size();
@ -1284,7 +1289,8 @@ namespace NBT {
for (int32_t i=0; i<elementCount.value; i++) { for (int32_t i=0; i<elementCount.value; i++) {
ErrorOr<tiny_utf8::string> nextString = Helper::readString(data, dataSize, initialPosition+*processedDataSize); ErrorOr<tiny_utf8::string> nextString = Helper::readString(data, dataSize, initialPosition+*processedDataSize);
if (nextString.isError) { 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)); contents.push_back(new Tag::String("", nextString.value));
// this cannot be an error because it just got read // 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); ErrorOr<std::vector<Tag::Generic*>> nextListContents = deserializeRawListContents(data, dataSize, initialPosition+*processedDataSize, containedDataSize);
if (nextListContents.isError) { if (nextListContents.isError) {
delete containedDataSize; 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)); contents.push_back(new Tag::List("", nextListContents.value));
*processedDataSize += *containedDataSize; *processedDataSize += *containedDataSize;
@ -1316,7 +1323,8 @@ namespace NBT {
ErrorOr<std::vector<Tag::Generic*>> nextCompoundData = deserialize(data, dataSize, initialPosition+*processedDataSize, containedDataSize); ErrorOr<std::vector<Tag::Generic*>> nextCompoundData = deserialize(data, dataSize, initialPosition+*processedDataSize, containedDataSize);
if (nextCompoundData.isError) { if (nextCompoundData.isError) {
delete containedDataSize; 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)); contents.push_back(new Tag::Compound("", nextCompoundData.value));
*processedDataSize += *containedDataSize; *processedDataSize += *containedDataSize;
@ -1328,7 +1336,8 @@ namespace NBT {
for (int32_t i=0; i<elementCount.value; i++) { for (int32_t i=0; i<elementCount.value; i++) {
ErrorOr<std::vector<int32_t>> nextArray = Helper::readInt32Array(data, dataSize, initialPosition+*processedDataSize); ErrorOr<std::vector<int32_t>> nextArray = Helper::readInt32Array(data, dataSize, initialPosition+*processedDataSize);
if (nextArray.isError) { 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)); contents.push_back(new Tag::Int32Array("", nextArray.value));
*processedDataSize += (uint64_t) nextArray.value.size() * 4; *processedDataSize += (uint64_t) nextArray.value.size() * 4;
@ -1339,7 +1348,8 @@ namespace NBT {
for (int32_t i=0; i<elementCount.value; i++) { for (int32_t i=0; i<elementCount.value; i++) {
ErrorOr<std::vector<int64_t>> nextArray = Helper::readInt64Array(data, dataSize, initialPosition+*processedDataSize); ErrorOr<std::vector<int64_t>> nextArray = Helper::readInt64Array(data, dataSize, initialPosition+*processedDataSize);
if (nextArray.isError) { 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)); contents.push_back(new Tag::Int64Array("", nextArray.value));
*processedDataSize += (uint64_t) nextArray.value.size() * 8; *processedDataSize += (uint64_t) nextArray.value.size() * 8;
@ -1347,9 +1357,16 @@ namespace NBT {
break; break;
} }
default: 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); 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 // comment about blindly passing up error codes applies here