8
8
import javascript
9
9
private import semmle.javascript.dataflow.internal.FlowSteps as FlowSteps
10
10
private import semmle.javascript.dataflow.internal.PreCallGraphStep
11
+ private import semmle.javascript.dataflow.internal.StepSummary
12
+ private import semmle.javascript.dataflow.internal.sharedlib.SummaryTypeTracker as SummaryTypeTracker
13
+ private import semmle.javascript.dataflow.internal.Contents:: Private as ContentPrivate
14
+ private import semmle.javascript.DynamicPropertyAccess
11
15
private import internal.CachedStages
12
16
13
17
/**
@@ -220,15 +224,53 @@ module API {
220
224
}
221
225
222
226
/**
223
- * Gets a node representing a member of this API component where the name of the member is
224
- * not known statically.
227
+ * DEPRECATED. Use either `getArrayElement()` or `getAMember()` instead.
225
228
*/
229
+ deprecated Node getUnknownMember ( ) { result = this .getArrayElement ( ) }
230
+
231
+ /**
232
+ * Gets an array element of unknown index.
233
+ */
234
+ cached
235
+ Node getUnknownArrayElement ( ) {
236
+ Stages:: ApiStage:: ref ( ) and
237
+ result = this .getASuccessor ( Label:: content ( ContentPrivate:: MkArrayElementUnknown ( ) ) )
238
+ }
239
+
226
240
cached
227
- Node getUnknownMember ( ) {
241
+ private Node getContentRaw ( DataFlow :: Content content ) {
228
242
Stages:: ApiStage:: ref ( ) and
229
- result = this .getASuccessor ( Label:: unknownMember ( ) )
243
+ result = this .getASuccessor ( Label:: content ( content ) )
230
244
}
231
245
246
+ /**
247
+ * Gets a representative for the `content` of this value.
248
+ *
249
+ * When possible, it is preferrable to use one of the specialized variants of this predicate, such as `getMember`.
250
+ */
251
+ pragma [ inline]
252
+ Node getContent ( DataFlow:: Content content ) {
253
+ result = this .getContentRaw ( content )
254
+ or
255
+ result = this .getMember ( content .asPropertyName ( ) )
256
+ }
257
+
258
+ /**
259
+ * Gets a representative for the `contents` of this value.
260
+ */
261
+ bindingset [ contents]
262
+ pragma [ inline_late]
263
+ private Node getContents ( DataFlow:: ContentSet contents ) {
264
+ // We always use getAStoreContent when generating content edges, and we always use getAReadContent when querying the graph.
265
+ result = this .getContent ( contents .getAReadContent ( ) )
266
+ }
267
+
268
+ /**
269
+ * Gets a node representing an arbitrary array element in the array represented by this node.
270
+ */
271
+ cached
272
+ Node getArrayElement ( ) { result = this .getContents ( DataFlow:: ContentSet:: arrayElement ( ) ) }
273
+
232
274
/**
233
275
* Gets a node representing a member of this API component where the name of the member may
234
276
* or may not be known statically.
@@ -238,7 +280,7 @@ module API {
238
280
Stages:: ApiStage:: ref ( ) and
239
281
result = this .getMember ( _)
240
282
or
241
- result = this .getUnknownMember ( )
283
+ result = this .getUnknownArrayElement ( )
242
284
}
243
285
244
286
/**
@@ -790,6 +832,11 @@ module API {
790
832
not DataFlow:: PseudoProperties:: isPseudoProperty ( prop )
791
833
)
792
834
or
835
+ exists ( DataFlow:: ContentSet contents |
836
+ SummaryTypeTracker:: basicStoreStep ( rhs , pred .getALocalUse ( ) , contents ) and
837
+ lbl = Label:: content ( contents .getAStoreContent ( ) )
838
+ )
839
+ or
793
840
exists ( DataFlow:: FunctionNode fn |
794
841
fn = pred and
795
842
lbl = Label:: return ( )
@@ -982,6 +1029,11 @@ module API {
982
1029
// avoid generating member edges like "$arrayElement$"
983
1030
not DataFlow:: PseudoProperties:: isPseudoProperty ( prop )
984
1031
)
1032
+ or
1033
+ exists ( DataFlow:: ContentSet contents |
1034
+ SummaryTypeTracker:: basicLoadStep ( pred .getALocalUse ( ) , ref , contents ) and
1035
+ lbl = Label:: content ( contents .getAStoreContent ( ) )
1036
+ )
985
1037
)
986
1038
or
987
1039
exists ( DataFlow:: Node def , DataFlow:: FunctionNode fn |
@@ -1199,8 +1251,6 @@ module API {
1199
1251
t = useStep ( nd , promisified , boundArgs , prop , result )
1200
1252
}
1201
1253
1202
- private import semmle.javascript.dataflow.internal.StepSummary
1203
-
1204
1254
/**
1205
1255
* Holds if `nd`, which is a use of an API-graph node, flows in zero or more potentially
1206
1256
* inter-procedural steps to some intermediate node, and then from that intermediate node to
@@ -1458,8 +1508,21 @@ module API {
1458
1508
bindingset [ result ]
1459
1509
LabelMember member ( string m ) { result .getProperty ( ) = m }
1460
1510
1461
- /** Gets the `member` edge label for the unknown member. */
1462
- LabelUnknownMember unknownMember ( ) { any ( ) }
1511
+ /** Gets the `content` edge label for content `c`. */
1512
+ LabelContent content ( ContentPrivate:: Content c ) { result .getContent ( ) = c }
1513
+
1514
+ /**
1515
+ * Gets the edge label for an unknown member.
1516
+ *
1517
+ * Currently this is represented the same way as an unknown array element, but this may
1518
+ * change in the future.
1519
+ */
1520
+ ApiLabel unknownMember ( ) { result = arrayElement ( ) }
1521
+
1522
+ /**
1523
+ * Gets the edge label for an unknown array element.
1524
+ */
1525
+ LabelContent arrayElement ( ) { result .getContent ( ) .isUnknownArrayElement ( ) }
1463
1526
1464
1527
/**
1465
1528
* Gets a property name referred to by the given dynamic property access,
@@ -1482,6 +1545,11 @@ module API {
1482
1545
result = unique( string s | s = getAnIndirectPropName ( ref ) )
1483
1546
}
1484
1547
1548
+ pragma [ nomagic]
1549
+ private predicate isEnumeratedPropName ( DataFlow:: Node node ) {
1550
+ node .getAPredecessor * ( ) instanceof EnumeratedPropName
1551
+ }
1552
+
1485
1553
/** Gets the `member` edge label for the given property reference. */
1486
1554
ApiLabel memberFromRef ( DataFlow:: PropRef pr ) {
1487
1555
exists ( string pn | pn = pr .getPropertyName ( ) or pn = getIndirectPropName ( pr ) |
@@ -1493,7 +1561,9 @@ module API {
1493
1561
or
1494
1562
not exists ( pr .getPropertyName ( ) ) and
1495
1563
not exists ( getIndirectPropName ( pr ) ) and
1496
- result = unknownMember ( )
1564
+ // Avoid assignments in an extend-like pattern
1565
+ not isEnumeratedPropName ( pr .getPropertyNameExpr ( ) .flow ( ) ) and
1566
+ result = arrayElement ( )
1497
1567
}
1498
1568
1499
1569
/** Gets the `instance` edge label. */
@@ -1516,10 +1586,10 @@ module API {
1516
1586
LabelForwardingFunction forwardingFunction ( ) { any ( ) }
1517
1587
1518
1588
/** Gets the `promised` edge label connecting a promise to its contained value. */
1519
- LabelPromised promised ( ) { any ( ) }
1589
+ LabelContent promised ( ) { result . getContent ( ) = ContentPrivate :: MkPromiseValue ( ) }
1520
1590
1521
1591
/** Gets the `promisedError` edge label connecting a promise to its rejected value. */
1522
- LabelPromisedError promisedError ( ) { any ( ) }
1592
+ LabelContent promisedError ( ) { result . getContent ( ) = ContentPrivate :: MkPromiseError ( ) }
1523
1593
1524
1594
/** Gets the label for an edge leading from a value `D` to any class that has `D` as a decorator. */
1525
1595
LabelDecoratedClass decoratedClass ( ) { any ( ) }
@@ -1542,18 +1612,12 @@ module API {
1542
1612
exists ( Impl:: MkModuleImport ( mod ) )
1543
1613
} or
1544
1614
MkLabelInstance ( ) or
1545
- MkLabelMember ( string prop ) {
1546
- exports ( _, prop , _) or
1547
- exists ( any ( DataFlow:: ClassNode c ) .getInstanceMethod ( prop ) ) or
1548
- prop = "exports" or
1549
- prop = any ( CanonicalName c ) .getName ( ) or
1550
- prop = any ( DataFlow:: PropRef p ) .getPropertyName ( ) or
1551
- exists ( Impl:: MkTypeUse ( _, prop ) ) or
1552
- exists ( any ( Module m ) .getAnExportedValue ( prop ) ) or
1553
- PreCallGraphStep:: loadStep ( _, _, prop ) or
1554
- PreCallGraphStep:: storeStep ( _, _, prop )
1615
+ MkLabelContent ( DataFlow:: Content content ) or
1616
+ MkLabelMember ( string name ) {
1617
+ name instanceof PropertyName
1618
+ or
1619
+ exists ( Impl:: MkTypeUse ( _, name ) )
1555
1620
} or
1556
- MkLabelUnknownMember ( ) or
1557
1621
MkLabelParameter ( int i ) {
1558
1622
i =
1559
1623
[ 0 .. max ( int args |
@@ -1564,8 +1628,6 @@ module API {
1564
1628
} or
1565
1629
MkLabelReceiver ( ) or
1566
1630
MkLabelReturn ( ) or
1567
- MkLabelPromised ( ) or
1568
- MkLabelPromisedError ( ) or
1569
1631
MkLabelDecoratedClass ( ) or
1570
1632
MkLabelDecoratedMember ( ) or
1571
1633
MkLabelDecoratedParameter ( ) or
@@ -1585,13 +1647,13 @@ module API {
1585
1647
}
1586
1648
1587
1649
/** A label that gets a promised value. */
1588
- class LabelPromised extends ApiLabel , MkLabelPromised {
1589
- override string toString ( ) { result = "getPromised()" }
1650
+ deprecated class LabelPromised extends ApiLabel {
1651
+ LabelPromised ( ) { this = MkLabelContent ( ContentPrivate :: MkPromiseValue ( ) ) }
1590
1652
}
1591
1653
1592
1654
/** A label that gets a rejected promise. */
1593
- class LabelPromisedError extends ApiLabel , MkLabelPromisedError {
1594
- override string toString ( ) { result = "getPromisedError()" }
1655
+ deprecated class LabelPromisedError extends ApiLabel {
1656
+ LabelPromisedError ( ) { this = MkLabelContent ( ContentPrivate :: MkPromiseError ( ) ) }
1595
1657
}
1596
1658
1597
1659
/** A label that gets the return value of a function. */
@@ -1617,9 +1679,39 @@ module API {
1617
1679
override string toString ( ) { result = "getInstance()" }
1618
1680
}
1619
1681
1682
+ /** A label for a content. */
1683
+ class LabelContent extends ApiLabel , MkLabelContent {
1684
+ private DataFlow:: Content content ;
1685
+
1686
+ LabelContent ( ) {
1687
+ this = MkLabelContent ( content ) and
1688
+ // Property names are represented by LabelMember to ensure additional property
1689
+ // names from PreCallGraph step are included, as well as those from MkTypeUse.
1690
+ not content instanceof ContentPrivate:: MkPropertyContent
1691
+ }
1692
+
1693
+ /** Gets the content associated with this label. */
1694
+ DataFlow:: Content getContent ( ) { result = content }
1695
+
1696
+ private string specialisedToString ( ) {
1697
+ content instanceof ContentPrivate:: MkPromiseValue and result = "getPromised()"
1698
+ or
1699
+ content instanceof ContentPrivate:: MkPromiseError and result = "getPromisedError()"
1700
+ or
1701
+ content instanceof ContentPrivate:: MkArrayElementUnknown and result = "getArrayElement()"
1702
+ }
1703
+
1704
+ override string toString ( ) {
1705
+ result = this .specialisedToString ( )
1706
+ or
1707
+ not exists ( this .specialisedToString ( ) ) and
1708
+ result = "getContent(" + content + ")"
1709
+ }
1710
+ }
1711
+
1620
1712
/** A label for the member named `prop`. */
1621
1713
class LabelMember extends ApiLabel , MkLabelMember {
1622
- string prop ;
1714
+ private string prop ;
1623
1715
1624
1716
LabelMember ( ) { this = MkLabelMember ( prop ) }
1625
1717
@@ -1630,10 +1722,8 @@ module API {
1630
1722
}
1631
1723
1632
1724
/** A label for a member with an unknown name. */
1633
- class LabelUnknownMember extends ApiLabel , MkLabelUnknownMember {
1634
- LabelUnknownMember ( ) { this = MkLabelUnknownMember ( ) }
1635
-
1636
- override string toString ( ) { result = "getUnknownMember()" }
1725
+ deprecated class LabelUnknownMember extends LabelContent {
1726
+ LabelUnknownMember ( ) { this .getContent ( ) .isUnknownArrayElement ( ) }
1637
1727
}
1638
1728
1639
1729
/** A label for parameter `i`. */
0 commit comments