Skip to content

Possible infinite loop in js execution? #988

@RuralHunter

Description

@RuralHunter

I'm using htmlunit 4.6 to open a web page. Occasionally it gets hanging up fore ever although I have already set timeout for network and js execution. I got the stack trace of the process and it looks is in an infinite loop based on the phenomenons:

  1. The hanging thread is runnable
  2. The stack trace doesn't change between times
  3. The process consumes much CPU.

There are 2 threads in the process hanging on the same spot of js execution. One is main thread at WebClient.getPage(). Another is "JS executor" from background jobs thread:
Thread 1:

"main" #1 prio=5 os_prio=0 cpu=22206697.68ms elapsed=22389.78s tid=0x00007f5170019f00 nid=0x2d6762 runnable  [0x00007f5174d00000]
   java.lang.Thread.State: RUNNABLE
	at org.htmlunit.corejs.javascript.EmbeddedSlotMap.query(EmbeddedSlotMap.java:82)
	at org.htmlunit.corejs.javascript.SlotMapContainer.query(SlotMapContainer.java:67)
	at org.htmlunit.corejs.javascript.ScriptableObject.isGetterOrSetter(ScriptableObject.java:656)
	at org.htmlunit.corejs.javascript.NativeArray.has(NativeArray.java:603)
	at org.htmlunit.corejs.javascript.ScriptableObject.getBase(ScriptableObject.java:2510)
	at org.htmlunit.corejs.javascript.ScriptableObject.putProperty(ScriptableObject.java:2362)
	at org.htmlunit.corejs.javascript.ScriptRuntime.setObjectElem(ScriptRuntime.java:1857)
	at org.htmlunit.corejs.javascript.ScriptRuntime.setObjectElem(ScriptRuntime.java:1846)
	at org.htmlunit.corejs.javascript.Interpreter.doSetElem(Interpreter.java:3004)
	at org.htmlunit.corejs.javascript.Interpreter.interpretLoop(Interpreter.java:1692)
	at org.htmlunit.corejs.javascript.Interpreter.interpret(Interpreter.java:1139)
	at org.htmlunit.corejs.javascript.InterpretedFunction.call(InterpretedFunction.java:91)
	at org.htmlunit.corejs.javascript.ContextFactory.doTopCall(ContextFactory.java:395)
	at org.htmlunit.javascript.HtmlUnitContextFactory.doTopCall(HtmlUnitContextFactory.java:300)
	at org.htmlunit.corejs.javascript.ScriptRuntime.doTopCall(ScriptRuntime.java:4278)
	at org.htmlunit.corejs.javascript.InterpretedFunction.exec(InterpretedFunction.java:104)
	at org.htmlunit.javascript.JavaScriptEngine$2.doRun(JavaScriptEngine.java:784)
	at org.htmlunit.javascript.JavaScriptEngine$HtmlUnitContextAction.run(JavaScriptEngine.java:890)
         ...

Thread 2:

"JS executor for org.htmlunit.WebClient@289254fe" #150 daemon prio=5 os_prio=0 cpu=22129222.51ms elapsed=22162.97s tid=0x00007f5171b45550 nid=0x2d68da runnable  [0x00007f50d2dfb000]
   java.lang.Thread.State: RUNNABLE
	at org.htmlunit.corejs.javascript.EmbeddedSlotMap.query(EmbeddedSlotMap.java:82)
	at org.htmlunit.corejs.javascript.SlotMapContainer.query(SlotMapContainer.java:67)
	at org.htmlunit.corejs.javascript.ScriptableObject.isGetterOrSetter(ScriptableObject.java:656)
	at org.htmlunit.corejs.javascript.NativeArray.has(NativeArray.java:603)
	at org.htmlunit.corejs.javascript.ScriptableObject.getBase(ScriptableObject.java:2510)
	at org.htmlunit.corejs.javascript.ScriptableObject.putProperty(ScriptableObject.java:2362)
	at org.htmlunit.corejs.javascript.ScriptRuntime.setObjectElem(ScriptRuntime.java:1857)
	at org.htmlunit.corejs.javascript.ScriptRuntime.setObjectElem(ScriptRuntime.java:1846)
	at org.htmlunit.corejs.javascript.Interpreter.doSetElem(Interpreter.java:3004)
	at org.htmlunit.corejs.javascript.Interpreter.interpretLoop(Interpreter.java:1692)
	at org.htmlunit.corejs.javascript.Interpreter.interpret(Interpreter.java:1139)
	at org.htmlunit.corejs.javascript.InterpretedFunction.call(InterpretedFunction.java:91)
	at org.htmlunit.corejs.javascript.ContextFactory.doTopCall(ContextFactory.java:395)
	at org.htmlunit.javascript.HtmlUnitContextFactory.doTopCall(HtmlUnitContextFactory.java:300)
	at org.htmlunit.corejs.javascript.ScriptRuntime.doTopCall(ScriptRuntime.java:4278)
	at org.htmlunit.corejs.javascript.NativePromise$Reaction.callReactionFunction(NativePromise.java:669)
	at org.htmlunit.corejs.javascript.NativePromise$Reaction.invoke(NativePromise.java:656)
	at org.htmlunit.corejs.javascript.NativePromise.lambda$fulfillPromise$8(NativePromise.java:473)
	at org.htmlunit.corejs.javascript.NativePromise$$Lambda$417/0x00007f50d4716420.run(Unknown Source)
	at org.htmlunit.corejs.javascript.Context.processMicrotasks(Context.java:2420)
	at org.htmlunit.javascript.JavaScriptEngine$HtmlUnitContextAction.run(JavaScriptEngine.java:893)
	at org.htmlunit.corejs.javascript.Context.call(Context.java:590)
	at org.htmlunit.corejs.javascript.ContextFactory.call(ContextFactory.java:487)
	at org.htmlunit.javascript.HtmlUnitContextFactory.callSecured(HtmlUnitContextFactory.java:314)
	at org.htmlunit.javascript.JavaScriptEngine.callFunction(JavaScriptEngine.java:846)
	at org.htmlunit.javascript.JavaScriptEngine.callFunction(JavaScriptEngine.java:814)
	at org.htmlunit.html.HtmlPage.executeJavaScriptFunction(HtmlPage.java:2568)
	at org.htmlunit.html.HtmlPage.executeJavaScriptFunction(HtmlPage.java:2561)
	at org.htmlunit.javascript.background.JavaScriptFunctionJob.runJavaScript(JavaScriptFunctionJob.java:56)
	at org.htmlunit.javascript.background.JavaScriptExecutionJob.run(JavaScriptExecutionJob.java:95)
	at org.htmlunit.javascript.background.JavaScriptJobManagerImpl.runSingleJob(JavaScriptJobManagerImpl.java:451)
	at org.htmlunit.javascript.background.DefaultJavaScriptExecutor.run(DefaultJavaScriptExecutor.java:154)
	at java.lang.Thread.run(java.base@17.0.15/Thread.java:840)

It's hard to reproduce so I'm not able to get the js causing this for now. I checked the code of the loop method is like this:

    public Slot query(Object key, int index) {
        if (slots == null) {
            return null;
        }

        int indexOrHash = (key != null ? key.hashCode() : index);
        int slotIndex = getSlotIndex(slots.length, indexOrHash);
        for (Slot slot = slots[slotIndex]; slot != null; slot = slot.next) {
            if (indexOrHash == slot.indexOrHash && Objects.equals(slot.name, key)) {
                return slot;
            }
        }
        return null;
    }

I'm wondering is it possible that in some casese the slot.next could point to a previous slot in the slots array and causes this infinite loop?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions