Skip to content

Commit c49aa8e

Browse files
Fix issue with large SARIF files crashing view
Authored by: Marc Jaramillo marcnjaramillo@github.com Authored by: Musab Guma'a mgsium@github.com
1 parent c590e2f commit c49aa8e

1 file changed

Lines changed: 54 additions & 12 deletions

File tree

  • extensions/ql-vscode/src

extensions/ql-vscode/src/cli.ts

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ import * as cpp from 'child-process-promise';
22
import * as child_process from 'child_process';
33
import * as fs from 'fs-extra';
44
import * as path from 'path';
5+
import { parser } from 'stream-json';
6+
import { pick } from 'stream-json/filters/Pick';
7+
import { verifier } from 'stream-json/utils/Verifier';
8+
import Assembler = require('stream-json/Assembler');
9+
import { chain } from 'stream-chain';
510
import * as sarif from 'sarif';
611
import { SemVer } from 'semver';
712
import { Readable } from 'stream';
@@ -682,19 +687,56 @@ export class CodeQLCliServer implements Disposable {
682687

683688
async interpretBqrs(metadata: QueryMetadata, resultsPath: string, interpretedResultsPath: string, sourceInfo?: SourceInfo): Promise<sarif.Log> {
684689
await this.runInterpretCommand(SARIF_FORMAT, metadata, resultsPath, interpretedResultsPath, sourceInfo);
685-
686-
let output: string;
687-
try {
688-
output = await fs.readFile(interpretedResultsPath, 'utf8');
689-
} catch (e) {
690-
const rawMessage = e.stderr || e.message;
691-
const errorMessage = rawMessage.startsWith('Cannot create a string')
692-
? `SARIF too large. ${rawMessage}`
693-
: rawMessage;
694-
throw new Error(`Reading output of interpretation failed: ${errorMessage}`);
695-
}
696690
try {
697-
return JSON.parse(output) as sarif.Log;
691+
// Parse the SARIF file into token streams, filtering out only the results array.
692+
const p = parser();
693+
const pipeline = chain([
694+
fs.createReadStream(interpretedResultsPath),
695+
p,
696+
pick({filter: 'runs.0.results'}),
697+
verifier()
698+
]);
699+
700+
// Creates JavaScript objects from the token stream
701+
const asm = Assembler.connectTo(pipeline);
702+
703+
// Returns a constructed Log object with the results or an empty array if no results were found.
704+
// If the parser fails for any reason, it will reject the promise.
705+
return await new Promise((resolve, reject) => {
706+
pipeline.on('error', (error) => {
707+
reject(error);
708+
});
709+
710+
asm.on('done', (asm) => {
711+
const dummyTool : sarif.Tool = {driver: {name: ''}};
712+
if (asm.current) {
713+
const log : sarif.Log = {
714+
version: '2.1.0',
715+
runs: [
716+
{
717+
tool: dummyTool,
718+
results: asm.current
719+
}
720+
]
721+
};
722+
723+
resolve(log);
724+
} else {
725+
const log : sarif.Log = {
726+
version: '2.1.0',
727+
runs: [
728+
{
729+
tool: dummyTool,
730+
results: []
731+
}
732+
]
733+
};
734+
735+
resolve(log);
736+
}
737+
738+
});
739+
});
698740
} catch (err) {
699741
throw new Error(`Parsing output of interpretation failed: ${err.stderr || err}`);
700742
}

0 commit comments

Comments
 (0)