Repository: pylint-dev/astroid

Issue:
AttributeError: 'Slice' object has no attribute 'qname' on fuzzed code
### Steps to reproduce

The following code triggers an `AttributeError` in astroid:

```python
s = slice(-2)
@s()
@six.add_metaclass()
class a: ...
```

This bug was discovered by OSS-Fuzz:
https://issues.oss-fuzz.com/issues/409585564 (report not public yet)

### Current behavior
```
Traceback (most recent call last):
  File "pylint/lint/pylinter.py", line 994, in get_ast
    return MANAGER.ast_from_file(filepath, modname, source=True)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "astroid/manager.py", line 165, in ast_from_file
    return AstroidBuilder(self).file_build(filepath, modname)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "astroid/builder.py", line 145, in file_build
    return self._post_build(module, builder, encoding)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "astroid/builder.py", line 173, in _post_build
    module = self._manager.visit_transforms(module)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "astroid/manager.py", line 129, in visit_transforms
    return self._transform.visit(node)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "astroid/transforms.py", line 162, in visit
    return self._visit(node)
           ^^^^^^^^^^^^^^^^^
  File "astroid/transforms.py", line 84, in _visit
    visited = self._visit_generic(value)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "astroid/transforms.py", line 112, in _visit_generic
    return [self._visit_generic(child) for child in node]
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "astroid/transforms.py", line 112, in <listcomp>
    return [self._visit_generic(child) for child in node]
            ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "astroid/transforms.py", line 119, in _visit_generic
    return self._visit(node)
           ^^^^^^^^^^^^^^^^^
  File "astroid/transforms.py", line 87, in _visit
    return self._transform(node)
           ^^^^^^^^^^^^^^^^^^^^^
  File "astroid/transforms.py", line 67, in _transform
    ret = transform_func(node)
          ^^^^^^^^^^^^^^^^^^^^
  File "astroid/brain/brain_six.py", line 185, in transform_six_add_metaclass
    if func.qname() == SIX_ADD_METACLASS and decorator.args:
       ^^^^^^^^^^
AttributeError: 'Slice' object has no attribute 'qname'
```

### Expected behavior
No crash

### Version
ce81c290efa0

Discussion:
@cdce8p: Note that `slice` itself is not a callable, so the code above would fail in production as well.
```py
>>> slice(-2)()
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    slice(-2)()
    ~~~~~~~~~^^
TypeError: 'slice' object is not callable
```@Pierre-Sassoulas: Thank you again for the fuzzing work @correctmost 

Solution patch:
diff --git a/astroid/brain/brain_six.py b/astroid/brain/brain_six.py
index c222a422..12180097 100644
--- a/astroid/brain/brain_six.py
+++ b/astroid/brain/brain_six.py
@@ -182,7 +182,11 @@ def transform_six_add_metaclass(node):  # pylint: disable=inconsistent-return-st
             func = next(decorator.func.infer())
         except (InferenceError, StopIteration):
             continue
-        if func.qname() == SIX_ADD_METACLASS and decorator.args:
+        if (
+            isinstance(func, (nodes.FunctionDef, nodes.ClassDef))
+            and func.qname() == SIX_ADD_METACLASS
+            and decorator.args
+        ):
             metaclass = decorator.args[0]
             node._metaclass = metaclass
             return node


Test patch:
diff --git a/tests/test_regrtest.py b/tests/test_regrtest.py
index 5321c7e0..528af7a5 100644
--- a/tests/test_regrtest.py
+++ b/tests/test_regrtest.py
@@ -504,3 +504,19 @@ def test_regression_no_crash_during_build() -> None:
     node: nodes.Attribute = extract_node("__()")
     assert node.args == []
     assert node.as_string() == "__()"
+
+
+def test_regression_no_crash_on_called_slice() -> None:
+    """Regression test for issue #2721."""
+    node: nodes.Attribute = extract_node(
+        textwrap.dedent(
+            """
+        s = slice(-2)
+        @s()
+        @six.add_metaclass()
+        class a: ...
+        """
+        )
+    )
+    assert isinstance(node, nodes.ClassDef)
+    assert node.name == "a"