Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Coverity reports out-of-bound-access in C++ code generated by Cython #5668

Closed
oleksandr-pavlyk opened this issue Aug 30, 2023 · 3 comments · Fixed by #5669
Closed

[BUG] Coverity reports out-of-bound-access in C++ code generated by Cython #5668

oleksandr-pavlyk opened this issue Aug 30, 2023 · 3 comments · Fixed by #5669

Comments

@oleksandr-pavlyk
Copy link
Contributor

Describe the bug

Using Cython 3.0.2 and the following source code (named "my_pyx.pyx"):

# distutils: language = c++
# cython: language_level=3
# cython: linetrace=True

cdef class Foo:
    cdef double bar_

    def __cinit__(self, double bar):
        self.bar_ = bar

    cdef double get_bar(self):
        return self.bar_

    def get_square(self):
        return self.bar_ * self.bar_

    @property
    def bar(self):
        return self.get_square()

Generate C++ source file using cython -t -w $(pwd) --cplus my_pyx.pyx. The output is too large to be included verbatim in the ticket.

I built this extension: g++ my_pyx.cpp -fPIC -shared $(python3-config --includes) $(python3-config --ldflags) $(python3-config --libs) -o my_pyx.so.

Coverity scan on such extension flags a "Very high" out-of-bound access issue:

image

Code to reproduce the behaviour:

# distutils: language = c++
# cython: language_level=3
# cython: linetrace=True

cdef class Foo:
    cdef double bar_

    def __cinit__(self, double bar):
        self.bar_ = bar

    cdef double get_bar(self):
        return self.bar_

    def get_square(self):
        return self.bar_ * self.bar_

    @property
    def bar(self):
        return self.get_square()

Expected behaviour

No response

OS

Linux

Python version

No response

Cython version

3.0.2

Additional context

Although Coverity assigns this issue a very high priority, keep in mind it may be a false positive. Even if so, it would be nice to resolve it, since it generates many different hits if many Cython source files are used in the project.

@da-woods
Copy link
Contributor

I think that's a false positive - the third argument is 0 so it's passing 0 args. However, it'd probably cost us little to make __pyx_callargs one element longer to avoid this. PR welcome

@oleksandr-pavlyk
Copy link
Contributor Author

@da-woods A local change

diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py
index 00cdb074c..c77439206 100644
--- a/Cython/Compiler/ExprNodes.py
+++ b/Cython/Compiler/ExprNodes.py
@@ -6601,11 +6601,13 @@ class PyMethodCallNode(SimpleCallNode):
         code.globalstate.use_utility_code(
             UtilityCode.load_cached("PyObjectFastCall", "ObjectHandling.c"))

+        padding_null_arg = code.funcstate.allocate_temp(py_object_type, manage_ref=True)
+        code.putln("%s = NULL;" % padding_null_arg)
         code.putln("{")
         code.putln("PyObject *__pyx_callargs[%d] = {%s, %s};" % (
-            len(args)+1,
+            len(args)+2,
             self_arg,
-            ', '.join(arg.py_result() for arg in args)))
+            ', '.join(tuple(arg.py_result() for arg in args) + (padding_null_arg,))))
         code.putln("%s = __Pyx_PyObject_FastCall(%s, __pyx_callargs+1-%s, %d+%s);" % (
             self.result(),
             function,
@@ -6614,7 +6616,9 @@ class PyMethodCallNode(SimpleCallNode):
             arg_offset_cname))

         code.put_xdecref_clear(self_arg, py_object_type)
+        code.put_xdecref_clear(padding_null_arg, py_object_type)
         code.funcstate.release_temp(self_arg)
+        code.funcstate.release_temp(padding_null_arg)
         code.funcstate.release_temp(arg_offset_cname)
         for arg in args:
             arg.generate_disposal_code(code)

does resolve the issue. If it seems agreeable, I'll open a PR.

oleksandr-pavlyk added a commit to oleksandr-pavlyk/cython that referenced this issue Aug 30, 2023
Closes cythongh-5668

This change resolve Coverity (a false-positive but annoying) issue
of reporting out-of-bound access to array __pyx_callargs in a call
to _Pyx_PyObject_FastCall.
@oleksandr-pavlyk
Copy link
Contributor Author

oleksandr-pavlyk commented Aug 30, 2023

I opened up a draft PR gh-5669 to discuss this change. I am open to suggestions on how to make this fix better.

scoder pushed a commit that referenced this issue Aug 31, 2023
…s pointer in the no-args case. (GH-5669)

This change resolves an issue reported by the Coverity scanner when calling into _Pyx_PyObject_FastCall().
This might be considered a false-positive because we correctly pass the argument length, but it has at least a code smell to pass a pointer that is just behind an array, and thus points to invalid memory.

Closes #5668
@scoder scoder added this to the 3.0.3 milestone Aug 31, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants