Often if you see loops, there is some gas-consuming logic which is executed inside it. If you now find a way for an attacker to artificially increase the loop iterations, you have succesfully crafted a DoS vulnerability where it may eventually reach the point where it exceeds the block gas limit, rendering the function uncallable and potentially freezing certain functionality of the contract.
Example: Vulnerable Code
The following example demonstrates a contract that processes a list of user addresses.
The function processUsers() loops through the entire array and processes each user. As the number of users increases, the gas required for the loop in processUsers() also increases. Eventually, if the array becomes too large, the gas cost for processing all users in a single transaction will exceed the block gas limit, making the function impossible to execute. This effectively results in a Denial of Service (DoS) for any operations dependent on processUsers().
Fix: Using Batched Loops
To avoid hitting the block gas limit, a common solution is to batch the operations. Instead of processing all users in one transaction, you can allow users to process a fixed number of items at a time in multiple transactions. This reduces the gas consumption per transaction and avoids exceeding the block gas limit.
Here's an updated version of the contract that processes users in batches and keeps track of the last processed index: