Incorrect length calculation on subTokenset
Description
The function subTokenset implements the subtract operation of token sets:
function subTokenset(Token[] memory a_, Token[] memory b) internal pure returns (Token[] memory) {
Token[] memory a = copyTokenset(a_);
uint newLength = a.length;
uint k;
for (uint i = 0; i < b.length; i++) {
k = a.length;
for (uint j = 0; j < a.length; j++) {
if (isSameToken(b[i], a[j])) {
require(a[j].amount >= b[i].amount, "a.amount less than b.amount");
a[j].amount -= b[i].amount;
if (a[j].amount == 0) {
newLength -= 1;
}
k = j;
break;
}
}
require(k < a.length, "a not contains b");
}
Token[] memory res = new Token[](newLength);
k = 0;
for (uint i = 0; i < a.length; i++) {
if (a[i].amount > 0) {
res[k++] = a[i];
}
}
return res;
}This function subtracts the token set b from the token set a and returns the result-token set. Internally, it modifies the given token set a with in-place manner, creates a new result-token set array, and then copies the nonzero tokens to the new array.
To calculate the length of the result-token--set array, the function uses the variable newLength. The initial value of this variable is the length of the array a, and this variable decrements when the function finds that subtracting the token leads the element in a to have a zero amount.
However, this logic is not perfect for calculating the length of a result array, because
one might include a token with a zero balance in the token set
a. While this influences the initial value ofnewLength, this will not be copied to the result-token set, resulting in an uninitialized token in the array.one might also include a token with a zero balance in the token set
aand then duplicates the same zero-balance token in the token setbmultiple times. This would reduce thenewLengthmore than the number of the tokens with zero balance, having some tokens omitted in the result-token set.
Impact
The subTokenset function may return the token set with uninitialized tokens or without some tokens.
Recommendations
Consider improving the way newLength is handled or manually calculating the length of the result-token set after the subtraction.
Remediation
This issue has been acknowledged by SoSoValue, and a fix was implemented in commit 7ddd9c5d↗.