python.attr.correctness.mutable-initializer.attr-mutable-initializer

profile photo of semgrepsemgrep
Author
4,484
Download Count*

Unsafe usage of mutable initializer with attr.s decorator. Multiple instances of this class will re-use the same data structure, which is likely not the desired behavior. Consider instead: replace assignment to mutable initializer (ex. dict() or {}) with attr.ib(factory=type) where type is dict, set, or list

Run Locally

Run in CI

Defintion

rules:
  - id: attr-mutable-initializer
    patterns:
      - pattern-not-inside: |
          def $Y(...):
            ...
      - pattern-not-inside: |
          def $Y(...) -> $TYPE:
            ...
      - pattern-either:
          - pattern-inside: |
              @attr.s(...,auto_attribs=True, ...)
              class $X(...):
                ...
          - pattern-inside: |
              @attrs.define
              class $X(...):
                ...
      - pattern-either:
          - pattern: |
              $M = {...}
          - pattern: $M = [...]
          - pattern: $M = list(...)
          - pattern: $M = set(...)
          - pattern: $M = dict(...)
    message: "Unsafe usage of mutable initializer with attr.s decorator. Multiple
      instances of this class will re-use the same data structure, which is
      likely not the desired behavior. Consider instead: replace assignment to
      mutable initializer (ex. dict() or {}) with attr.ib(factory=type) where
      type is dict, set, or list"
    severity: WARNING
    languages:
      - python
    metadata:
      category: correctness
      technology:
        - attr
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]

Examples

mutable-initializer.py

from attrs import define
from attrs import field


@attr.s(auto_attribs=True)
class ExampleClass(object):
    # ruleid:attr-mutable-initializer
    empty_dict = {}
    # ruleid:attr-mutable-initializer
    empty_list = []
    # ruleid:attr-mutable-initializer
    somedict = dict()
    # ruleid:attr-mutable-initializer
    somelist = list()
    # ruleid:attr-mutable-initializer
    someset = set()
    # ok:attr-mutable-initializer
    ex_good1 = attr.ib(factory=dict)
    # ok:attr-mutable-initializer
    ex_good2 = attr.ib(factory=list)
    # ok:attr-mutable-initializer
    ex_good3 = attr.ib(factory=set)
    # ruleid:attr-mutable-initializer
    myset = {1, 2, 3}

    def foo(self):
        # ok:attr-mutable-initializer
        x = {}

    def bar(self) -> int:
        # ok:attr-mutable-initializer
        thisset = set()


@define
class ExampleClass(object):
    # ruleid:attr-mutable-initializer
    empty_dict = {}
    # ruleid:attr-mutable-initializer
    empty_list = []
    # ruleid:attr-mutable-initializer
    somedict = dict()
    # ruleid:attr-mutable-initializer
    somelist = list()
    # ruleid:attr-mutable-initializer
    someset = set()
    # ok:attr-mutable-initializer
    ex_good1 = field(factory=dict)
    # ok:attr-mutable-initializer
    ex_good2 = field(factory=list)
    # ok:attr-mutable-initializer
    ex_good3 = field(factory=set)
    # ruleid:attr-mutable-initializer
    myset = {1, 2, 3}

    def foo(self):
        # ok:attr-mutable-initializer
        x = {}

    def bar(self) -> int:
        # ok:attr-mutable-initializer
        thisset = set()