@specs-feup/clava
Version:
A C/C++ source-to-source compiler written in Typescript
115 lines (106 loc) • 3.48 kB
text/typescript
import Query from "@specs-feup/lara/api/weaver/Query.js";
import {
ArrayAccess,
ArrayType,
FileJp,
FunctionJp,
Program,
Vardecl,
} from "../../../Joinpoints.js";
import Analyser from "../Analyser.js";
import ResultFormatManager from "../ResultFormatManager.js";
import BoundsResult from "./BoundsResult.js";
type T = Program | FileJp;
/**
* Analyser that scan code to detect unsafe array accesses
*/
export default class BoundsAnalyser extends Analyser {
resultFormatManager = new ResultFormatManager();
/**
* Check file for illegal access of an array with an invalid index
* @param $startNode -
* @returns fileResult
*/
analyse($startNode: T = Query.root() as Program) {
let boundsResultList: BoundsResult[] = [];
for (const $node of Query.searchFrom($startNode)) {
if (!($node instanceof FunctionJp)) {
continue;
}
for (const $child of $node.descendants) {
if ($child instanceof Vardecl && $child.type instanceof ArrayType) {
const lengths = $child.type.arrayDims;
if ($child.hasInit) {
boundsResultList.push(
new BoundsResult(
"Unsafe array access",
$child,
" The index used to access the array is not valid (CWE-119). Please check the length of the array accessed.\n\n",
$node.name,
true,
false,
lengths
)
);
continue;
}
boundsResultList.push(
new BoundsResult(
"Unsafe array access",
$child,
" The array being accessed has not been initialized (CWE-457).\n\n",
$node.name,
false,
false,
lengths
)
);
continue;
}
if ($child instanceof ArrayAccess) {
const arrayName = $child.arrayVar.code;
for (const result of boundsResultList) {
if (result.arrayName === arrayName) {
// list of indexes in square brackets
const indexes = $child.code.match(/\[[0-9]+\]/g);
if (indexes == null) {
continue;
}
for (let i = 0; i < indexes.length; i++) {
if (indexes[i].length > 1) {
// formats list of indexes
indexes.forEach((index) =>
index.substring(1, index.length - 1)
);
}
if (result.initializedFlag === false) {
result.unsafeAccessFlag = true;
result.line = $child.line;
continue;
}
if (
Number(indexes[i]) > result.lengths[i] - 1 ||
Number(indexes[i]) < 0
) {
// access out of bounds
result.unsafeAccessFlag = true;
result.line = $child.line;
continue;
}
}
}
}
}
}
}
boundsResultList = boundsResultList.filter(
(result) => result.unsafeAccessFlag === true
);
this.resultFormatManager.setAnalyserResultList(boundsResultList);
const fileResult = this.resultFormatManager.formatResultList($startNode);
if (fileResult === undefined) {
return;
}
return fileResult;
}
}