UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

83 lines 4.73 kB
"use strict"; 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