@@ -580,88 +580,112 @@ module Private {
580580 * summaries into a `SummarizedCallable`s.
581581 */
582582 module External {
583- /**
584- * Provides a means of translating an externally (e.g., CSV) defined flow
585- * summary into a `SummarizedCallable`.
586- */
587- abstract class ExternalSummaryCompilation extends string {
588- bindingset [ this ]
589- ExternalSummaryCompilation ( ) { any ( ) }
590-
591- /** Holds if this flow summary is for callable `c`. */
592- abstract predicate callable ( DataFlowCallable c , boolean preservesValue ) ;
593-
594- /** Holds if the `i`th input component is `c`. */
595- abstract predicate input ( int i , SummaryComponent c ) ;
596-
597- /** Holds if the `i`th output component is `c`. */
598- abstract predicate output ( int i , SummaryComponent c ) ;
599-
600- /**
601- * Holds if the input components starting from index `i` translate into `suffix`.
602- */
603- final predicate translateInput ( int i , SummaryComponentStack suffix ) {
604- exists ( SummaryComponent comp | this .input ( i , comp ) |
605- i = max ( int j | this .input ( j , _) ) and
606- suffix = TSingletonSummaryComponentStack ( comp )
607- or
608- exists ( TSummaryComponent head , SummaryComponentStack tail |
609- this .translateInputCons ( i , head , tail ) and
610- suffix = TConsSummaryComponentStack ( head , tail )
611- )
612- )
613- }
583+ /** Holds if the `n`th component of specification `s` is `c`. */
584+ predicate specSplit ( string s , string c , int n ) { relevantSpec ( s ) and s .splitAt ( " of " , n ) = c }
614585
615- final predicate translateInputCons ( int i , SummaryComponent head , SummaryComponentStack tail ) {
616- this .input ( i , head ) and
617- this .translateInput ( i + 1 , tail )
618- }
586+ /** Holds if specification `s` has length `len`. */
587+ predicate specLength ( string s , int len ) { len = 1 + max ( int n | specSplit ( s , _, n ) ) }
619588
620- /**
621- * Holds if the output components starting from index `i` translate into `suffix`.
622- */
623- predicate translateOutput ( int i , SummaryComponentStack suffix ) {
624- exists ( SummaryComponent comp | this .output ( i , comp ) |
625- i = max ( int j | this .output ( j , _) ) and
626- suffix = TSingletonSummaryComponentStack ( comp )
627- or
628- exists ( TSummaryComponent head , SummaryComponentStack tail |
629- this .translateOutputCons ( i , head , tail ) and
630- suffix = TConsSummaryComponentStack ( head , tail )
631- )
589+ /** Gets the last component of specification `s`. */
590+ string specLast ( string s ) {
591+ exists ( int len |
592+ specLength ( s , len ) and
593+ specSplit ( s , result , len - 1 )
594+ )
595+ }
596+
597+ /** Holds if specification component `c` parses as parameter `n`. */
598+ predicate parseParam ( string c , int n ) {
599+ specSplit ( _, c , _) and
600+ (
601+ c .regexpCapture ( "Parameter\\[([-0-9]+)\\]" , 1 ) .toInt ( ) = n
602+ or
603+ exists ( int n1 , int n2 |
604+ c .regexpCapture ( "Parameter\\[([-0-9]+)\\.\\.([0-9]+)\\]" , 1 ) .toInt ( ) = n1 and
605+ c .regexpCapture ( "Parameter\\[([-0-9]+)\\.\\.([0-9]+)\\]" , 2 ) .toInt ( ) = n2 and
606+ n = [ n1 .. n2 ]
632607 )
633- }
608+ )
609+ }
634610
635- predicate translateOutputCons ( int i , SummaryComponent head , SummaryComponentStack tail ) {
636- this .output ( i , head ) and
637- this .translateOutput ( i + 1 , tail )
638- }
611+ /** Holds if specification component `c` parses as argument `n`. */
612+ predicate parseArg ( string c , int n ) {
613+ specSplit ( _, c , _) and
614+ (
615+ c .regexpCapture ( "Argument\\[([-0-9]+)\\]" , 1 ) .toInt ( ) = n
616+ or
617+ exists ( int n1 , int n2 |
618+ c .regexpCapture ( "Argument\\[([-0-9]+)\\.\\.([0-9]+)\\]" , 1 ) .toInt ( ) = n1 and
619+ c .regexpCapture ( "Argument\\[([-0-9]+)\\.\\.([0-9]+)\\]" , 2 ) .toInt ( ) = n2 and
620+ n = [ n1 .. n2 ]
621+ )
622+ )
639623 }
640624
641- private class ExternalRequiredSummaryComponentStack extends RequiredSummaryComponentStack {
642- private SummaryComponent head ;
625+ private SummaryComponent interpretComponent ( string c ) {
626+ specSplit ( _, c , _) and
627+ (
628+ exists ( int pos | parseArg ( c , pos ) and result = SummaryComponent:: argument ( pos ) )
629+ or
630+ exists ( int pos | parseParam ( c , pos ) and result = SummaryComponent:: parameter ( pos ) )
631+ or
632+ result = interpretComponentSpecific ( c )
633+ )
634+ }
643635
644- ExternalRequiredSummaryComponentStack ( ) {
645- any ( ExternalSummaryCompilation s ) .translateInputCons ( _, head , this ) or
646- any ( ExternalSummaryCompilation s ) .translateOutputCons ( _, head , this )
647- }
636+ private predicate interpretSpec ( string spec , int idx , SummaryComponentStack stack ) {
637+ exists ( string c |
638+ relevantSpec ( spec ) and
639+ specLength ( spec , idx + 1 ) and
640+ specSplit ( spec , c , idx ) and
641+ stack = SummaryComponentStack:: singleton ( interpretComponent ( c ) )
642+ )
643+ or
644+ exists ( SummaryComponent head , SummaryComponentStack tail |
645+ interpretSpec ( spec , idx , head , tail ) and
646+ stack = SummaryComponentStack:: push ( head , tail )
647+ )
648+ }
648649
649- override predicate required ( SummaryComponent c ) { c = head }
650+ private predicate interpretSpec (
651+ string output , int idx , SummaryComponent head , SummaryComponentStack tail
652+ ) {
653+ exists ( string c |
654+ interpretSpec ( output , idx + 1 , tail ) and
655+ specSplit ( output , c , idx ) and
656+ head = interpretComponent ( c )
657+ )
650658 }
651659
652- class ExternalSummarizedCallableAdaptor extends SummarizedCallable {
653- ExternalSummarizedCallableAdaptor ( ) { any ( ExternalSummaryCompilation s ) .callable ( this , _) }
660+ private class MkStack extends RequiredSummaryComponentStack {
661+ MkStack ( ) { interpretSpec ( _, _, _, this ) }
662+
663+ override predicate required ( SummaryComponent c ) { interpretSpec ( _, _, c , this ) }
664+ }
665+
666+ private class SummarizedCallableExternal extends SummarizedCallable {
667+ SummarizedCallableExternal ( ) { externalSummary ( this , _, _, _) }
654668
655669 override predicate propagatesFlow (
656670 SummaryComponentStack input , SummaryComponentStack output , boolean preservesValue
657671 ) {
658- exists ( ExternalSummaryCompilation s |
659- s .callable ( this , preservesValue ) and
660- s .translateInput ( 0 , input ) and
661- s .translateOutput ( 0 , output )
672+ exists ( string inSpec , string outSpec , string kind |
673+ externalSummary ( this , inSpec , outSpec , kind ) and
674+ interpretSpec ( inSpec , 0 , input ) and
675+ interpretSpec ( outSpec , 0 , output )
676+ |
677+ kind = "value" and preservesValue = true
678+ or
679+ kind = "taint" and preservesValue = false
662680 )
663681 }
664682 }
683+
684+ /** Holds if component `c` of specification `spec` cannot be parsed. */
685+ predicate invalidSpecComponent ( string spec , string c ) {
686+ specSplit ( spec , c , _) and
687+ not exists ( interpretComponent ( c ) )
688+ }
665689 }
666690
667691 /** Provides a query predicate for outputting a set of relevant flow summaries. */
0 commit comments