{"record":{"id":"1e34af625773c3ef","repo":"NationalSecurityAgency/ghidra","slug":"invalid-referenced-function-circular-thunk-refere","errorCode":null,"errorMessage":"Invalid referenced function: circular thunk reference at ","messagePattern":"Invalid referenced function: circular thunk reference at ","errorType":"exception","errorClass":"OverlappingFunctionException","httpStatus":null,"severity":"error","filePath":"Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CreateFunctionCmd.java","lineNumber":506,"sourceCode":"\t * @param body new function body\n\t * @param monitor task monitor\n\t * @return true if the entry resolved to a thunk\n\t *\n\t * @throws OverlappingFunctionException if thunk thunks itself\n\t */\n\tprivate boolean resolveThunk(Address entry, AddressSetView body, TaskMonitor monitor)\n\t\t\tthrows OverlappingFunctionException {\n\n\t\tAddress thunkedAddr =\n\t\t\tCreateThunkFunctionCmd.getThunkedExternalFunctionAddress(program, entry);\n\t\tif (thunkedAddr == null) {\n\t\t\tthunkedAddr = CreateThunkFunctionCmd.getThunkedAddr(program, entry);\n\t\t}\n\t\tif (thunkedAddr == null || thunkedAddr.equals(entry)) {\n\t\t\treturn false;\n\t\t}\n\t\tif (referringThunkAddresses != null && referringThunkAddresses.contains(entry)) {\n\t\t\tthrow new OverlappingFunctionException(\n\t\t\t\t\"Invalid referenced function: circular thunk reference at \" + entry);\n\t\t}\n\t\t// Handles simple check for single computed jump - may need to add more complex cases\n\t\tCreateThunkFunctionCmd cmd =\n\t\t\tnew CreateThunkFunctionCmd(entry, body, thunkedAddr, referringThunkAddresses);\n\t\tif (cmd.applyTo(program, monitor)) {\n\t\t\tthis.newFunc = cmd.getThunkFunction();\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * using the body map revert any changes made to function bodies\n\t *\n\t * @param bodyChangeMap map of functions to original bodies\n\t */\n\tprivate static void restoreOriginalBodies(Map<Function, AddressSetView> bodyChangeMap) {","sourceCodeStart":488,"sourceCodeEnd":524,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CreateFunctionCmd.java#L488-L524","documentation":"Thrown by CreateFunctionCmd.resolveThunk when the entry being resolved appears in the referringThunkAddresses list - i.e. the function is a thunk that points back to itself (directly or via a chain being constructed), forming a cycle. CreateThunkFunctionCmd refuses to create such a self-referential thunk, so the command aborts with OverlappingFunctionException.","triggerScenarios":"Creating a function at an entry whose thunk target resolves back to the same entry, while that entry is already in the referring-thunk chain. Common with self-jumping trampolines, obfuscated dispatchers, or misidentified thunks where the 'thunked' address equals the entry.","commonSituations":"Obfuscated code with self-referential jumps misclassified as thunks. Manually constructing thunk chains that loop. Re-running CreateFunctionCmd on a half-created thunk graph.","solutions":["Do not mark such an entry as a thunk; create it as a normal function (the 'thunked' address equals the entry, which resolveThunk already skips via thunkedAddr.equals(entry)).","Break the cycle by removing one of the thunk references before re-running the command.","If using CreateFunctionCmd(entry, referringThunkAddresses), ensure the entry is not in that list.","Run auto-analysis 'Thunk' identification with care on obfuscated binaries."],"exampleFix":"// before\nnew CreateFunctionCmd(entry, List.of(entry)).applyTo(program, monitor);\n// entry is in referringThunkAddresses -> OverlappingFunctionException\n\n// after - do not include entry in its own referring-thunk list\nList<Address> referring = new ArrayList<>(thunkChain);\nreferring.remove(entry); // break self-reference\nnew CreateFunctionCmd(entry, referring).applyTo(program, monitor);","handlingStrategy":"validation","validationCode":"if (referringThunkAddresses != null && referringThunkAddresses.contains(entry)) {\n    // would form a self/circular thunk - do not call resolveThunk/CreateFunctionCmd\n}","typeGuard":"boolean isSelfReferentialThunk(Address entry, List<Address> referring) {\n    return referring != null && referring.contains(entry);\n}","tryCatchPattern":"try {\n    cmd.applyTo(program, monitor);\n} catch (OverlappingFunctionException e) {\n    if (e.getMessage().contains(\"circular thunk reference\")) {\n        // remove entry from referringThunkAddresses and retry as a normal function\n    } else throw e;\n}","preventionTips":["Never include the entry in its own referringThunkAddresses list.","Break thunk cycles before re-running CreateFunctionCmd.","Be cautious with thunk auto-analysis on obfuscated binaries."],"tags":["function","thunk","command","circular-reference"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}