commit eaf9b8665be224c47bb2371e3748232fdd4a8b07
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Thu Oct 27 10:46:22 2011 -0400
cpychecker: Py_BuildValue("s") expects a (char*)
Py_BuildValue("s") expects a (char*), but can also accept a (const char*)
libcpychecker/Py_BuildValue.py | 4 +-
libcpychecker/formatstrings.py | 17 ++++++-
.../code_s/incorrect-constness/input.c | 48 ++++++++++++++++++++
.../code_s/incorrect-constness/script.py | 19 ++++++++
.../code_s/incorrect-constness/stderr.txt | 7 +++
.../refcounts/Py_BuildValue/correct-code-s/input.c | 2 +-
6 files changed, 92 insertions(+), 5 deletions(-)
---
diff --git a/libcpychecker/Py_BuildValue.py b/libcpychecker/Py_BuildValue.py
index 508ee56..79afcd3 100644
--- a/libcpychecker/Py_BuildValue.py
+++ b/libcpychecker/Py_BuildValue.py
@@ -205,12 +205,12 @@ class PyBuildValueFmt(ParsedFormatString):
if c in 'sz':
if next == '#':
result.add_argument(c + '#',
- [get_const_char_ptr(),
+ [get_char_ptr(),
get_hash_size_type(with_size_t).pointer])
i += 1
else:
result.add_argument(c,
- [get_const_char_ptr()])
+ [get_char_ptr()])
continue
if c in 'NSO':
diff --git a/libcpychecker/formatstrings.py b/libcpychecker/formatstrings.py
index 11dfb1c..3037f6d 100644
--- a/libcpychecker/formatstrings.py
+++ b/libcpychecker/formatstrings.py
@@ -24,6 +24,9 @@ from libcpychecker.utils import log
const_correctness = True
+def get_char_ptr():
+ return gcc.Type.char().pointer
+
def get_const_char_ptr():
return gcc.Type.char().const_equivalent.pointer
@@ -272,6 +275,16 @@ def compatible_type(exp_type, actual_type, actualarg=None):
if compatible_type(exp_type.dereference, actual_type.dereference):
return True
+ # Support (const char*) vs (char*)
+ # Somewhat counter-intuitively, the APIs that expect a char* are those that
+ # read the string data (Py_BuildValue); those that expect a const char* are
+ # those that write back a const char* value (PyArg_ParseTuple)
+ #
+ # Hence it's OK to accept a (const char*) when a (char*) was expected:
+ if str(exp_type) == 'char *':
+ if str(actual_type) == 'const char *':
+ return True
+
# Don't be too fussy about typedefs to integer types
# For instance:
# typedef unsigned PY_LONG_LONG gdb_py_ulongest;
@@ -288,8 +301,8 @@ def compatible_type(exp_type, actual_type, actualarg=None):
if compare_int_types():
return True
- # Support character arrays vs const char*:
- if str(exp_type) == 'const char *':
+ # Support character arrays vs char*:
+ if str(exp_type) == 'char *':
if isinstance(actual_type, gcc.PointerType):
if isinstance(actual_type.dereference, gcc.ArrayType):
if actual_type.dereference.dereference == gcc.Type.char():
diff --git a/tests/cpychecker/PyArg_ParseTuple/code_s/incorrect-constness/input.c
b/tests/cpychecker/PyArg_ParseTuple/code_s/incorrect-constness/input.c
new file mode 100644
index 0000000..6e56419
--- /dev/null
+++ b/tests/cpychecker/PyArg_ParseTuple/code_s/incorrect-constness/input.c
@@ -0,0 +1,48 @@
+/*
+ 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/>.
+*/
+
+/*
+ Verify that the checker emits a warning for code "s" with a non-const
+ char*
+
+ Code "s" writes a pointer back to the insides of an object's
representation,
+ so it really should be a (const char*), not just a (char*)
+*/
+#include <Python.h>
+
+PyObject *
+test(PyObject *self, PyObject *args)
+{
+ char *str;
+
+ if (!PyArg_ParseTuple(args, "s",
+ &str)) {
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/PyArg_ParseTuple/code_s/incorrect-constness/script.py
b/tests/cpychecker/PyArg_ParseTuple/code_s/incorrect-constness/script.py
new file mode 100644
index 0000000..e120c53
--- /dev/null
+++ b/tests/cpychecker/PyArg_ParseTuple/code_s/incorrect-constness/script.py
@@ -0,0 +1,19 @@
+# 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()
diff --git a/tests/cpychecker/PyArg_ParseTuple/code_s/incorrect-constness/stderr.txt
b/tests/cpychecker/PyArg_ParseTuple/code_s/incorrect-constness/stderr.txt
new file mode 100644
index 0000000..7aa7320
--- /dev/null
+++ b/tests/cpychecker/PyArg_ParseTuple/code_s/incorrect-constness/stderr.txt
@@ -0,0 +1,7 @@
+tests/cpychecker/PyArg_ParseTuple/code_s/incorrect-constness/input.c: In function
'test':
+tests/cpychecker/PyArg_ParseTuple/code_s/incorrect-constness/input.c:34:26: error:
Mismatching type in call to PyArg_ParseTuple with format code "s"
[-fpermissive]
+ argument 3 ("&str") had type
+ "char * *"
+ but was expecting
+ "const char * *"
+ for format code "s"
diff --git a/tests/cpychecker/refcounts/Py_BuildValue/correct-code-s/input.c
b/tests/cpychecker/refcounts/Py_BuildValue/correct-code-s/input.c
index 2c2c2c6..3c4ed33 100644
--- a/tests/cpychecker/refcounts/Py_BuildValue/correct-code-s/input.c
+++ b/tests/cpychecker/refcounts/Py_BuildValue/correct-code-s/input.c
@@ -24,7 +24,7 @@
*/
PyObject *
-test(const char *foo, const char *bar)
+test(const char *foo, char *bar)
{
return Py_BuildValue("(s, s)",
foo, bar);