[gcc-python-plugin] make-index.py: categorize error reports in the summary
by David Hugh Malcolm
commit cc9ff9c0d6c02870ff2eefbd2733a0ae222826e0
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Fri Feb 10 13:37:37 2012 -0500
make-index.py: categorize error reports in the summary
Add a Triager class, implementing a policy to try to categorize the error
reports, presenting them in priority order.
Also, link to the correct report within HTML pages that contain multiple
reports
misc/fedora/make-index.py | 129 ++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 115 insertions(+), 14 deletions(-)
---
diff --git a/misc/fedora/make-index.py b/misc/fedora/make-index.py
index f01c0df..0229970 100644
--- a/misc/fedora/make-index.py
+++ b/misc/fedora/make-index.py
@@ -20,41 +20,129 @@
from collections import namedtuple
import os
+import re
from BeautifulSoup import BeautifulSoup
class ErrorReport(namedtuple('ErrorReport',
- ('filename', 'function', 'errmsg'))):
- pass
+ ('htmlpath', 'htmlid', 'filename', 'function', 'errmsg'))):
+ def href(self):
+ return '%s#%s' % (self.htmlpath, self.htmlid)
-def get_errors_from_file(path):
+def get_errors_from_file(htmlpath):
"""
Scrape metadata from out of a -refcount-errors.html file,
yielding a sequence of ErrorReport
"""
- with open(path) as f:
+ with open(htmlpath) as f:
soup = BeautifulSoup(f)
- # Look within top-level <table> elements for result summaries that
+ # Look within top-level <div> elements for result summaries that
# look like this:
+ # <div id="report-0">
# <table>
# <tr><td>File:</td> <td><b>gstmodule.c</b></td></tr>
# <tr><td>Function:</td> <td><b>init_gst</b></td></tr>
# <tr><td>Error:</td> <td><b>ob_refcnt of new ref from (unknown) pygobject_init is 1 too high</b></td></tr>
# </table>
- for table in soup.html.body.findAll('table'):
+ for div in soup.html.body.findAll('div'):
+ table = div.table
+ if not table:
+ continue
+ print div['id']
+ #print 'div: %r' % div
rows = table('tr')
def get_second_col(row):
return row('td')[1].b.string
- yield ErrorReport(filename=get_second_col(rows[0]),
+ yield ErrorReport(htmlpath=htmlpath,
+ htmlid=div['id'],
+ filename=get_second_col(rows[0]),
function = get_second_col(rows[1]),
errmsg = get_second_col(rows[2]))
+class Severity(namedtuple('Severity', ('priority', 'title', 'description'))):
+ """
+ priority: the int values are in asending severity (so that e.g. priority 5
+ is more severe than severity 4). This should give us a useful sort order
+ for Severity instances
+ """
+
+(PRIORITY__RETURNING_NULL_WITHOUT_SETTING_EXCEPTION,
+ PRIORITY__REFERENCE_LEAK_OF_SINGLETON,
+ PRIORITY__REFERENCE_LEAK,
+ PRIORITY__REFERENCE_COUNT_TOO_LOW,
+ PRIORITY__SEGFAULT,
+ PRIORITY__UNCLASSIFIED,
+ ) = range(6)
+
+class Triager:
+ """
+ Classify ErrorReport instances into various severity levels, identified by
+ Severity instances
+ """
+ def classify(self, report):
+ m = re.match('ob_refcnt of (.+) too high', report.errmsg)
+ if m:
+ if 'PyBool_FromLong' in report.errmsg:
+ is_singleton = True
+ else:
+ is_singleton = False
+ if is_singleton:
+ return Severity(priority=PRIORITY__REFERENCE_LEAK_OF_SINGLETON,
+ title='Reference leaks of a singleton',
+ description=('Code paths in which the reference count of a singleton object will be left too large. '
+ 'Technically incorrect, but unlikely to cause problems'))
+ else:
+ return Severity(priority=PRIORITY__REFERENCE_LEAK,
+ title='Reference leaks',
+ description='')
+
+ m = re.match('ob_refcnt of (.+) too low', report.errmsg)
+ if m:
+ return Severity(priority=PRIORITY__REFERENCE_COUNT_TOO_LOW,
+ title='Reference count too low',
+ description='')
+
+ if report.errmsg == 'returning (PyObject*)NULL without setting an exception':
+ return Severity(priority=PRIORITY__RETURNING_NULL_WITHOUT_SETTING_EXCEPTION,
+ title='Returning (PyObject*)NULL without setting an exception',
+ description='These messages are often false-positives')
+
+ m = re.match('calling (.+) with NULL as argument (.*)', report.errmsg)
+ if m:
+ # FIXME: is it just on the error-handling path?
+ return Severity(priority=PRIORITY__SEGFAULT,
+ title='Segfaults',
+ description='')
+
+ m = re.match('dereferencing NULL (.*)', report.errmsg)
+ if m:
+ # FIXME: is it just on the error-handling path?
+ return Severity(priority=PRIORITY__SEGFAULT,
+ title='Segfaults',
+ description='')
+
+ m = re.match('reading from deallocated memory (.*)', report.errmsg)
+ if m:
+ # FIXME: is it just on the error-handling path?
+ return Severity(priority=PRIORITY__SEGFAULT,
+ title='Segfaults',
+ description='')
+
+ return Severity(priority=PRIORITY__UNCLASSIFIED,
+ title='Unclassified errors',
+ description="The triager didn't know how to classify these ones")
+
def gather_html_reports(path):
outpath = os.path.join(path, 'index.html')
with open(outpath, 'w') as f:
f.write('<html><head><title>%s</title></head>\n' % path)
f.write(' <body>\n')
- f.write(' <table>\n')
+
+ # Gather the ErrorReport by severity
+ triager = Triager()
+
+ # mapping from Severity to list of ErrorReport
+ severities = {}
for dirpath, dirnames, filenames in os.walk(path):
#print dirpath, dirnames, filenames
@@ -66,12 +154,25 @@ def gather_html_reports(path):
print(er.filename)
print(er.function)
print(er.errmsg)
- href = os.path.relpath(htmlpath, path)
- f.write(' <tr> <td><a href=%s>%s</a></td> <td><a href=%s>%s</a></td> <td><a href=%s>%s</a></td> </tr>'
- % (href, er.filename,
- href, er.function,
- href, er.errmsg))
- f.write(' </table>\n')
+ sev = triager.classify(er)
+ print(sev)
+ if sev in severities:
+ severities[sev].append(er)
+ else:
+ severities[sev] = [er]
+
+ for sev in sorted(severities.keys())[::-1]:
+ f.write(' <h2>%s</h2>\n' % sev.title)
+ f.write(' <p>%s</p>\n' % sev.description)
+ f.write(' <table>\n')
+ for er in severities[sev]:
+ href = os.path.relpath(er.href(), path)
+ f.write(' <tr> <td><a href=%s>%s</a></td> <td><a href=%s>%s</a></td> <td><a href=%s>%s</a></td> </tr>'
+ % (href, er.filename,
+ href, er.function,
+ href, er.errmsg))
+ f.write(' </table>\n')
+
f.write(' </body>\n')
f.write('</html>\n')
12 years, 3 months
[gcc-python-plugin] cpychecker: improvement to HTML reports
by David Hugh Malcolm
commit f65c7e347c2fcab043d0757bbefb5f52c0fda6de
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Fri Feb 10 13:32:27 2012 -0500
cpychecker: improvement to HTML reports
wrap each report in a div tag, with an "id".
fix missing closing tags
libcpychecker/visualizations.py | 7 +++++--
1 files changed, 5 insertions(+), 2 deletions(-)
---
diff --git a/libcpychecker/visualizations.py b/libcpychecker/visualizations.py
index aea23fb..c2431e5 100644
--- a/libcpychecker/visualizations.py
+++ b/libcpychecker/visualizations.py
@@ -290,9 +290,9 @@ pre {
return result
def make_report(self, report):
-
+ result = '<div id="report-%i">\n' % self.trace_idx
# Heading:
- result = '<table>\n'
+ result += '<table>\n'
result += ' <tr><td>File:</td> <td><b>%s</b></td></tr>\n' % self.fun.start.file
result += ' <tr><td>Function:</td> <td><b>%s</b></td></tr>\n' % self.fun.decl.name
result += ' <tr><td>Error:</td> <td><b>%s</b></td></tr>\n' % report.msg
@@ -302,6 +302,8 @@ pre {
if report.trace:
result += self.make_html_for_trace(report, report.trace)
result += '<hr/>'
+
+ result += '</div>\n'
return result
def make_html_for_trace(self, report, trace):
@@ -383,6 +385,7 @@ pre {
if note.loc and note.loc.line == linenum:
result += '<span class="transition">%s</span>\n' % note.msg
+ result += '</pre></div>\n'
result += '\n'
result += '<script type="text/javascript">\n'
result += ' jsPlumb.bind("ready", function() {\n'
12 years, 3 months
[gcc-python-plugin] mass-rebuild.py: add a new script to generate an index.html summary from build logs
by David Hugh Malcolm
commit c59c1bc615ff3f794da8bfc21d32962ed25635e6
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Fri Feb 10 11:24:39 2012 -0500
mass-rebuild.py: add a new script to generate an index.html summary from build logs
misc/fedora/make-index.py | 84 +++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 84 insertions(+), 0 deletions(-)
---
diff --git a/misc/fedora/make-index.py b/misc/fedora/make-index.py
new file mode 100644
index 0000000..f01c0df
--- /dev/null
+++ b/misc/fedora/make-index.py
@@ -0,0 +1,84 @@
+# Copyright 2012 David Malcolm <dmalcolm(a)redhat.com>
+# Copyright 2012 Red Hat, Inc.
+#
+# This is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <http://www.gnu.org/licenses/>.
+
+# Walk a directory hierarchy looking for *-refcount-errors.html files,
+# building an index.html linking to them all
+
+from collections import namedtuple
+import os
+
+from BeautifulSoup import BeautifulSoup
+
+class ErrorReport(namedtuple('ErrorReport',
+ ('filename', 'function', 'errmsg'))):
+ pass
+
+def get_errors_from_file(path):
+ """
+ Scrape metadata from out of a -refcount-errors.html file,
+ yielding a sequence of ErrorReport
+ """
+ with open(path) as f:
+ soup = BeautifulSoup(f)
+ # Look within top-level <table> elements for result summaries that
+ # look like this:
+ # <table>
+ # <tr><td>File:</td> <td><b>gstmodule.c</b></td></tr>
+ # <tr><td>Function:</td> <td><b>init_gst</b></td></tr>
+ # <tr><td>Error:</td> <td><b>ob_refcnt of new ref from (unknown) pygobject_init is 1 too high</b></td></tr>
+ # </table>
+ for table in soup.html.body.findAll('table'):
+ rows = table('tr')
+ def get_second_col(row):
+ return row('td')[1].b.string
+ yield ErrorReport(filename=get_second_col(rows[0]),
+ function = get_second_col(rows[1]),
+ errmsg = get_second_col(rows[2]))
+
+def gather_html_reports(path):
+ outpath = os.path.join(path, 'index.html')
+ with open(outpath, 'w') as f:
+ f.write('<html><head><title>%s</title></head>\n' % path)
+ f.write(' <body>\n')
+ f.write(' <table>\n')
+
+ for dirpath, dirnames, filenames in os.walk(path):
+ #print dirpath, dirnames, filenames
+ for filename in filenames:
+ if filename.endswith('-refcount-errors.html'):
+ print ' ', os.path.join(dirpath, filename)
+ htmlpath = os.path.join(dirpath, filename)
+ for er in get_errors_from_file(htmlpath):
+ print(er.filename)
+ print(er.function)
+ print(er.errmsg)
+ href = os.path.relpath(htmlpath, path)
+ f.write(' <tr> <td><a href=%s>%s</a></td> <td><a href=%s>%s</a></td> <td><a href=%s>%s</a></td> </tr>'
+ % (href, er.filename,
+ href, er.function,
+ href, er.errmsg))
+ f.write(' </table>\n')
+ f.write(' </body>\n')
+ f.write('</html>\n')
+
+
+# locate .html
+# iterate over toplevel in "LOGS":
+for resultdir in os.listdir('LOGS'):
+ resultpath = os.path.join('LOGS', resultdir)
+ print(resultpath)
+ gather_html_reports(resultpath)
12 years, 3 months
[gcc-python-plugin] cpychecker: fix various format codes for Py_BuildValue
by David Hugh Malcolm
commit 40c8d008d86e97560402aca871bd330ac9cb9532
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Wed Feb 8 19:59:52 2012 -0500
cpychecker: fix various format codes for Py_BuildValue
The format code handling for Py_BuildValue was missing support for the
following codes:
'u' and 'u#'
'f' and 'd'
'D'
'c'
In addition, the handling for 's#' and 'z#' had a bug in which it erroneously
expected an int* or Py_ssize_t*, rather than just a int or Py_ssize_t.
This commit fixes these issues, and (I hope) gives full coverage of all valid
format codes for Py_BuildValue in Python 2.
libcpychecker/Py_BuildValue.py | 37 +++++++++++++++++++-
.../Py_BuildValue/code_D/correct/input.c | 36 +++++++++++++++++++
.../Py_BuildValue/code_D/correct/script.py | 19 ++++++++++
.../Py_BuildValue/code_D/incorrect/input.c | 37 ++++++++++++++++++++
.../Py_BuildValue/code_D/incorrect/metadata.ini | 3 ++
.../Py_BuildValue/code_D/incorrect/script.py | 19 ++++++++++
.../Py_BuildValue/code_D/incorrect/stderr.txt | 7 ++++
.../Py_BuildValue/code_c/correct/input.c | 36 +++++++++++++++++++
.../Py_BuildValue/code_c/correct/script.py | 19 ++++++++++
.../Py_BuildValue/code_d/correct/input.c | 36 +++++++++++++++++++
.../Py_BuildValue/code_d/correct/script.py | 19 ++++++++++
.../Py_BuildValue/code_f/correct/input.c | 36 +++++++++++++++++++
.../Py_BuildValue/code_f/correct/script.py | 19 ++++++++++
.../Py_BuildValue/code_s_hash/correct/input.c | 36 +++++++++++++++++++
.../Py_BuildValue/code_s_hash/correct/script.py | 19 ++++++++++
.../Py_BuildValue/code_u/correct/input.c | 36 +++++++++++++++++++
.../Py_BuildValue/code_u/correct/script.py | 19 ++++++++++
.../Py_BuildValue/code_u_hash/correct/input.c | 36 +++++++++++++++++++
.../Py_BuildValue/code_u_hash/correct/script.py | 19 ++++++++++
19 files changed, 487 insertions(+), 1 deletions(-)
---
diff --git a/libcpychecker/Py_BuildValue.py b/libcpychecker/Py_BuildValue.py
index 8d5289f..41d0201 100644
--- a/libcpychecker/Py_BuildValue.py
+++ b/libcpychecker/Py_BuildValue.py
@@ -63,6 +63,28 @@ def _type_of_simple_arg(arg):
'k': gcc.Type.unsigned_long,
# 'L' covered below
# 'K' covered below
+ # 'u': covered in from_string() below
+
+ 'f': gcc.Type.double,
+ # (although documented as "[float]", 'f' accepts a "va_double" in
+ # modsupport.c)
+
+ 'd': gcc.Type.double,
+ # 'D' covered below
+
+ 'c': gcc.Type.int,
+ # (although documented as "[char]", 'c' accepts an "int" in
+ # modsupport.c)
+
+ # 's': covered in from_string() below
+ # 'z': covered in from_string() below
+ # 'N': covered in from_string() below
+ # 'S': covered in from_string() below
+ # 'O': covered in from_string() below
+ # ':': covered in from_string() below
+ # ',': covered in from_string() below
+ # ' ': covered in from_string() below
+ # '\t': covered in from_string() below
}
if arg in simple:
# FIXME: ideally this shouldn't need calling; it should just be an
@@ -75,6 +97,8 @@ def _type_of_simple_arg(arg):
return get_PY_LONG_LONG()
elif arg == 'K':
return get_PY_LONG_LONG().unsigned_equivalent
+ elif arg == 'D':
+ return get_Py_complex().pointer
class AnyPyObjectPtr(AwkwardType):
"""
@@ -215,13 +239,24 @@ class PyBuildValueFmt(ParsedFormatString):
if next == '#':
result.add_argument(c + '#',
[get_char_ptr(),
- get_hash_size_type(with_size_t).pointer])
+ get_hash_size_type(with_size_t)])
i += 1
else:
result.add_argument(c,
[get_char_ptr()])
continue
+ if c == 'u':
+ if next == '#':
+ result.add_argument(c + '#',
+ [Py_UNICODE().pointer,
+ get_hash_size_type(with_size_t)])
+ i += 1
+ else:
+ result.add_argument(c,
+ [Py_UNICODE().pointer])
+ continue
+
if c in 'NSO':
if next == '&':
result.add_complex_argument()
diff --git a/tests/cpychecker/Py_BuildValue/code_D/correct/input.c b/tests/cpychecker/Py_BuildValue/code_D/correct/input.c
new file mode 100644
index 0000000..6ae90f3
--- /dev/null
+++ b/tests/cpychecker/Py_BuildValue/code_D/correct/input.c
@@ -0,0 +1,36 @@
+/*
+ Copyright 2012 David Malcolm <dmalcolm(a)redhat.com>
+ Copyright 2012 Red Hat, Inc.
+
+ This is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#include <Python.h>
+
+/* Verify handling of the "D" format code to Py_BuildValue: */
+
+PyObject *
+test(Py_complex *c)
+{
+ return Py_BuildValue("D", c);
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/Py_BuildValue/code_D/correct/script.py b/tests/cpychecker/Py_BuildValue/code_D/correct/script.py
new file mode 100644
index 0000000..1aa8b6d
--- /dev/null
+++ b/tests/cpychecker/Py_BuildValue/code_D/correct/script.py
@@ -0,0 +1,19 @@
+# Copyright 2012 David Malcolm <dmalcolm(a)redhat.com>
+# Copyright 2012 Red Hat, Inc.
+#
+# This is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <http://www.gnu.org/licenses/>.
+
+from libcpychecker import main
+main()
diff --git a/tests/cpychecker/Py_BuildValue/code_D/incorrect/input.c b/tests/cpychecker/Py_BuildValue/code_D/incorrect/input.c
new file mode 100644
index 0000000..ed9cacc
--- /dev/null
+++ b/tests/cpychecker/Py_BuildValue/code_D/incorrect/input.c
@@ -0,0 +1,37 @@
+/*
+ Copyright 2012 David Malcolm <dmalcolm(a)redhat.com>
+ Copyright 2012 Red Hat, Inc.
+
+ This is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#include <Python.h>
+
+/* Verify detection of incorrect "D" format code to Py_BuildValue: */
+
+PyObject *
+test(double d)
+{
+ /* BUG: expects a (Py_complex*): */
+ return Py_BuildValue("D", d);
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/Py_BuildValue/code_D/incorrect/metadata.ini b/tests/cpychecker/Py_BuildValue/code_D/incorrect/metadata.ini
new file mode 100644
index 0000000..0d5711c
--- /dev/null
+++ b/tests/cpychecker/Py_BuildValue/code_D/incorrect/metadata.ini
@@ -0,0 +1,3 @@
+[ExpectedBehavior]
+# We expect only compilation *warnings*, so we expect a 0 exit code
+exitcode = 0
diff --git a/tests/cpychecker/Py_BuildValue/code_D/incorrect/script.py b/tests/cpychecker/Py_BuildValue/code_D/incorrect/script.py
new file mode 100644
index 0000000..1aa8b6d
--- /dev/null
+++ b/tests/cpychecker/Py_BuildValue/code_D/incorrect/script.py
@@ -0,0 +1,19 @@
+# Copyright 2012 David Malcolm <dmalcolm(a)redhat.com>
+# Copyright 2012 Red Hat, Inc.
+#
+# This is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <http://www.gnu.org/licenses/>.
+
+from libcpychecker import main
+main()
diff --git a/tests/cpychecker/Py_BuildValue/code_D/incorrect/stderr.txt b/tests/cpychecker/Py_BuildValue/code_D/incorrect/stderr.txt
new file mode 100644
index 0000000..fc91961
--- /dev/null
+++ b/tests/cpychecker/Py_BuildValue/code_D/incorrect/stderr.txt
@@ -0,0 +1,7 @@
+tests/cpychecker/Py_BuildValue/code_D/incorrect/input.c: In function 'test':
+tests/cpychecker/Py_BuildValue/code_D/incorrect/input.c:25:nn: warning: Mismatching type in call to Py_BuildValue with format code "D" [enabled by default]
+ argument 2 ("d") had type
+ "double"
+ but was expecting
+ "struct Py_complex *"
+ for format code "D"
diff --git a/tests/cpychecker/Py_BuildValue/code_c/correct/input.c b/tests/cpychecker/Py_BuildValue/code_c/correct/input.c
new file mode 100644
index 0000000..6748231
--- /dev/null
+++ b/tests/cpychecker/Py_BuildValue/code_c/correct/input.c
@@ -0,0 +1,36 @@
+/*
+ Copyright 2012 David Malcolm <dmalcolm(a)redhat.com>
+ Copyright 2012 Red Hat, Inc.
+
+ This is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#include <Python.h>
+
+/* Verify handling of the "c" format code to Py_BuildValue: */
+
+PyObject *
+test(char ch)
+{
+ return Py_BuildValue("c", ch);
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/Py_BuildValue/code_c/correct/script.py b/tests/cpychecker/Py_BuildValue/code_c/correct/script.py
new file mode 100644
index 0000000..1aa8b6d
--- /dev/null
+++ b/tests/cpychecker/Py_BuildValue/code_c/correct/script.py
@@ -0,0 +1,19 @@
+# Copyright 2012 David Malcolm <dmalcolm(a)redhat.com>
+# Copyright 2012 Red Hat, Inc.
+#
+# This is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <http://www.gnu.org/licenses/>.
+
+from libcpychecker import main
+main()
diff --git a/tests/cpychecker/Py_BuildValue/code_d/correct/input.c b/tests/cpychecker/Py_BuildValue/code_d/correct/input.c
new file mode 100644
index 0000000..817a64c
--- /dev/null
+++ b/tests/cpychecker/Py_BuildValue/code_d/correct/input.c
@@ -0,0 +1,36 @@
+/*
+ Copyright 2012 David Malcolm <dmalcolm(a)redhat.com>
+ Copyright 2012 Red Hat, Inc.
+
+ This is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#include <Python.h>
+
+/* Verify handling of the "d" format code to Py_BuildValue: */
+
+PyObject *
+test(double x, double y, double z)
+{
+ return Py_BuildValue("ddd", x, y, z);
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/Py_BuildValue/code_d/correct/script.py b/tests/cpychecker/Py_BuildValue/code_d/correct/script.py
new file mode 100644
index 0000000..1aa8b6d
--- /dev/null
+++ b/tests/cpychecker/Py_BuildValue/code_d/correct/script.py
@@ -0,0 +1,19 @@
+# Copyright 2012 David Malcolm <dmalcolm(a)redhat.com>
+# Copyright 2012 Red Hat, Inc.
+#
+# This is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <http://www.gnu.org/licenses/>.
+
+from libcpychecker import main
+main()
diff --git a/tests/cpychecker/Py_BuildValue/code_f/correct/input.c b/tests/cpychecker/Py_BuildValue/code_f/correct/input.c
new file mode 100644
index 0000000..7a692c2
--- /dev/null
+++ b/tests/cpychecker/Py_BuildValue/code_f/correct/input.c
@@ -0,0 +1,36 @@
+/*
+ Copyright 2012 David Malcolm <dmalcolm(a)redhat.com>
+ Copyright 2012 Red Hat, Inc.
+
+ This is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#include <Python.h>
+
+/* Verify handling of the "f" format code to Py_BuildValue: */
+
+PyObject *
+test(float x, float y, float z)
+{
+ return Py_BuildValue("fff", x, y, z);
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/Py_BuildValue/code_f/correct/script.py b/tests/cpychecker/Py_BuildValue/code_f/correct/script.py
new file mode 100644
index 0000000..1aa8b6d
--- /dev/null
+++ b/tests/cpychecker/Py_BuildValue/code_f/correct/script.py
@@ -0,0 +1,19 @@
+# Copyright 2012 David Malcolm <dmalcolm(a)redhat.com>
+# Copyright 2012 Red Hat, Inc.
+#
+# This is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <http://www.gnu.org/licenses/>.
+
+from libcpychecker import main
+main()
diff --git a/tests/cpychecker/Py_BuildValue/code_s_hash/correct/input.c b/tests/cpychecker/Py_BuildValue/code_s_hash/correct/input.c
new file mode 100644
index 0000000..68e15d8
--- /dev/null
+++ b/tests/cpychecker/Py_BuildValue/code_s_hash/correct/input.c
@@ -0,0 +1,36 @@
+/*
+ Copyright 2012 David Malcolm <dmalcolm(a)redhat.com>
+ Copyright 2012 Red Hat, Inc.
+
+ This is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#include <Python.h>
+
+/* Verify handling of the "s#" format code to Py_BuildValue: */
+
+PyObject *
+test(char *str, int len)
+{
+ return Py_BuildValue("s#", str, len);
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/Py_BuildValue/code_s_hash/correct/script.py b/tests/cpychecker/Py_BuildValue/code_s_hash/correct/script.py
new file mode 100644
index 0000000..1aa8b6d
--- /dev/null
+++ b/tests/cpychecker/Py_BuildValue/code_s_hash/correct/script.py
@@ -0,0 +1,19 @@
+# Copyright 2012 David Malcolm <dmalcolm(a)redhat.com>
+# Copyright 2012 Red Hat, Inc.
+#
+# This is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <http://www.gnu.org/licenses/>.
+
+from libcpychecker import main
+main()
diff --git a/tests/cpychecker/Py_BuildValue/code_u/correct/input.c b/tests/cpychecker/Py_BuildValue/code_u/correct/input.c
new file mode 100644
index 0000000..c240e07
--- /dev/null
+++ b/tests/cpychecker/Py_BuildValue/code_u/correct/input.c
@@ -0,0 +1,36 @@
+/*
+ Copyright 2012 David Malcolm <dmalcolm(a)redhat.com>
+ Copyright 2012 Red Hat, Inc.
+
+ This is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#include <Python.h>
+
+/* Verify handling of the "u" format code to Py_BuildValue: */
+
+PyObject *
+test(Py_UNICODE *u)
+{
+ return Py_BuildValue("u", u);
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/Py_BuildValue/code_u/correct/script.py b/tests/cpychecker/Py_BuildValue/code_u/correct/script.py
new file mode 100644
index 0000000..1aa8b6d
--- /dev/null
+++ b/tests/cpychecker/Py_BuildValue/code_u/correct/script.py
@@ -0,0 +1,19 @@
+# Copyright 2012 David Malcolm <dmalcolm(a)redhat.com>
+# Copyright 2012 Red Hat, Inc.
+#
+# This is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <http://www.gnu.org/licenses/>.
+
+from libcpychecker import main
+main()
diff --git a/tests/cpychecker/Py_BuildValue/code_u_hash/correct/input.c b/tests/cpychecker/Py_BuildValue/code_u_hash/correct/input.c
new file mode 100644
index 0000000..489765c
--- /dev/null
+++ b/tests/cpychecker/Py_BuildValue/code_u_hash/correct/input.c
@@ -0,0 +1,36 @@
+/*
+ Copyright 2012 David Malcolm <dmalcolm(a)redhat.com>
+ Copyright 2012 Red Hat, Inc.
+
+ This is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#include <Python.h>
+
+/* Verify handling of the "u#" format code to Py_BuildValue: */
+
+PyObject *
+test(Py_UNICODE *u, int len)
+{
+ return Py_BuildValue("u#", u, len);
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/Py_BuildValue/code_u_hash/correct/script.py b/tests/cpychecker/Py_BuildValue/code_u_hash/correct/script.py
new file mode 100644
index 0000000..1aa8b6d
--- /dev/null
+++ b/tests/cpychecker/Py_BuildValue/code_u_hash/correct/script.py
@@ -0,0 +1,19 @@
+# Copyright 2012 David Malcolm <dmalcolm(a)redhat.com>
+# Copyright 2012 Red Hat, Inc.
+#
+# This is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <http://www.gnu.org/licenses/>.
+
+from libcpychecker import main
+main()
12 years, 3 months
[gcc-python-plugin] mass-rebuild.py: patch the latest libcpychecker code into the chroot
by David Hugh Malcolm
commit b2d20c44d5717d8d50e593485ecbec3f477c59ef
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Wed Feb 8 18:51:54 2012 -0500
mass-rebuild.py: patch the latest libcpychecker code into the chroot
misc/fedora/mass-rebuild.py | 12 ++++++++++++
1 files changed, 12 insertions(+), 0 deletions(-)
---
diff --git a/misc/fedora/mass-rebuild.py b/misc/fedora/mass-rebuild.py
index 326f79e..5ed9206 100644
--- a/misc/fedora/mass-rebuild.py
+++ b/misc/fedora/mass-rebuild.py
@@ -91,7 +91,19 @@ def local_rebuild_of_srpm_in_mock(srpmpath, mockcfg):
if 1:
run_mock(['--init'])
run_mock(['--installdeps', srpmpath])
+
+ # Install the pre-built plugin:
run_mock(['install', PLUGIN_PATH]) # this doesn't work when cleaned: can't open state.log
+
+ # Copy up latest version of the libcpychecker code from this working copy
+ # overriding the copy from the pre-built plugin:
+ if 1:
+ for module in glob.glob('../../libcpychecker/*.py'):
+ HACKED_PATH='/usr/lib/gcc/x86_64-redhat-linux/4.6.2/plugin/python2/libcpychecker'
+ # FIXME: ^^ this will need changing
+ run_mock(['--copyin', module, HACKED_PATH])
+
+ # Locate existing __global_cflags so that we can prepend our flags to it:
out, err = run_mock(['--chroot', 'rpm --eval "%{__global_cflags}"'],
captureOut=True)
global_cflags = out.strip()
12 years, 3 months
[gcc-python-plugin] mass-rebuild.py: scrape out *-refcount-errors.html from the chroot
by David Hugh Malcolm
commit afb3fe79a23895c5bf5146dedaa04c73a3ba2069
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Wed Feb 8 18:50:47 2012 -0500
mass-rebuild.py: scrape out *-refcount-errors.html from the chroot
In the mass rebuild script, scrape out *-refcount-errors.html from the
chroot into a results directory.
Doing so requires that we disable ccache.
misc/fedora/mass-rebuild.py | 25 ++++++++++++++++++++++++-
1 files changed, 24 insertions(+), 1 deletions(-)
---
diff --git a/misc/fedora/mass-rebuild.py b/misc/fedora/mass-rebuild.py
index 7f76d97..326f79e 100644
--- a/misc/fedora/mass-rebuild.py
+++ b/misc/fedora/mass-rebuild.py
@@ -68,7 +68,7 @@ def local_rebuild_of_srpm_in_mock(srpmpath, mockcfg):
code in RPM form; gathering the results to a subdir within "LOGS"
"""
def run_mock(commands, captureOut=False, captureErr=False):
- cmds = ['mock', '-r', mockcfg] + commands
+ cmds = ['mock', '-r', mockcfg, '--disable-plugin=ccache'] + commands
print('--------------------------------------------------------------')
print(' '.join(cmds))
print('--------------------------------------------------------------')
@@ -117,6 +117,29 @@ def local_rebuild_of_srpm_in_mock(srpmpath, mockcfg):
shutil.copy('/var/lib/mock/%s/result/build.log' % mockcfg,
resultdir)
+ # Scrape out *refcount-errors.html:
+ BUILD_PREFIX='/builddir/build/BUILD'
+ out, err = run_mock(['chroot',
+ 'find %s -name *-refcount-errors.html' % BUILD_PREFIX],
+ captureOut=True)
+ for line in out.splitlines():
+ if line.endswith('-refcount-errors.html'):
+ # Convert from e.g.
+ # '/builddir/build/BUILD/gst-python-0.10.19/gst/.libs/gstmodule.c.init_gst-refcount-errors.html'
+ # to:
+ # 'gst-python-0.10.19/gst/.libs/gstmodule.c.init_gst-refcount-errors.html"
+ dstPath = line[len(BUILD_PREFIX)+1:]
+
+ # Place it within resultdir:
+ dstPath = os.path.join(resultdir, dstPath)
+
+ # Lazily construct directory hierarchy:
+ dirPath = os.path.dirname(dstPath)
+ if not os.path.exists(dirPath):
+ os.makedirs(dirPath)
+ # Copy the file from the chroot to our result location:
+ run_mock(['--copyout', line, dstPath])
+
PLUGIN_PATH='gcc-python2-plugin-0.9-1.fc16.x86_64.rpm'
MOCK_CONFIG='fedora-16-x86_64'
12 years, 3 months
[gcc-python-plugin] cpychecker: fix an off-by-one in the handling of conditionals
by David Hugh Malcolm
commit fdb8e64195ab463230ac18f4f635bc33146575fb
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Tue Feb 7 17:27:26 2012 -0500
cpychecker: fix an off-by-one in the handling of conditionals
When splitting a WithinRange against a ConcreteValue due to a conditional,
ensure that all of the boundaries are within the existing WithinRange,
and extend the final boundary up to the final range, rather than assume that
the final range covers [boundary[n-1]..boundary[n]] (which isn't true when
the split is happening close to the max value of the range).
Fixes a traceback seen with a pair of loops when compiling
gstreamer-python-0.10.19 under the checker.
Also, make it easier to debug comparisons by by indenting the optional debug
text that appears when debug_comparisons is enabled.
libcpychecker/absinterp.py | 34 +++++++-----
.../ConcreteValue-lt-two-value-range/input.c | 53 ++++++++++++++++++++
.../ConcreteValue-lt-two-value-range/script.py | 22 ++++++++
.../ConcreteValue-lt-two-value-range/stdout.txt | 53 ++++++++++++++++++++
tests/cpychecker/absinterp/two-loops/input.c | 44 ++++++++++++++++
tests/cpychecker/absinterp/two-loops/script.py | 22 ++++++++
tests/cpychecker/absinterp/two-loops/stdout.txt | 20 +++++++
.../PyList_Append/incorrect-loop/stderr.txt | 50 +++++++++---------
.../PyList_Append/incorrect-loop/stdout.txt | 2 +-
tests/cpychecker/refcounts/loop_n_times/stdout.txt | 4 +-
.../loops/complex-loop-conditional-1/stderr.txt | 2 +-
.../loops/complex-loop-conditional-1/stdout.txt | 2 +-
12 files changed, 264 insertions(+), 44 deletions(-)
---
diff --git a/libcpychecker/absinterp.py b/libcpychecker/absinterp.py
index d9fc663..21af225 100644
--- a/libcpychecker/absinterp.py
+++ b/libcpychecker/absinterp.py
@@ -97,6 +97,8 @@ if debug_comparisons:
print('%sreturned: %s' % (' ' * debug_indent, r))
return r
return impl_fn
+ def debug_comparison(msg):
+ print('%s%s' % (' ' * debug_indent, msg))
else:
# empty decorator
def dump_comparison(f):
@@ -536,17 +538,21 @@ class ConcreteValue(AbstractValue):
self.value + 1,
rhs.minvalue,
rhs.maxvalue])))
+ # Filter them to be within the existing range:
+ raw_boundaries = [v
+ for v in raw_boundaries
+ if rhs.contains(v)]
if debug_comparisons:
- print([value_to_str(v) for v in raw_boundaries])
+ debug_comparison([value_to_str(v) for v in raw_boundaries])
# Calculate a minimal list of RangeOfComparison instances
# Within each one, the comparison against the ConcreteValue has
# a consistent result:
ranges = []
- num_boundary_ranges = len(raw_boundaries)-1
+ num_boundary_ranges = len(raw_boundaries)
if debug_comparisons:
- print('num_boundary_ranges: %r' % num_boundary_ranges)
- for i in range(len(raw_boundaries)-1):
+ debug_comparison('num_boundary_ranges: %r' % num_boundary_ranges)
+ for i in range(num_boundary_ranges):
minvalue = raw_boundaries[i]
if minvalue < rhs.gcctype.min_value.constant:
minvalue = rhs.gcctype.min_value.constant
@@ -556,16 +562,16 @@ class ConcreteValue(AbstractValue):
maxvalue = raw_boundaries[i + 1] - 1
else:
# Final range: use full range:
- maxvalue = raw_boundaries[i + 1]
+ maxvalue = rhs.maxvalue
if maxvalue > rhs.gcctype.max_value.constant:
maxvalue = rhs.gcctype.max_value.constant
if debug_comparisons:
- print('%i [%s..%s]'
- % (i,
- value_to_str(minvalue),
- value_to_str(maxvalue)))
+ debug_comparison('%i [%s..%s]'
+ % (i,
+ value_to_str(minvalue),
+ value_to_str(maxvalue)))
check_isinstance(minvalue, numeric_types)
check_isinstance(maxvalue, numeric_types)
@@ -579,11 +585,11 @@ class ConcreteValue(AbstractValue):
# against the concrete value:
assert self_vs_min == self_vs_max
if debug_comparisons:
- print(' [%s..%s] %s %s ?: %s'
- % (value_to_str(minvalue),
- value_to_str(maxvalue),
- opname, self.value,
- self_vs_min))
+ debug_comparison(' [%s..%s] %s %s ?: %s'
+ % (value_to_str(minvalue),
+ value_to_str(maxvalue),
+ opname, self.value,
+ self_vs_min))
if ranges and ranges[-1].result == self_vs_min:
# These ranges are adjacent and have the same result;
diff --git a/tests/cpychecker/absinterp/comparisons/boundaries/ConcreteValue-lt-two-value-range/input.c b/tests/cpychecker/absinterp/comparisons/boundaries/ConcreteValue-lt-two-value-range/input.c
new file mode 100644
index 0000000..e35793e
--- /dev/null
+++ b/tests/cpychecker/absinterp/comparisons/boundaries/ConcreteValue-lt-two-value-range/input.c
@@ -0,0 +1,53 @@
+/*
+ Copyright 2012 David Malcolm <dmalcolm(a)redhat.com>
+ Copyright 2012 Red Hat, Inc.
+
+ This is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#include <Python.h>
+
+int
+test(int j)
+{
+ int i = 0;
+ if (j < 0) {
+ return 0;
+ }
+ if (j >= 2) {
+ return 1;
+ }
+
+ /*
+ OK, j should now be WithinRange(0, 1)
+
+ Test of:
+ ConcreteValue(0) < WithinRange(0, 1)
+ Either branch is possible:
+ */
+ if (i < j) {
+ return 2; /* j should provably be 1 */
+ } else {
+ return 3; /* j should provably be 0 */
+ }
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/absinterp/comparisons/boundaries/ConcreteValue-lt-two-value-range/script.py b/tests/cpychecker/absinterp/comparisons/boundaries/ConcreteValue-lt-two-value-range/script.py
new file mode 100644
index 0000000..c1bff09
--- /dev/null
+++ b/tests/cpychecker/absinterp/comparisons/boundaries/ConcreteValue-lt-two-value-range/script.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Copyright 2012 David Malcolm <dmalcolm(a)redhat.com>
+# Copyright 2012 Red Hat, Inc.
+#
+# This is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <http://www.gnu.org/licenses/>.
+
+from libcpychecker import main
+main(verify_refcounting=True,
+ dump_traces=True,
+ show_traces=False)
diff --git a/tests/cpychecker/absinterp/comparisons/boundaries/ConcreteValue-lt-two-value-range/stdout.txt b/tests/cpychecker/absinterp/comparisons/boundaries/ConcreteValue-lt-two-value-range/stdout.txt
new file mode 100644
index 0000000..d8c8aaa
--- /dev/null
+++ b/tests/cpychecker/absinterp/comparisons/boundaries/ConcreteValue-lt-two-value-range/stdout.txt
@@ -0,0 +1,53 @@
+Trace 0:
+ Transitions:
+ 'when considering range: -0x80000000 <= value <= -1'
+ 'taking True path'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='int', loc=gcc.Location(file='tests/cpychecker/absinterp/comparisons/boundaries/ConcreteValue-lt-two-value-range/input.c', line=27), value=0)
+ str(): (int)0 from tests/cpychecker/absinterp/comparisons/boundaries/ConcreteValue-lt-two-value-range/input.c:27
+ Exception:
+ (struct PyObject *)0 from tests/cpychecker/absinterp/comparisons/boundaries/ConcreteValue-lt-two-value-range/input.c:24
+
+Trace 1:
+ Transitions:
+ 'when considering range: 0 <= value <= 0x7fffffff'
+ 'taking False path'
+ 'when considering range: 0 <= value <= 1'
+ 'taking False path'
+ 'when considering value == (int)0 from tests/cpychecker/absinterp/comparisons/boundaries/ConcreteValue-lt-two-value-range/input.c:23'
+ 'taking False path'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='int', loc=gcc.Location(file='tests/cpychecker/absinterp/comparisons/boundaries/ConcreteValue-lt-two-value-range/input.c', line=43), value=3)
+ str(): (int)3 from tests/cpychecker/absinterp/comparisons/boundaries/ConcreteValue-lt-two-value-range/input.c:43
+ Exception:
+ (struct PyObject *)0 from tests/cpychecker/absinterp/comparisons/boundaries/ConcreteValue-lt-two-value-range/input.c:24
+
+Trace 2:
+ Transitions:
+ 'when considering range: 0 <= value <= 0x7fffffff'
+ 'taking False path'
+ 'when considering range: 0 <= value <= 1'
+ 'taking False path'
+ 'when considering value == (int)1 from tests/cpychecker/absinterp/comparisons/boundaries/ConcreteValue-lt-two-value-range/input.c:23'
+ 'taking True path'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='int', loc=gcc.Location(file='tests/cpychecker/absinterp/comparisons/boundaries/ConcreteValue-lt-two-value-range/input.c', line=41), value=2)
+ str(): (int)2 from tests/cpychecker/absinterp/comparisons/boundaries/ConcreteValue-lt-two-value-range/input.c:41
+ Exception:
+ (struct PyObject *)0 from tests/cpychecker/absinterp/comparisons/boundaries/ConcreteValue-lt-two-value-range/input.c:24
+
+Trace 3:
+ Transitions:
+ 'when considering range: 0 <= value <= 0x7fffffff'
+ 'taking False path'
+ 'when considering range: 2 <= value <= 0x7fffffff'
+ 'taking True path'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='int', loc=gcc.Location(file='tests/cpychecker/absinterp/comparisons/boundaries/ConcreteValue-lt-two-value-range/input.c', line=30), value=1)
+ str(): (int)1 from tests/cpychecker/absinterp/comparisons/boundaries/ConcreteValue-lt-two-value-range/input.c:30
+ Exception:
+ (struct PyObject *)0 from tests/cpychecker/absinterp/comparisons/boundaries/ConcreteValue-lt-two-value-range/input.c:24
diff --git a/tests/cpychecker/absinterp/two-loops/input.c b/tests/cpychecker/absinterp/two-loops/input.c
new file mode 100644
index 0000000..ad23a10
--- /dev/null
+++ b/tests/cpychecker/absinterp/two-loops/input.c
@@ -0,0 +1,44 @@
+/*
+ Copyright 2012 David Malcolm <dmalcolm(a)redhat.com>
+ Copyright 2012 Red Hat, Inc.
+
+ This is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#include <Python.h>
+
+/*
+ Reproducer for a traceback seen in a function with two loops
+*/
+
+void
+test(int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ }
+
+ for (i = 0; i < len; i++) {
+ }
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/absinterp/two-loops/script.py b/tests/cpychecker/absinterp/two-loops/script.py
new file mode 100644
index 0000000..fdd5ba3
--- /dev/null
+++ b/tests/cpychecker/absinterp/two-loops/script.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Copyright 2011 David Malcolm <dmalcolm(a)redhat.com>
+# Copyright 2011 Red Hat, Inc.
+#
+# This is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <http://www.gnu.org/licenses/>.
+
+from libcpychecker import main
+main(verify_refcounting=True,
+ dump_traces=True,
+ show_traces=False)
diff --git a/tests/cpychecker/absinterp/two-loops/stdout.txt b/tests/cpychecker/absinterp/two-loops/stdout.txt
new file mode 100644
index 0000000..0a8574b
--- /dev/null
+++ b/tests/cpychecker/absinterp/two-loops/stdout.txt
@@ -0,0 +1,20 @@
+Trace 0:
+ Transitions:
+ 'when considering range: -0x80000000 <= value <= 0'
+ 'taking False path'
+ 'taking False path'
+ 'returning'
+ Exception:
+ (struct PyObject *)0 from tests/cpychecker/absinterp/two-loops/input.c:28
+
+Trace 1:
+ Transitions:
+ 'when considering range: 1 <= value <= 0x7fffffff'
+ 'taking True path'
+ 'when considering value == (int)1 from tests/cpychecker/absinterp/two-loops/input.c:27'
+ 'taking False path'
+ 'taking True path'
+ 'taking False path'
+ 'returning'
+ Exception:
+ (struct PyObject *)0 from tests/cpychecker/absinterp/two-loops/input.c:28
diff --git a/tests/cpychecker/refcounts/PyList_Append/incorrect-loop/stderr.txt b/tests/cpychecker/refcounts/PyList_Append/incorrect-loop/stderr.txt
index bd676db..2d19aba 100644
--- a/tests/cpychecker/refcounts/PyList_Append/incorrect-loop/stderr.txt
+++ b/tests/cpychecker/refcounts/PyList_Append/incorrect-loop/stderr.txt
@@ -1,26 +1,26 @@
tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c: In function 'test':
-tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:60:1: warning: ob_refcnt of '*item' is 1 too high [enabled by default]
-tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:60:1: note: was expecting final ob_refcnt to be N + 1 (for some unknown N)
-tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:60:1: note: due to object being referenced by: PyListObject.ob_item[0]
-tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:60:1: note: but final ob_refcnt is N + 2
-tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:41:14: note: new ref from (unknown) item_ctor allocated at: item = item_ctor();
-tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:34:10: note: when PyList_New() succeeds at: list = PyList_New(0);
-tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:35:8: note: taking False path at: if (!list) {
-tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:38:12: note: reaching: for (i = 0; i < n; i++) {
-tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:38:5: note: when considering range: 1 <= value <= 0x7fffffff at: for (i = 0; i < n; i++) {
-tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:38:5: note: taking True path at: for (i = 0; i < n; i++) {
-tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:41:14: note: reaching: item = item_ctor();
-tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:41:14: note: when item_ctor() succeeds at: item = item_ctor();
-tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:41:14: note: ob_refcnt is now refs: 1 + N where N >= 0
-tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:42:12: note: taking False path at: if (!item) {
-tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:47:26: note: reaching: if (PyList_Append(list, item)) {
-tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:47:26: note: when PyList_Append() succeeds at: if (PyList_Append(list, item)) {
-tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:47:26: note: ob_refcnt is now refs: 2 + N where N >= 0
-tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:47:26: note: '*item' is now referenced by 1 non-stack value(s): PyListObject.ob_item[0]
-tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:47:12: note: taking False path at: if (PyList_Append(list, item)) {
-tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:38:25: note: reaching: for (i = 0; i < n; i++) {
-tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:38:5: note: when considering range: 0 <= value <= 1 at: for (i = 0; i < n; i++) {
-tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:38:5: note: taking False path at: for (i = 0; i < n; i++) {
-tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:59:5: note: reaching: return list;
-tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:60:1: note: returning
-tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:30:1: note: graphical error report for function 'test' written out to 'tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c.test-refcount-errors.html'
+tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:60:nn: warning: ob_refcnt of '*item' is 1 too high [enabled by default]
+tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:60:nn: note: was expecting final ob_refcnt to be N + 1 (for some unknown N)
+tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:60:nn: note: due to object being referenced by: PyListObject.ob_item[0]
+tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:60:nn: note: but final ob_refcnt is N + 2
+tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:41:nn: note: new ref from (unknown) item_ctor allocated at: item = item_ctor();
+tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:34:nn: note: when PyList_New() succeeds at: list = PyList_New(0);
+tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:35:nn: note: taking False path at: if (!list) {
+tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:38:nn: note: reaching: for (i = 0; i < n; i++) {
+tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:38:nn: note: when considering range: 1 <= value <= 0x7fffffff at: for (i = 0; i < n; i++) {
+tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:38:nn: note: taking True path at: for (i = 0; i < n; i++) {
+tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:41:nn: note: reaching: item = item_ctor();
+tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:41:nn: note: when item_ctor() succeeds at: item = item_ctor();
+tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:41:nn: note: ob_refcnt is now refs: 1 + N where N >= 0
+tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:42:nn: note: taking False path at: if (!item) {
+tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:47:nn: note: reaching: if (PyList_Append(list, item)) {
+tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:47:nn: note: when PyList_Append() succeeds at: if (PyList_Append(list, item)) {
+tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:47:nn: note: ob_refcnt is now refs: 2 + N where N >= 0
+tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:47:nn: note: '*item' is now referenced by 1 non-stack value(s): PyListObject.ob_item[0]
+tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:47:nn: note: taking False path at: if (PyList_Append(list, item)) {
+tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:38:nn: note: reaching: for (i = 0; i < n; i++) {
+tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:38:nn: note: when considering value == (int)1 from tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:29 at: for (i = 0; i < n; i++) {
+tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:38:nn: note: taking False path at: for (i = 0; i < n; i++) {
+tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:59:nn: note: reaching: return list;
+tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:60:nn: note: returning
+tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:30:nn: note: graphical error report for function 'test' written out to 'tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c.test-refcount-errors.html'
diff --git a/tests/cpychecker/refcounts/PyList_Append/incorrect-loop/stdout.txt b/tests/cpychecker/refcounts/PyList_Append/incorrect-loop/stdout.txt
index 3f6bf21..99d0991 100644
--- a/tests/cpychecker/refcounts/PyList_Append/incorrect-loop/stdout.txt
+++ b/tests/cpychecker/refcounts/PyList_Append/incorrect-loop/stdout.txt
@@ -23,7 +23,7 @@ Trace 1:
'taking False path'
'when PyList_Append() succeeds'
'taking False path'
- 'when considering range: 0 <= value <= 1'
+ 'when considering value == (int)1 from tests/cpychecker/refcounts/PyList_Append/incorrect-loop/input.c:29'
'taking False path'
'returning'
Return value:
diff --git a/tests/cpychecker/refcounts/loop_n_times/stdout.txt b/tests/cpychecker/refcounts/loop_n_times/stdout.txt
index cf83b24..27e8165 100644
--- a/tests/cpychecker/refcounts/loop_n_times/stdout.txt
+++ b/tests/cpychecker/refcounts/loop_n_times/stdout.txt
@@ -80,7 +80,7 @@ Trace 2:
'when considering range: 1 <= value <= 0x7fffffff'
'taking True path'
'PyList_SetItem() succeeds'
- 'when considering range: 0 <= value <= 1'
+ 'when considering value == (int)1 from tests/cpychecker/refcounts/loop_n_times/input.c:34'
'taking False path'
'when taking True path'
'returning'
@@ -118,7 +118,7 @@ Trace 3:
'when considering range: 1 <= value <= 0x7fffffff'
'taking True path'
'PyList_SetItem() succeeds'
- 'when considering range: 0 <= value <= 1'
+ 'when considering value == (int)1 from tests/cpychecker/refcounts/loop_n_times/input.c:34'
'taking False path'
'when taking False path'
'calling tp_dealloc on PyLongObject allocated at tests/cpychecker/refcounts/loop_n_times/input.c:42'
diff --git a/tests/cpychecker/refcounts/loops/complex-loop-conditional-1/stderr.txt b/tests/cpychecker/refcounts/loops/complex-loop-conditional-1/stderr.txt
index b2d449e..d9ea4d4 100644
--- a/tests/cpychecker/refcounts/loops/complex-loop-conditional-1/stderr.txt
+++ b/tests/cpychecker/refcounts/loops/complex-loop-conditional-1/stderr.txt
@@ -19,7 +19,7 @@ tests/cpychecker/refcounts/loops/complex-loop-conditional-1/input.c:43:nn: note:
tests/cpychecker/refcounts/loops/complex-loop-conditional-1/input.c:43:nn: note: '*item' is now referenced by 1 non-stack value(s): PyListObject.ob_item[0]
tests/cpychecker/refcounts/loops/complex-loop-conditional-1/input.c:43:nn: note: taking False path at: if (-1 == PyList_Append(result, item)) {
tests/cpychecker/refcounts/loops/complex-loop-conditional-1/input.c:38:nn: note: reaching: for (i = 0; i < unknown_unsigned_val; i++) {
-tests/cpychecker/refcounts/loops/complex-loop-conditional-1/input.c:38:nn: note: when considering range: 0 <= value <= 1 at: for (i = 0; i < unknown_unsigned_val; i++) {
+tests/cpychecker/refcounts/loops/complex-loop-conditional-1/input.c:38:nn: note: when considering value == (const unsigned int)1 from tests/cpychecker/refcounts/loops/complex-loop-conditional-1/input.c:22 at: for (i = 0; i < unknown_unsigned_val; i++) {
tests/cpychecker/refcounts/loops/complex-loop-conditional-1/input.c:38:nn: note: taking False path at: for (i = 0; i < unknown_unsigned_val; i++) {
tests/cpychecker/refcounts/loops/complex-loop-conditional-1/input.c:57:nn: note: reaching: return result;
tests/cpychecker/refcounts/loops/complex-loop-conditional-1/input.c:62:nn: note: returning
diff --git a/tests/cpychecker/refcounts/loops/complex-loop-conditional-1/stdout.txt b/tests/cpychecker/refcounts/loops/complex-loop-conditional-1/stdout.txt
index 81e444d..2d0a020 100644
--- a/tests/cpychecker/refcounts/loops/complex-loop-conditional-1/stdout.txt
+++ b/tests/cpychecker/refcounts/loops/complex-loop-conditional-1/stdout.txt
@@ -33,7 +33,7 @@ Trace 1:
'taking False path'
'when PyList_Append() succeeds'
'taking False path'
- 'when considering range: 0 <= value <= 1'
+ 'when considering value == (const unsigned int)1 from tests/cpychecker/refcounts/loops/complex-loop-conditional-1/input.c:22'
'taking False path'
'returning'
Return value:
12 years, 3 months
[gcc-python-plugin] cpychecker: cope with opaque structs when detecting PyObject subclasses
by David Hugh Malcolm
commit b71bb825fc3d8ebf578e46fb15ffddb0e3d7e416
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Tue Feb 7 16:23:09 2012 -0500
cpychecker: cope with opaque structs when detecting PyObject subclasses
Explicitly check for opaque structs en detecting PyObject subclasses; treat
such a struct as *not* being a PyObject subclass.
Fixes a traceback seen when compiling gstreamer-python-0.10.19 under the
checker
libcpychecker/refcounts.py | 5 +++
.../refcounts/subclass/opaque-struct/input.c | 39 ++++++++++++++++++++
.../refcounts/subclass/opaque-struct/script.py | 22 +++++++++++
.../refcounts/subclass/opaque-struct/stdout.txt | 5 +++
4 files changed, 71 insertions(+), 0 deletions(-)
---
diff --git a/libcpychecker/refcounts.py b/libcpychecker/refcounts.py
index 6fd8763..d42236a 100644
--- a/libcpychecker/refcounts.py
+++ b/libcpychecker/refcounts.py
@@ -67,6 +67,11 @@ def type_is_pyobjptr_subclass(t):
fields = t.dereference.fields
+ if len(fields) == 0:
+ # Opaque struct: there's nothing we can do.
+ # Assume it's *not* a PyObject subclass:
+ return False
+
# if first field is a PyObject subclass, then we're good:
if type_is_pyobjptr_subclass(fields[0].type.pointer):
return True
diff --git a/tests/cpychecker/refcounts/subclass/opaque-struct/input.c b/tests/cpychecker/refcounts/subclass/opaque-struct/input.c
new file mode 100644
index 0000000..a7fefca
--- /dev/null
+++ b/tests/cpychecker/refcounts/subclass/opaque-struct/input.c
@@ -0,0 +1,39 @@
+/*
+ Copyright 2012 David Malcolm <dmalcolm(a)redhat.com>
+ Copyright 2012 Red Hat, Inc.
+
+ This is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#include <Python.h>
+
+/*
+ Verify that the checker can cope with an opaque struct
+*/
+typedef struct _sometype SomeType;
+
+void
+test(SomeType *foo)
+{
+ /* empty */
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/refcounts/subclass/opaque-struct/script.py b/tests/cpychecker/refcounts/subclass/opaque-struct/script.py
new file mode 100644
index 0000000..fdd5ba3
--- /dev/null
+++ b/tests/cpychecker/refcounts/subclass/opaque-struct/script.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Copyright 2011 David Malcolm <dmalcolm(a)redhat.com>
+# Copyright 2011 Red Hat, Inc.
+#
+# This is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <http://www.gnu.org/licenses/>.
+
+from libcpychecker import main
+main(verify_refcounting=True,
+ dump_traces=True,
+ show_traces=False)
diff --git a/tests/cpychecker/refcounts/subclass/opaque-struct/stdout.txt b/tests/cpychecker/refcounts/subclass/opaque-struct/stdout.txt
new file mode 100644
index 0000000..18d3801
--- /dev/null
+++ b/tests/cpychecker/refcounts/subclass/opaque-struct/stdout.txt
@@ -0,0 +1,5 @@
+Trace 0:
+ Transitions:
+ 'returning'
+ Exception:
+ (struct PyObject *)0 from tests/cpychecker/refcounts/subclass/opaque-struct/input.c:29
12 years, 3 months
[gcc-python-plugin] cpychecker: implement PyObject_CallObject
by David Hugh Malcolm
commit 65d196b74ea7c2b5bda9c0c4b6fc31747b352a96
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Tue Feb 7 15:40:50 2012 -0500
cpychecker: implement PyObject_CallObject
libcpychecker/refcounts.py | 16 ++++++++
.../refcounts/PyObject_CallObject/correct/input.c | 38 ++++++++++++++++++
.../PyObject_CallObject/correct/script.py | 22 ++++++++++
.../PyObject_CallObject/correct/stdout.txt | 41 ++++++++++++++++++++
4 files changed, 117 insertions(+), 0 deletions(-)
---
diff --git a/libcpychecker/refcounts.py b/libcpychecker/refcounts.py
index d530811..6fd8763 100644
--- a/libcpychecker/refcounts.py
+++ b/libcpychecker/refcounts.py
@@ -2166,6 +2166,22 @@ class CPython(Facet):
return self.make_transitions_for_new_ref_or_fail(stmt, fnmeta)
+ def impl_PyObject_CallObject(self, stmt, v_o, v_args):
+ fnmeta = FnMeta(name='PyObject_CallObject',
+ docurl='http://docs.python.org/c-api/object.html#PyObject_CallObject',
+ defined_in='Objects/abstract.c',
+ prototype=('PyAPI_FUNC(PyObject *) PyObject_CallObject(PyObject *callable_object,\n'
+ ' PyObject *args);'))
+ # internally, is just:
+ # return PyEval_CallObjectWithKeywords(o, a, NULL);
+
+ # args can be NULL, but the callable obj can't be:
+ self.state.raise_any_null_ptr_func_arg(stmt, 0, v_o,
+ why=('%s() looks up func->ob_type (within PyObject_Call'
+ ' within PyEval_CallObjectWithKeywords)'
+ % fnmeta.name))
+ return self.make_transitions_for_new_ref_or_fail(stmt, fnmeta)
+
def impl_PyObject_GetAttrString(self, stmt, v_v, v_name):
fnmeta = FnMeta(name='PyObject_GetAttrString',
docurl='http://docs.python.org/c-api/object.html#PyObject_GetAttrString',
diff --git a/tests/cpychecker/refcounts/PyObject_CallObject/correct/input.c b/tests/cpychecker/refcounts/PyObject_CallObject/correct/input.c
new file mode 100644
index 0000000..8648c92
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyObject_CallObject/correct/input.c
@@ -0,0 +1,38 @@
+/*
+ Copyright 2012 David Malcolm <dmalcolm(a)redhat.com>
+ Copyright 2012 Red Hat, Inc.
+
+ This is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#include <Python.h>
+
+/*
+ Test of correct reference-handling in a call to PyObject_CallObject
+*/
+
+PyObject *
+test(PyObject *callable, PyObject *args)
+{
+ return PyObject_CallObject(callable, args);
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/refcounts/PyObject_CallObject/correct/script.py b/tests/cpychecker/refcounts/PyObject_CallObject/correct/script.py
new file mode 100644
index 0000000..fdd5ba3
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyObject_CallObject/correct/script.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Copyright 2011 David Malcolm <dmalcolm(a)redhat.com>
+# Copyright 2011 Red Hat, Inc.
+#
+# This is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <http://www.gnu.org/licenses/>.
+
+from libcpychecker import main
+main(verify_refcounting=True,
+ dump_traces=True,
+ show_traces=False)
diff --git a/tests/cpychecker/refcounts/PyObject_CallObject/correct/stdout.txt b/tests/cpychecker/refcounts/PyObject_CallObject/correct/stdout.txt
new file mode 100644
index 0000000..d2d6f8a
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyObject_CallObject/correct/stdout.txt
@@ -0,0 +1,41 @@
+Trace 0:
+ Transitions:
+ 'when PyObject_CallObject() succeeds'
+ 'returning'
+ Return value:
+ repr(): PointerToRegion(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallObject/correct/input.c', line=29), region=RegionOnHeap('new ref from call to PyObject_CallObject', gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallObject/correct/input.c', line=29)))
+ str(): (struct PyObject *)&RegionOnHeap('new ref from call to PyObject_CallObject', gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallObject/correct/input.c', line=29)) from tests/cpychecker/refcounts/PyObject_CallObject/correct/input.c:29
+ r->ob_refcnt: refs: 1 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallObject/correct/input.c', line=29), region=Region('PyTypeObject for new ref from call to PyObject_CallObject'))
+ Region("region-for-arg-gcc.ParmDecl('callable')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('callable')")
+ str(): Region("region-for-arg-gcc.ParmDecl('callable')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallObject/correct/input.c', line=27), region=Region("region-for-type-of-arg-gcc.ParmDecl('callable')"))
+ Region("region-for-arg-gcc.ParmDecl('args')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('args')")
+ str(): Region("region-for-arg-gcc.ParmDecl('args')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallObject/correct/input.c', line=27), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')"))
+ Exception:
+ (struct PyObject *)0 from tests/cpychecker/refcounts/PyObject_CallObject/correct/input.c:28
+
+Trace 1:
+ Transitions:
+ 'when PyObject_CallObject() fails'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallObject/correct/input.c', line=29), value=0)
+ str(): (struct PyObject *)0 from tests/cpychecker/refcounts/PyObject_CallObject/correct/input.c:29
+ Region("region-for-arg-gcc.ParmDecl('callable')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('callable')")
+ str(): Region("region-for-arg-gcc.ParmDecl('callable')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallObject/correct/input.c', line=27), region=Region("region-for-type-of-arg-gcc.ParmDecl('callable')"))
+ Region("region-for-arg-gcc.ParmDecl('args')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('args')")
+ str(): Region("region-for-arg-gcc.ParmDecl('args')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyObject_CallObject/correct/input.c', line=27), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')"))
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) from tests/cpychecker/refcounts/PyObject_CallObject/correct/input.c:29
12 years, 3 months
[gcc-python-plugin] cpychecker: implement PyCObject_FromVoidPtrAndDesc
by David Hugh Malcolm
commit 87c6dd4b28f7ccd96561ee1cbbc6399e92faaf2c
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Tue Feb 7 15:28:30 2012 -0500
cpychecker: implement PyCObject_FromVoidPtrAndDesc
libcpychecker/refcounts.py | 17 ++++
.../PyCObject_FromVoidPtrAndDesc/incorrect/input.c | 53 ++++++++++++
.../incorrect/metadata.ini | 3 +
.../incorrect/script.py | 22 +++++
.../incorrect/stderr.txt | 15 ++++
.../incorrect/stdout.txt | 89 ++++++++++++++++++++
6 files changed, 199 insertions(+), 0 deletions(-)
---
diff --git a/libcpychecker/refcounts.py b/libcpychecker/refcounts.py
index 4489a1d..d530811 100644
--- a/libcpychecker/refcounts.py
+++ b/libcpychecker/refcounts.py
@@ -1154,6 +1154,23 @@ class CPython(Facet):
self.mktrans_cobject_deprecation_warning(fnmeta, stmt),
t_failure]
+ def impl_PyCObject_FromVoidPtrAndDesc(self, stmt, v_cobj, v_desc, v_destr):
+ fnmeta = FnMeta(name='PyCObject_FromVoidPtrAndDesc',
+ docurl='http://docs.python.org/c-api/cobject.html#PyCObject_FromVoidPtrAndDesc',
+ declared_in='cobject.h',
+ prototype=('PyAPI_FUNC(PyObject *) PyCObject_FromVoidPtrAndDesc(\n'
+ ' void *cobj, void *desc, void (*destruct)(void*,void*));'),
+ defined_in='Objects/cobject.c',
+ notes='Deprecated API')
+ r_newobj, t_success, t_failure = self.object_ctor(stmt,
+ 'PyCObject',
+ 'PyCObject_Type')
+ return [t_success,
+ # Prioritize the more interesting failure over regular malloc
+ # failure, so that it doesn't disapper in de-duplication:
+ self.mktrans_cobject_deprecation_warning(fnmeta, stmt),
+ t_failure]
+
########################################################################
# PyDict_*
########################################################################
diff --git a/tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c b/tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c
new file mode 100644
index 0000000..14e717f
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c
@@ -0,0 +1,53 @@
+/*
+ Copyright 2012 David Malcolm <dmalcolm(a)redhat.com>
+ Copyright 2012 Red Hat, Inc.
+
+ This is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#include <Python.h>
+
+/*
+ Test that we detect a call to PyCObject_FromVoidPtrAndDesc that doesn't
+ handle e.g. deprecation failure
+*/
+
+struct foo
+{
+ int i;
+ int j;
+};
+
+struct foo some_foo;
+
+PyObject *
+test(PyObject *self, PyObject *args)
+{
+ PyObject *obj = PyCObject_FromVoidPtrAndDesc(&some_foo, "struct foo", NULL);
+
+ /*
+ This is incorrect: there's no error handling for if the call above
+ fails, and there's a reference leak on "obj" even if it succeeds:
+ */
+ return PyTuple_Pack(2, self, obj);
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/metadata.ini b/tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/metadata.ini
new file mode 100644
index 0000000..0d5711c
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/metadata.ini
@@ -0,0 +1,3 @@
+[ExpectedBehavior]
+# We expect only compilation *warnings*, so we expect a 0 exit code
+exitcode = 0
diff --git a/tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/script.py b/tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/script.py
new file mode 100644
index 0000000..fdd5ba3
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/script.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Copyright 2011 David Malcolm <dmalcolm(a)redhat.com>
+# Copyright 2011 Red Hat, Inc.
+#
+# This is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <http://www.gnu.org/licenses/>.
+
+from libcpychecker import main
+main(verify_refcounting=True,
+ dump_traces=True,
+ show_traces=False)
diff --git a/tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/stderr.txt b/tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/stderr.txt
new file mode 100644
index 0000000..0db1611
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/stderr.txt
@@ -0,0 +1,15 @@
+tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c: In function 'test':
+tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:44:nn: warning: ob_refcnt of '*obj' is 1 too high [enabled by default]
+tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:44:nn: note: was expecting final ob_refcnt to be N + 0 (for some unknown N)
+tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:44:nn: note: but final ob_refcnt is N + 1
+tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:38:nn: note: PyCObject allocated at: PyObject *obj = PyCObject_FromVoidPtrAndDesc(&some_foo, "struct foo", NULL);
+tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:38:nn: note: when PyCObject_FromVoidPtrAndDesc() succeeds at: PyObject *obj = PyCObject_FromVoidPtrAndDesc(&some_foo, "struct foo", NULL);
+tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:38:nn: note: ob_refcnt is now refs: 1 + N where N >= 0
+tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:44:nn: note: when PyTuple_Pack() succeeds at: return PyTuple_Pack(2, self, obj);
+tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:44:nn: note: returning at: return PyTuple_Pack(2, self, obj);
+tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:44:nn: note: found 1 similar trace(s) to this
+tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:44:nn: warning: calling PyTuple_Pack with NULL as argument 3 (obj) at tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:44 [enabled by default]
+tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:38:nn: note: when PyCObject_FromVoidPtrAndDesc() fails (when py3k deprecation warnings are enabled and configured to raise exceptions) at: PyObject *obj = PyCObject_FromVoidPtrAndDesc(&some_foo, "struct foo", NULL);
+tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:44:nn: note: PyTuple_Pack() invokes Py_INCREF() on the pointer, thus accessing (NULL)->ob_refcnt
+tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:44:nn: note: found 1 similar trace(s) to this
+tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:37:nn: note: graphical error report for function 'test' written out to 'tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c.test-refcount-errors.html'
diff --git a/tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/stdout.txt b/tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/stdout.txt
new file mode 100644
index 0000000..2ba1810
--- /dev/null
+++ b/tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/stdout.txt
@@ -0,0 +1,89 @@
+Trace 0:
+ Transitions:
+ 'when PyCObject_FromVoidPtrAndDesc() succeeds'
+ 'when PyTuple_Pack() succeeds'
+ 'returning'
+ Return value:
+ repr(): PointerToRegion(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c', line=44), region=RegionOnHeap('PyTupleObject', gcc.Location(file='tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c', line=44)))
+ str(): (struct PyObject *)&RegionOnHeap('PyTupleObject', gcc.Location(file='tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c', line=44)) from tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:44
+ r->ob_refcnt: refs: 1 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c', line=44), region=RegionForGlobal(gcc.VarDecl('PyTuple_Type')))
+ Region("region-for-arg-gcc.ParmDecl('self')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('self')")
+ str(): Region("region-for-arg-gcc.ParmDecl('self')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c', line=36), region=Region("region-for-type-of-arg-gcc.ParmDecl('self')"))
+ Region("region-for-arg-gcc.ParmDecl('args')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('args')")
+ str(): Region("region-for-arg-gcc.ParmDecl('args')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c', line=36), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')"))
+ PyCObject allocated at tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:38:
+ repr(): RegionOnHeap('PyCObject', gcc.Location(file='tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c', line=38))
+ str(): PyCObject allocated at tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:38
+ r->ob_refcnt: refs: 1 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c', line=38), region=RegionForGlobal(gcc.VarDecl('PyCObject_Type')))
+ Exception:
+ (struct PyObject *)0 from tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:37
+
+Trace 1:
+ Transitions:
+ 'when PyCObject_FromVoidPtrAndDesc() succeeds'
+ 'when PyTuple_Pack() fails'
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='struct PyObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c', line=44), value=0)
+ str(): (struct PyObject *)0 from tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:44
+ Region("region-for-arg-gcc.ParmDecl('self')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('self')")
+ str(): Region("region-for-arg-gcc.ParmDecl('self')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c', line=36), region=Region("region-for-type-of-arg-gcc.ParmDecl('self')"))
+ Region("region-for-arg-gcc.ParmDecl('args')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('args')")
+ str(): Region("region-for-arg-gcc.ParmDecl('args')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c', line=36), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')"))
+ PyCObject allocated at tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:38:
+ repr(): RegionOnHeap('PyCObject', gcc.Location(file='tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c', line=38))
+ str(): PyCObject allocated at tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:38
+ r->ob_refcnt: refs: 1 + N where N >= 0
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c', line=38), region=RegionForGlobal(gcc.VarDecl('PyCObject_Type')))
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) from tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:44
+
+Trace 2:
+ Transitions:
+ 'when PyCObject_FromVoidPtrAndDesc() fails (when py3k deprecation warnings are enabled and configured to raise exceptions)'
+ error: NullPtrArgument()
+ error: calling PyTuple_Pack with NULL as argument 3 (obj) at tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:44
+ Region("region-for-arg-gcc.ParmDecl('self')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('self')")
+ str(): Region("region-for-arg-gcc.ParmDecl('self')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c', line=36), region=Region("region-for-type-of-arg-gcc.ParmDecl('self')"))
+ Region("region-for-arg-gcc.ParmDecl('args')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('args')")
+ str(): Region("region-for-arg-gcc.ParmDecl('args')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c', line=36), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')"))
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) from tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:38
+
+Trace 3:
+ Transitions:
+ 'when PyCObject_FromVoidPtrAndDesc() fails'
+ error: NullPtrArgument()
+ error: calling PyTuple_Pack with NULL as argument 3 (obj) at tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:44
+ Region("region-for-arg-gcc.ParmDecl('self')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('self')")
+ str(): Region("region-for-arg-gcc.ParmDecl('self')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c', line=36), region=Region("region-for-type-of-arg-gcc.ParmDecl('self')"))
+ Region("region-for-arg-gcc.ParmDecl('args')"):
+ repr(): Region("region-for-arg-gcc.ParmDecl('args')")
+ str(): Region("region-for-arg-gcc.ParmDecl('args')")
+ r->ob_refcnt: refs: 0 + N where N >= 1
+ r->ob_type: PointerToRegion(gcctype='struct PyTypeObject *', loc=gcc.Location(file='tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c', line=36), region=Region("region-for-type-of-arg-gcc.ParmDecl('args')"))
+ Exception:
+ (struct PyObject *)&RegionForGlobal(gcc.VarDecl('PyExc_MemoryError')) from tests/cpychecker/refcounts/PyCObject_FromVoidPtrAndDesc/incorrect/input.c:38
12 years, 3 months