@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
83 lines • 4.73 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PROBLEMATIC_EVAL = void 0;
const linter_format_1 = require("../linter-format");
const flowr_search_builder_1 = require("../../search/flowr-search-builder");
const range_1 = require("../../util/range");
const linter_tags_1 = require("../linter-tags");
const simple_input_classifier_1 = require("../../queries/catalog/input-sources-query/simple-input-classifier");
const query_1 = require("../../queries/query");
const parse_1 = require("../../slicing/criterion/parse");
/**
* Format a list of input sources either as a single-line string (inline) or a block.
* - inline: returns a semicolon-separated single-line summary
* - block: returns an array of lines (to be joined with newlines by the caller)
*/
function formatInputSources(inputs, inline = true) {
if (!inputs || inputs.length === 0) {
return inline ? '' : [];
}
if (inline) {
return inputs.map(s => `${s.id} (type: ${Array.isArray(s.type) ? '[' + s.type.join(',') + ']' : s.type}, trace: ${s.trace}${s.cds ? ', cds: [' + s.cds.join(',') + ']' : ''})`).join('; ');
}
return inputs.map(s => `- ${s.id}: type=${Array.isArray(s.type) ? '[' + s.type.join(',') + ']' : s.type}, trace=${s.trace}${s.cds ? ', cds=[' + s.cds.join(',') + ']' : ''}`);
}
exports.PROBLEMATIC_EVAL = {
/* create a search that finds calls that look like eval-like functions */
createSearch: config => flowr_search_builder_1.Q.fromQuery({
type: 'call-context',
callName: config.considerAsEval,
callNameExact: false
}),
processSearchResult: async (elements, _config, data) => {
const results = [];
for (const element of elements.getElements()) {
const nid = element.node.info.id;
// run an input-sources query for this eval-like call
const criterion = parse_1.SlicingCriterion.fromId(nid);
const q = { type: 'input-sources', criterion };
const all = await (0, query_1.executeQueries)({ analyzer: data.analyzer }, [q]);
const inputSourcesResult = all['input-sources'];
const sources = inputSourcesResult?.results?.[criterion] ?? [];
// if any input is not a constant or derived constant, flag it
const problematic = sources.some(s => Array.isArray(s.type)
? s.type.some(t => t !== simple_input_classifier_1.InputType.Constant && t !== simple_input_classifier_1.InputType.DerivedConstant)
: (s.type !== simple_input_classifier_1.InputType.Constant && s.type !== simple_input_classifier_1.InputType.DerivedConstant));
if (problematic) {
results.push({
involvedId: nid,
certainty: sources.some(s => Array.isArray(s.type) ? s.type.includes(simple_input_classifier_1.InputType.Unknown) : s.type === simple_input_classifier_1.InputType.Unknown) ? linter_format_1.LintingResultCertainty.Uncertain : linter_format_1.LintingResultCertainty.Certain,
loc: range_1.SourceLocation.fromNode(element.node) ?? range_1.SourceLocation.invalid(),
sources
});
}
}
return {
results,
'.meta': {}
};
},
/* helper to format input sources for pretty printing */
prettyPrint: {
[linter_format_1.LintingPrettyPrintContext.Query]: result => {
const inputs = result.sources ?? [];
const srcStr = formatInputSources(inputs, true);
return `Use of eval-like function at ${range_1.SourceLocation.format(result.loc)}${srcStr ? `; inputs: ${srcStr}` : ''}`;
},
[linter_format_1.LintingPrettyPrintContext.Full]: result => {
const inputs = result.sources ?? [];
const srcLines = formatInputSources(inputs, false);
return `Use of eval-like function at ${range_1.SourceLocation.format(result.loc)} is potentially problematic${srcLines.length ? '\nInputs:\n' + srcLines.join('\n') : ''}`;
}
},
info: {
name: 'Problematic eval',
description: 'Detects uses of eval-like functions whose inputs are not statically constant. Prints the computed input-sources for the eval and flags usages that depend on non-constant/trusted inputs.',
tags: [linter_tags_1.LintingRuleTag.Security, linter_tags_1.LintingRuleTag.Smell, linter_tags_1.LintingRuleTag.Readability, linter_tags_1.LintingRuleTag.Performance],
certainty: linter_format_1.LintingRuleCertainty.BestEffort,
defaultConfig: {
considerAsEval: '^eval$'
}
}
};
//# sourceMappingURL=problematic-eval.js.map