@@ -846,10 +846,27 @@ predicate comprehensionStoreStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) {
846846 * ```
847847 * data flows from `x` to the attribute `foo` of (the post-update node for) `obj`.
848848 */
849- predicate attributeStoreStep ( Node nodeFrom , AttributeContent c , PostUpdateNode nodeTo ) {
850- exists ( AttrWrite write |
851- write .accesses ( nodeTo .getPreUpdateNode ( ) , c .getAttribute ( ) ) and
852- nodeFrom = write .getValue ( )
849+ predicate attributeStoreStep ( Node nodeFrom , AttributeContent c , Node nodeTo ) {
850+ exists ( Node object |
851+ // normally we target any PostUpdateNode. However, for class definitions the class
852+ // is only constructed after evaluating its' entire scope, so in terms of python
853+ // evaluations there is no post or pre update nodes, just one node for the class
854+ // expression. Therefore we target the class expression directly.
855+ //
856+ // Note: Due to the way we handle decorators, using a class decorator will result in
857+ // there being a post-update node for the class (argument to the decorator). We do
858+ // not want to differentiate between these two cases, so still target the class
859+ // expression directly.
860+ object = nodeTo .( PostUpdateNode ) .getPreUpdateNode ( ) and
861+ not object .asExpr ( ) instanceof ClassExpr
862+ or
863+ object = nodeTo and
864+ object .asExpr ( ) instanceof ClassExpr
865+ |
866+ exists ( AttrWrite write |
867+ write .accesses ( object , c .getAttribute ( ) ) and
868+ nodeFrom = write .getValue ( )
869+ )
853870 )
854871}
855872
0 commit comments