Merge branch

'origin/GP-6791_emteere_PR-9154_Luminger_fix_noreturn-callfixup-conflict-2'
into patch (Closes #9154)
This commit is contained in:
Ryan Kurtz
2026-05-14 10:37:19 -04:00
2 changed files with 35 additions and 4 deletions
@@ -89,7 +89,7 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
public FindNoReturnFunctionsAnalyzer(String name, String description, public FindNoReturnFunctionsAnalyzer(String name, String description,
AnalyzerType analyzerType) { AnalyzerType analyzerType) {
super(name, description, analyzerType); super(name, description, analyzerType);
setPriority(AnalysisPriority.DISASSEMBLY.after()); setPriority(AnalysisPriority.DISASSEMBLY.after().after());
setSupportsOneTimeAnalysis(); setSupportsOneTimeAnalysis();
} }
@@ -373,6 +373,13 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
} }
for (Address target : flows) { for (Address target : flows) {
// Skip targets that have a callfixup with fall-through semantics.
// A fall-through callfixup explicitly models the function's return
// behavior, so heuristic evidence should not override it.
if (hasCallFixupWithFallThrough(cp, target)) {
continue;
}
int count = 1; int count = 1;
ReferenceIterator refsTo = cp.getReferenceManager().getReferencesTo(target); ReferenceIterator refsTo = cp.getReferenceManager().getReferencesTo(target);
for (Reference reference : refsTo) { for (Reference reference : refsTo) {
@@ -421,6 +428,30 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
return hadSuspiciousFunctions; return hadSuspiciousFunctions;
} }
/**
* Check if the function at the given address has a callfixup that falls through.
* A fall-through callfixup explicitly models the function's return behavior
* (e.g., Watcom's __CHK/__STK stack-check functions), so heuristic noreturn
* detection should not override it.
*
* @param cp current program
* @param target address of the potential noreturn function
* @return true if the function has a callfixup with fall-through semantics
*/
private boolean hasCallFixupWithFallThrough(Program cp, Address target) {
Function func = cp.getFunctionManager().getFunctionAt(target);
if (func == null) {
return false;
}
String callFixup = func.getCallFixup();
if (callFixup == null || callFixup.isEmpty()) {
return false;
}
PcodeInjectLibrary lib = cp.getCompilerSpec().getPcodeInjectLibrary();
InjectPayload payload = lib.getPayload(InjectPayload.CALLFIXUP_TYPE, callFixup);
return payload != null && payload.isFallThru();
}
private boolean targetOnlyCallsNoReturn(Program cp, Address target, AddressSet noReturnSet) private boolean targetOnlyCallsNoReturn(Program cp, Address target, AddressSet noReturnSet)
throws CancelledException { throws CancelledException {
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -47,7 +47,7 @@ public class CallFixupAnalyzer extends AbstractAnalyzer {
public CallFixupAnalyzer(String name, AnalyzerType analyzerType, public CallFixupAnalyzer(String name, AnalyzerType analyzerType,
boolean supportsOneTimeAnalysis) { boolean supportsOneTimeAnalysis) {
super(name, DESCRIPTION, analyzerType); super(name, DESCRIPTION, analyzerType);
setPriority(AnalysisPriority.DISASSEMBLY.after().after()); setPriority(AnalysisPriority.DISASSEMBLY.after());
setDefaultEnablement(true); setDefaultEnablement(true);
if (supportsOneTimeAnalysis) { if (supportsOneTimeAnalysis) {
setSupportsOneTimeAnalysis(); setSupportsOneTimeAnalysis();