How to handle infinite loops within user code

Infinite loops are a pain. In general, running an infinite loop can eat up your computer’s resources and then freeze your IDE – and sometimes even your entire machine. Inside CodeSignal IDE, allowing infinite loops to be unchecked will eventually slow down or crash the UI. These UI issues will make things more difficult for our users and affect the quality of assessment, so we need to make sure we provide a responsive and usable programming environment.

To that end, we had to find a way to handle the problem of users writing infinite loops in their code. even though stop problem This proves that we cannot fully explore infinite loops, by focusing on solving this problem for our specific product and infrastructure, we found solutions that protect our users’ experiences.

handle infinite loops

Basic Solution: Code Instrumentation

Code instrumentation is a common solution for handling infinite loops. Basically, an instrumentation tool can monitor and break infinite loops. we maintained loop protection package in our codebase, which rewrites JavaScript code to break loops that run too long. While a more complex analysis may have enabled us to detect instances of infinite looping, for our CodeSignal IDE, we can go with a simpler solution and have a reasonable timeout for how long a loop should run. should be able to. We avoid the halting problem because we don’t need to decide whether any piece of code will eventually terminate – if a candidate’s code will take a year to finish, it probably won’t be useful for their evaluation Is.

However, this code instrumentation tool can only handle infinite loops explicitly because of the `while`, `for`, and `do…while` keywords. Unfortunately, infinite loops can also be explicitly introduced. For example, a frontend React task might introduce an infinite loop by simultaneously using and updating the same condition in the `useeffect` hook:

 const [count, setCount] = useState(-1);
 useEffect(() => setCount(count + 1), [count]);

Here, update count will call `useeffect`, which will update `count`, which will call `useeffect`, and so on forever

This type of infinite loop will not be caught by the ‘loop-protect’ code instrumentation.

Optimized solution: checking with pings

I looked for a standard solution or package to handle these types of infinite loops that stem from improper use of frontend frameworks, but I didn’t find anything in my search. Since there was no general solution, I started thinking of some optimized approaches based on the infrastructure of CodeSignal.

Luckily, I found a way that our infrastructure would allow us to handle this type of infinite loop. First, some context: In our frontend, the UI is rendered using an IFrame, and the IFrame is hosted on a separate server, with a different domain, over which we have full control. Nowadays, most modern browsers will run an IFRAME from a different domain in a separate thread from the main app. When an infinite loop occurs, however, only the resources in the IFrame thread will be consumed, while other threads can run normally.

Based on this, I implemented a simple ping mechanism: the IFRAME thread regularly finds the thread running the React app, and if the React app does not receive the ping within a certain time frame, it renders the IFRAME shuts off.

Therefore, when an infinite loop occurs, the IFRAME thread consumes more and more resources. This causes longer and longer delays when triggering the next interval, and thus, delays the ping for the response thread. On the React thread, it checks whether it receives a ping from the IFrame thread at a regular rhythm. If it doesn’t receive the ping before it does, we assume that an infinite loop is running and halts the rendering of the iframe. With this mechanism, the user’s browser tab does not freeze due to an infinite loop.

It is important to find the right balance here. The timeout has to be long enough that the proper solution will be able to run even if it is slow and cause minor slowdowns in the iframe thread. If we allow infinite loops to run for too long, however, it is possible that the entire browser will freeze before the timeout is triggered.

Here is a pseudocode example of how to set this ping:

iframescript.js

setInterval(() => 
   // send a ping event to the React thread every 2 sec
   parent.postMessage(
     
       action: 'iframe-ping',
     ,
     '*'
   );
 , 2000);

react component

Class IdeComponent 
 componentDidMount() 
  setInterval(() => 
     If (!this.isIframePing) 
        // halt iframe
        iframe.src = ‘’;
      else 
        this.iframePing = false;
     
  , 10000)
 
 
  window.addEventListener('message', this.processMessage, false);
 
 
 processMessage(message) 
  if (message.data.action === ‘iframe-ping’) 
    this.isIframePing = true;
  
 

Ultimately, this bespoke solution came from our understanding of what our product requirements are and what our infrastructure can support. The halting problem is fascinating and important, but for our needs we didn’t have to solve the whole thing (lucky for us, because it’s literally impossible).

If you love building great products and finding solutions to thorny problems, we’re hiring. Join us, and hopefully someday we’ll be able to show our ingenuity right here on this blog!


Zhoucheng Li is a software engineer at CodeSignal. In his work, he focuses on designing and manufacturing features in CodeSignal’s products using various technology stacks.

Leave a Reply