-
Notifications
You must be signed in to change notification settings - Fork 288
/
return-break.sol
143 lines (112 loc) · 3.77 KB
/
return-break.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
import "forge-std/Test.sol";
/*
Name: Use of return in inner loop iteration leads to unintended termination.
Description:
BankContractBug's addBanks function exhibits an incorrect usage of the return statement within a loop iteration,
resulting in unintended termination of the loop. The return statement is placed inside the inner loop,
causing premature exit from the function before completing the iteration over all bank addresses.
Mitigation:
Use break instead of return
REF:
https://twitter.com/1nf0s3cpt/status/1678596730865221632
https://github.com/code-423n4/2022-03-lifinance-findings/issues/34
https://solidity-by-example.org/loop/
*/
contract ContractTest is Test {
BankContractBug BankContractBugContract;
FixedBank FixedBankContract;
function setUp() public {
BankContractBugContract = new BankContractBug();
FixedBankContract = new FixedBank();
}
function testReturnBug() public {
address[] memory bankAddresses = new address[](3);
string[] memory bankNames = new string[](3);
// Bank account 1
bankAddresses[0] = address(1);
bankNames[0] = "ABC Bank";
// Bank account 2
bankAddresses[1] = address(2);
bankNames[1] = "XYZ Bank";
// Bank account 3
bankAddresses[2] = address(3);
bankNames[2] = "Global Bank";
BankContractBugContract.addBanks(bankAddresses, bankNames);
BankContractBugContract.getBankCount();
}
function testBreak() public {
address[] memory bankAddresses = new address[](3);
string[] memory bankNames = new string[](3);
// Bank account 1
bankAddresses[0] = address(1);
bankNames[0] = "ABC Bank";
// Bank account 2
bankAddresses[1] = address(2);
bankNames[1] = "XYZ Bank";
// Bank account 3
bankAddresses[2] = address(3);
bankNames[2] = "Global Bank";
FixedBankContract.addBanks(bankAddresses, bankNames);
FixedBankContract.getBankCount();
}
receive() external payable {}
}
contract BankContractBug {
struct Bank {
address bankAddress;
string bankName;
}
Bank[] public banks;
function addBanks(
address[] memory bankAddresses,
string[] memory bankNames
) public {
require(
bankAddresses.length == bankNames.length,
"Input arrays must have the same length."
);
for (uint i = 0; i < bankAddresses.length; i++) {
if (bankAddresses[i] == address(0)) {
continue;
}
// i++ is not executed when return is executed
for (i = 0; i < bankAddresses.length; i++) {
banks.push(Bank(bankAddresses[i], bankNames[i]));
return;
}
}
}
function getBankCount() public view returns (uint) {
return banks.length;
}
}
contract FixedBank {
struct Bank {
address bankAddress;
string bankName;
}
Bank[] public banks;
function addBanks(
address[] memory bankAddresses,
string[] memory bankNames
) public {
require(
bankAddresses.length == bankNames.length,
"Input arrays must have the same length."
);
for (uint i = 0; i < bankAddresses.length; i++) {
if (bankAddresses[i] == address(0)) {
continue;
}
for (uint i = 0; i < bankAddresses.length; i++) {
banks.push(Bank(bankAddresses[i], bankNames[i]));
break; // Correct usage of break to terminate the inner loop
}
}
}
function getBankCount() public view returns (uint) {
return banks.length;
}
}