@@ -362,8 +362,8 @@ export class CodeQLCliServer implements Disposable {
362
362
silent ?: boolean ,
363
363
) : Promise < string > {
364
364
const stderrBuffers : Buffer [ ] = [ ] ;
365
- // The array of fragments of stderr of this line. To be used for logging.
366
- let currentLineStderrBuffers : Buffer [ ] = [ ] ;
365
+ // The current buffer of stderr of a single line. To be used for logging.
366
+ let currentLineStderrBuffer : Buffer = Buffer . alloc ( 0 ) ;
367
367
if ( this . commandInProcess ) {
368
368
throw new Error ( "runCodeQlCliInternal called while cli was running" ) ;
369
369
}
@@ -423,28 +423,34 @@ export class CodeQLCliServer implements Disposable {
423
423
stderrBuffers . push ( newData ) ;
424
424
425
425
if ( ! silent ) {
426
- currentLineStderrBuffers . push ( newData ) ;
426
+ currentLineStderrBuffer = Buffer . concat ( [
427
+ currentLineStderrBuffer ,
428
+ newData ,
429
+ ] ) ;
427
430
428
431
// Print the stderr to the logger as it comes in. We need to ensure that
429
432
// we don't split messages on the same line, so we buffer the stderr and
430
433
// split it on EOLs.
431
- let currentLineBuffer = Buffer . concat ( currentLineStderrBuffers ) ;
432
434
const eolBuffer = Buffer . from ( EOL ) ;
433
- if ( currentLineBuffer . includes ( eolBuffer ) ) {
434
- while ( currentLineBuffer . includes ( eolBuffer ) ) {
435
- const line = currentLineBuffer . subarray (
436
- 0 ,
437
- currentLineBuffer . indexOf ( eolBuffer ) ,
438
- ) ;
439
-
440
- void this . logger . log ( line . toString ( "utf-8" ) ) ;
441
-
442
- currentLineBuffer = currentLineBuffer . subarray (
443
- currentLineBuffer . indexOf ( eolBuffer ) + eolBuffer . length ,
444
- ) ;
445
- }
446
435
447
- currentLineStderrBuffers = [ currentLineBuffer ] ;
436
+ let hasCreatedSubarray = false ;
437
+
438
+ let eolIndex ;
439
+ while (
440
+ ( eolIndex = currentLineStderrBuffer . indexOf ( eolBuffer ) ) !== - 1
441
+ ) {
442
+ const line = currentLineStderrBuffer . subarray ( 0 , eolIndex ) ;
443
+ void this . logger . log ( line . toString ( "utf-8" ) ) ;
444
+ currentLineStderrBuffer = currentLineStderrBuffer . subarray (
445
+ eolIndex + eolBuffer . length ,
446
+ ) ;
447
+ hasCreatedSubarray = true ;
448
+ }
449
+
450
+ // We have created a subarray, which means that the complete original buffer is now referenced
451
+ // by the subarray. We need to create a new buffer to avoid memory leaks.
452
+ if ( hasCreatedSubarray ) {
453
+ currentLineStderrBuffer = Buffer . from ( currentLineStderrBuffer ) ;
448
454
}
449
455
}
450
456
} ) ;
@@ -461,10 +467,8 @@ export class CodeQLCliServer implements Disposable {
461
467
// Make sure we remove the terminator;
462
468
const data = fullBuffer . toString ( "utf8" , 0 , fullBuffer . length - 1 ) ;
463
469
if ( ! silent ) {
464
- void this . logger . log (
465
- Buffer . concat ( currentLineStderrBuffers ) . toString ( "utf8" ) ,
466
- ) ;
467
- currentLineStderrBuffers = [ ] ;
470
+ void this . logger . log ( currentLineStderrBuffer . toString ( "utf8" ) ) ;
471
+ currentLineStderrBuffer = Buffer . alloc ( 0 ) ;
468
472
void this . logger . log ( "CLI command succeeded." ) ;
469
473
}
470
474
return data ;
@@ -484,10 +488,8 @@ export class CodeQLCliServer implements Disposable {
484
488
cliError . stack += getErrorStack ( err ) ;
485
489
throw cliError ;
486
490
} finally {
487
- if ( ! silent && currentLineStderrBuffers . length > 0 ) {
488
- void this . logger . log (
489
- Buffer . concat ( currentLineStderrBuffers ) . toString ( "utf8" ) ,
490
- ) ;
491
+ if ( ! silent && currentLineStderrBuffer . length > 0 ) {
492
+ void this . logger . log ( currentLineStderrBuffer . toString ( "utf8" ) ) ;
491
493
}
492
494
// Remove the listeners we set up.
493
495
process . stdout . removeAllListeners ( "data" ) ;
0 commit comments