[prev in list] [next in list] [prev in thread] [next in thread]
List: gcc-python-plugin-commits
Subject: [gcc-python-plugin] cpychecker: reworking of l-values and r-values
From: dmalcolm () fedoraproject ! org (dmalcolm)
Date: 2011-10-20 19:34:06
Message-ID: 20111020193406.B6B3A12026E () lists ! fedorahosted ! org
[Download RAW message or body]
commit 35c1937df1f3d2ba26c5bd25dd5c4facf1a436e7
Author: David Malcolm <dmalcolm at redhat.com>
Date: Thu Oct 20 15:32:08 2011 -0400
cpychecker: reworking of l-values and r-values
Extracting a field from a struct with unknown value revealed a flaw in the
existing scheme for handling r-values: the UnknownValue() would be inherited
from the parent region (the struct), but would have the wrong type:
UnknownValue(gcctype=some_struct)
rather than
UnknownStruct(gcctype=type_of_field)
This lead to various flaws, including Python exceptions when handling pointer
fields, since the machinery for splitting the r-value into the NULL/non-NULL
cases requires such an r-value to be a pointer type.
This is covered by new test cases:
tests/cpychecker/absinterp/nested-fields2
tests/cpychecker/absinterp/nested-fields3
This patch introduces an AbstractValue.extract_from_parent() method, which can
be called on a r-value supplied as a default by a parent region, coercing it to
the appropriate type for the child region.
Doing so uncovered an issue with array handling. Within:
int arr[10];
int *ptr = arr;
ptr's r-value had type "&int[10]", rather than type "int*". This led to
issues where e.g.:
ptr[0] = 42;
return ptr[1];
would leak to 'arr' being assigned a default r-value of 42, when really only
'arr[0]' should have the r-value, and thus ptr[1] would erroneously evaluate
to 42, rather than be detected as uninitialized.
The fix for this is to introduce a new ArrayElementRegion subclass, signifying
a specific indexed location within an array, and for the above to give ptr the
r-value "&arr[0]" (with type 'int*') rather than "arr", and to update pointer
arithmetic accordingly.
These test cases add additional test coverage for pointer arithmetic within an
array:
tests/cpychecker/absinterp/arrays5
tests/cpychecker/absinterp/arrays6
The introduction of ArrayElementRegion has a knock-on effect on how we handle
string constants: in code of this form:
char *str = "hello world";
'str' now with an r-value of &("hello world"[0]) since this is a char*, rather
than of the "hello world" directly, since this is a char[12]. (i.e. it has a
PointerToRegion() to a ArrayElementRegion() within aRegionForStringConstant(),
rather than to the latter directly).
libcpychecker/absinterp.py | 63 ++++++++++++++++++-
libcpychecker/refcounts.py | 16 +----
tests/cpychecker/absinterp/arrays5/input.c | 47 +++++++++++++++
tests/cpychecker/absinterp/arrays5/script.py | 22 +++++++
tests/cpychecker/absinterp/arrays5/stdout.txt | 8 +++
tests/cpychecker/absinterp/arrays6/input.c | 44 ++++++++++++++
tests/cpychecker/absinterp/arrays6/script.py | 22 +++++++
tests/cpychecker/absinterp/arrays6/stderr.txt | 3 +
tests/cpychecker/absinterp/arrays6/stdout.txt | 6 ++
tests/cpychecker/absinterp/nested-fields2/input.c | 50 ++++++++++++++++
.../cpychecker/absinterp/nested-fields2/script.py | 22 +++++++
.../cpychecker/absinterp/nested-fields2/stdout.txt | 17 +++++
tests/cpychecker/absinterp/nested-fields3/input.c | 51 ++++++++++++++++
.../cpychecker/absinterp/nested-fields3/script.py | 22 +++++++
.../cpychecker/absinterp/nested-fields3/stderr.txt | 3 +
.../cpychecker/absinterp/nested-fields3/stdout.txt | 6 ++
.../absinterp/string-constants/stdout.txt | 8 +-
tests/cpychecker/absinterp/switch/stdout.txt | 12 ++--
18 files changed, 396 insertions(+), 26 deletions(-)
---
diff --git a/libcpychecker/absinterp.py b/libcpychecker/absinterp.py
index c731e0e..cedbae1 100644
--- a/libcpychecker/absinterp.py
+++ b/libcpychecker/absinterp.py
@@ -158,6 +158,31 @@ class AbstractValue:
"""
raise NotImplementedError("impl_is_ge for %s (with %s" % (self, rhs))
+ def extract_from_parent(self, region, gcctype, loc):
+ """
+ Called on a parent when inheriting a value from it for a child region,
+ for example, when a whole struct has "UnknownValue", we can extract
+ a particular field, giving an UnknownValue of the appropriate type
+ """
+ raise NotImplementedError('%s.extract_from_parent(%s, %s, %s)'
+ % (self.__class__.__name__, region, gcctype, loc))
+
+ def as_string_constant(self):
+ """
+ If this is a pointer to a string constant, return the underlying
+ string, otherwise return None
+ """
+ if isinstance(self, PointerToRegion):
+ if isinstance(self.region, RegionForStringConstant):
+ return self.region.text
+ # We could be dealing with e.g. char *ptr = "hello world";
+ # where "hello world" is a 'char[12]', and thus ptr has been
+ # assigned a char* pointing to '"hello world"[0]'
+ if isinstance(self.region, ArrayElementRegion):
+ if isinstance(self.region.parent, RegionForStringConstant):
+ return self.region.parent.text[self.region.index:]
+ # Otherwise, not a string constant, return None
+
class UnknownValue(AbstractValue):
"""
A value that we know nothing about
@@ -207,6 +232,9 @@ class UnknownValue(AbstractValue):
def impl_is_ge(self, rhs):
return None
+ def extract_from_parent(self, region, gcctype, loc):
+ return UnknownValue.make(gcctype, loc)
+
def eval_binop(exprcode, a, b):
"""
Evaluate a gcc exprcode on a pair of Python values (as opposed to
@@ -600,6 +628,9 @@ class DeallocatedMemory(AbstractValue):
else:
return 'deallocated memory'
+ def extract_from_parent(self, region, gcctype, loc):
+ return DeallocatedMemory(gcctype, self.loc)
+
class UninitializedData(AbstractValue):
def __str__(self):
if self.loc:
@@ -634,6 +665,9 @@ class UninitializedData(AbstractValue):
raise CallOfUninitializedFunctionPtr(stmt, self)
+ def extract_from_parent(self, region, gcctype, loc):
+ return UninitializedData(gcctype, self.loc)
+
############################################################################
# Various kinds of predicted error:
############################################################################
@@ -856,6 +890,11 @@ class RegionForStringConstant(Region):
Region.__init__(self, text, None)
self.text = text
+class ArrayElementRegion(Region):
+ def __init__(self, name, parent, index):
+ Region.__init__(self, name, parent)
+ self.index = index
+
class MissingValue(Exception):
"""
The value tracking system couldn't figure out any information about the
@@ -1113,7 +1152,11 @@ class State:
log('expr.operand: %r', expr.operand)
lvalue = self.eval_lvalue(expr.operand, loc)
check_isinstance(lvalue, Region)
- return PointerToRegion(expr.type, loc, lvalue)
+ if isinstance(expr.operand.type, gcc.ArrayType):
+ index0_lvalue = self._array_region(lvalue, 0)
+ return PointerToRegion(expr.type, loc, index0_lvalue)
+ else:
+ return PointerToRegion(expr.type, loc, lvalue)
if isinstance(expr, gcc.ArrayRef):
log('expr.array: %r', expr.array)
log('expr.index: %r', expr.index)
@@ -1208,6 +1251,9 @@ class State:
sizeof = rhs[0].type.dereference.sizeof
log('%s', sizeof)
index = b.value / sizeof
+ # Are we offsetting within an array?
+ if isinstance(parent, ArrayElementRegion):
+ return self._array_region(parent.parent, parent.index + index)
return self._array_region(parent, index)
else:
raise NotImplementedError("Don't know how to cope with pointer addition \
of\n %r\nand\n %rat %s" @@ -1215,6 +1261,7 @@ class State:
def _array_region(self, parent, index):
# Used by element_region, and pointer_add_region
+ log('_array_region(%s, %s)', parent, index)
check_isinstance(parent, Region)
check_isinstance(index, (int, long, UnknownValue, ConcreteValue, \
WithinRange)) if isinstance(index, ConcreteValue):
@@ -1223,7 +1270,7 @@ class State:
log('reusing')
return parent.fields[index]
log('not reusing')
- region = Region('%s[%s]' % (parent.name, index), parent)
+ region = ArrayElementRegion('%s[%s]' % (parent.name, index), parent, index)
parent.fields[index] = region
# it is its own region:
self.region_for_var[region] = region
@@ -1282,14 +1329,15 @@ class State:
def _get_store_recursive(self, region, gcctype, loc):
check_isinstance(region, Region)
- # self.log(log)
+ log('_get_store_recursive(%s, %s, %s)', region, gcctype, loc)
if region in self.value_for_region:
return self.value_for_region[region]
# Not found; try default value from parent region:
if region.parent:
try:
- return self._get_store_recursive(region.parent, gcctype, loc)
+ parent_value = self._get_store_recursive(region.parent, gcctype, \
loc) + return parent_value.extract_from_parent(region, gcctype, loc)
except MissingValue:
raise MissingValue(region)
@@ -1836,6 +1884,13 @@ class State:
gcc.TruthAndExpr, gcc.TruthOrExpr
):
a, b = self.eval_binop_args(stmt)
+ if isinstance(a, UninitializedData):
+ raise UsageOfUninitializedData(self, stmt.rhs[0], a,
+ 'usage of uninitialized data in \
left-hand side of %s' % stmt.exprcode) + if isinstance(b, \
UninitializedData): + raise UsageOfUninitializedData(self, \
stmt.rhs[1], b, + 'usage of \
uninitialized data in right-hand side of %s' % stmt.exprcode) +
try:
c = a.eval_binop(stmt.exprcode, b, stmt.lhs.type, stmt.loc)
check_isinstance(c, AbstractValue)
diff --git a/libcpychecker/refcounts.py b/libcpychecker/refcounts.py
index f155f6a..5ec999c 100644
--- a/libcpychecker/refcounts.py
+++ b/libcpychecker/refcounts.py
@@ -208,11 +208,6 @@ class GenericTpDealloc(AbstractValue):
return [Transition(state, s_new, desc)]
-def _get_format_string(v_fmt):
- if isinstance(v_fmt, PointerToRegion):
- if isinstance(v_fmt.region, RegionForStringConstant):
- return v_fmt.region.text
-
class CPython(Facet):
def __init__(self, state, exception_rvalue=None, fun=None):
Facet.__init__(self, state)
@@ -527,10 +522,7 @@ class CPython(Facet):
within the trace.
"""
returntype = stmt.fn.type.dereference.type
- desc = None
- if isinstance(args[0], PointerToRegion):
- if isinstance(args[0].region, RegionForStringConstant):
- desc = args[0].region.text
+ desc = args[0].as_string_constant()
return [self.state.mktrans_assignment(stmt.lhs,
UnknownValue.make(returntype, stmt.loc),
desc)]
@@ -626,7 +618,7 @@ class CPython(Facet):
check_isinstance(v_new, AbstractValue)
s_success.value_for_region[v_vararg.region] = v_new
- fmt_string = _get_format_string(v_fmt)
+ fmt_string = v_fmt.as_string_constant()
if fmt_string:
try:
fmt = PyArgParseFmt.from_string(fmt_string, with_size_t)
@@ -796,7 +788,7 @@ class CPython(Facet):
t_success, t_failure = self.make_transitions_for_new_ref_or_fail(stmt)
- fmt_string = _get_format_string(v_fmt)
+ fmt_string = v_fmt.as_string_constant()
if fmt_string:
try:
fmt = PyBuildValueFmt.from_string(fmt_string, with_size_t)
@@ -1435,7 +1427,7 @@ class CPython(Facet):
t_success, t_failure = self.make_transitions_for_new_ref_or_fail(stmt)
- fmt_string = _get_format_string(v_fmt)
+ fmt_string = v_fmt.as_string_constant()
if fmt_string:
try:
fmt = PyBuildValueFmt.from_string(fmt_string, with_size_t)
diff --git a/tests/cpychecker/absinterp/arrays5/input.c \
b/tests/cpychecker/absinterp/arrays5/input.c new file mode 100644
index 0000000..98406ff
--- /dev/null
+++ b/tests/cpychecker/absinterp/arrays5/input.c
@@ -0,0 +1,47 @@
+/*
+ Copyright 2011 David Malcolm <dmalcolm at 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/>.
+*/
+
+#include <Python.h>
+
+/*
+ Test of reading and writing simple arrays via pointers
+*/
+int test_arrays5(void)
+{
+ int arr[10];
+ int *ptr = arr + 3;
+
+ ptr[0] = 1;
+ ptr[1] = 2;
+ ptr[2] = 3;
+
+ /*
+ The analyser ought to be able to figure out that there's a single trace
+ with return value 6 (rather than "unknown", or uninitialized data):
+ */
+ return arr[3] + arr[4] + arr[5];
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/absinterp/arrays5/script.py \
b/tests/cpychecker/absinterp/arrays5/script.py new file mode 100644
index 0000000..6bb62fd
--- /dev/null
+++ b/tests/cpychecker/absinterp/arrays5/script.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Copyright 2011 David Malcolm <dmalcolm at 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)
diff --git a/tests/cpychecker/absinterp/arrays5/stdout.txt \
b/tests/cpychecker/absinterp/arrays5/stdout.txt new file mode 100644
index 0000000..46e9126
--- /dev/null
+++ b/tests/cpychecker/absinterp/arrays5/stdout.txt
@@ -0,0 +1,8 @@
+Trace 0:
+ Transitions:
+ 'returning'
+ Return value:
+ repr(): ConcreteValue(gcctype='int', \
loc=gcc.Location(file='tests/cpychecker/absinterp/arrays5/input.c', line=38), \
value=6) + str(): (int)6 from tests/cpychecker/absinterp/arrays5/input.c:38
+ Exception:
+ (struct PyObject *)0 from tests/cpychecker/absinterp/arrays5/input.c:26
diff --git a/tests/cpychecker/absinterp/arrays6/input.c \
b/tests/cpychecker/absinterp/arrays6/input.c new file mode 100644
index 0000000..b1f76f7
--- /dev/null
+++ b/tests/cpychecker/absinterp/arrays6/input.c
@@ -0,0 +1,44 @@
+/*
+ Copyright 2011 David Malcolm <dmalcolm at 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/>.
+*/
+
+#include <Python.h>
+
+/*
+ Test of reading and writing simple arrays via pointers
+*/
+int test_arrays6(void)
+{
+ int arr[10];
+ int *ptr = arr;
+
+ ptr[0] = 42;
+
+ /*
+ The analyser ought to figure out that arr[1] is still uninitialized:
+ */
+ return arr[0] + arr[1];
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/absinterp/arrays6/script.py \
b/tests/cpychecker/absinterp/arrays6/script.py new file mode 100644
index 0000000..6bb62fd
--- /dev/null
+++ b/tests/cpychecker/absinterp/arrays6/script.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Copyright 2011 David Malcolm <dmalcolm at 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)
diff --git a/tests/cpychecker/absinterp/arrays6/stderr.txt \
b/tests/cpychecker/absinterp/arrays6/stderr.txt new file mode 100644
index 0000000..4d7c4ec
--- /dev/null
+++ b/tests/cpychecker/absinterp/arrays6/stderr.txt
@@ -0,0 +1,3 @@
+tests/cpychecker/absinterp/arrays6/input.c: In function 'test_arrays6':
+tests/cpychecker/absinterp/arrays6/input.c:35:5: error: usage of uninitialized data \
in right-hand side of <type 'gcc.PlusExpr'>: gcc.VarDecl(nnnn) at \
tests/cpychecker/absinterp/arrays6/input.c:35 \
+tests/cpychecker/absinterp/arrays6/input.c:26:1: note: graphical error report for \
function 'test_arrays6' written out to \
'tests/cpychecker/absinterp/arrays6/input.c.test_arrays6-refcount-errors.html'
diff --git a/tests/cpychecker/absinterp/arrays6/stdout.txt \
b/tests/cpychecker/absinterp/arrays6/stdout.txt new file mode 100644
index 0000000..bbeb6eb
--- /dev/null
+++ b/tests/cpychecker/absinterp/arrays6/stdout.txt
@@ -0,0 +1,6 @@
+Trace 0:
+ Transitions:
+ error: UsageOfUninitializedData()
+ error: usage of uninitialized data in right-hand side of <type 'gcc.PlusExpr'>: \
gcc.VarDecl(nnnn) at tests/cpychecker/absinterp/arrays6/input.c:35 + Exception:
+ (struct PyObject *)0 from tests/cpychecker/absinterp/arrays6/input.c:26
diff --git a/tests/cpychecker/absinterp/nested-fields2/input.c \
b/tests/cpychecker/absinterp/nested-fields2/input.c new file mode 100644
index 0000000..2374ab3
--- /dev/null
+++ b/tests/cpychecker/absinterp/nested-fields2/input.c
@@ -0,0 +1,50 @@
+/*
+ Copyright 2011 David Malcolm <dmalcolm at 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/>.
+*/
+
+#include <Python.h>
+
+/*
+ Test that we can cope with nested structures with unknown value
+*/
+struct FooType {
+ int field;
+};
+
+struct BarType {
+ struct FooType *ptr;
+};
+
+int test_nested(struct BarType bar)
+{
+ /*
+ "bar" has an UnknownValue of type "struct BarType"
+ "bar.ptr" inherits the fact that the value is unknown, but must
+ have type "struct FooType*": the UnknownValue must be cast to the
+ correct type.
+ */
+ return bar.ptr->field;
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/absinterp/nested-fields2/script.py \
b/tests/cpychecker/absinterp/nested-fields2/script.py new file mode 100644
index 0000000..6bb62fd
--- /dev/null
+++ b/tests/cpychecker/absinterp/nested-fields2/script.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Copyright 2011 David Malcolm <dmalcolm at 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)
diff --git a/tests/cpychecker/absinterp/nested-fields2/stdout.txt \
b/tests/cpychecker/absinterp/nested-fields2/stdout.txt new file mode 100644
index 0000000..46ca38f
--- /dev/null
+++ b/tests/cpychecker/absinterp/nested-fields2/stdout.txt
@@ -0,0 +1,17 @@
+Trace 0:
+ Transitions:
+ 'when treating unknown struct FooType * from \
tests/cpychecker/absinterp/nested-fields2/input.c:41 as non-NULL' + 'returning'
+ Return value:
+ repr(): WithinRange(gcctype='int', \
loc=gcc.Location(file='tests/cpychecker/absinterp/nested-fields2/input.c', line=41), \
minvalue=-0x80000000, maxvalue=0x7fffffff) + str(): (int)val [-0x80000000 <= val \
<= 0x7fffffff] from tests/cpychecker/absinterp/nested-fields2/input.c:41 + \
Exception: + (struct PyObject *)0 from \
tests/cpychecker/absinterp/nested-fields2/input.c:34 +
+Trace 1:
+ Transitions:
+ 'when treating unknown struct FooType * from \
tests/cpychecker/absinterp/nested-fields2/input.c:41 as NULL' + error: \
NullPtrDereference() + error: possibly dereferencing NULL (D.nnnnn->field) at \
tests/cpychecker/absinterp/nested-fields2/input.c:41 + Exception:
+ (struct PyObject *)0 from tests/cpychecker/absinterp/nested-fields2/input.c:34
diff --git a/tests/cpychecker/absinterp/nested-fields3/input.c \
b/tests/cpychecker/absinterp/nested-fields3/input.c new file mode 100644
index 0000000..7686d14
--- /dev/null
+++ b/tests/cpychecker/absinterp/nested-fields3/input.c
@@ -0,0 +1,51 @@
+/*
+ Copyright 2011 David Malcolm <dmalcolm at 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/>.
+*/
+
+#include <Python.h>
+
+/*
+ Test that we can cope with nested structures with an uninialized value
+*/
+struct FooType {
+ int field;
+};
+
+struct BarType {
+ struct FooType *ptr;
+};
+
+int test_nested(void)
+{
+ struct BarType bar;
+ /*
+ "bar" has an UninitializedValue of type "struct BarType"
+ "bar.ptr" inherits the fact that the value is unitialized, but must
+ have type "struct FooType*": the UninitializedValue must be cast to the
+ correct type.
+ */
+ return bar.ptr->field;
+}
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/cpychecker/absinterp/nested-fields3/script.py \
b/tests/cpychecker/absinterp/nested-fields3/script.py new file mode 100644
index 0000000..6bb62fd
--- /dev/null
+++ b/tests/cpychecker/absinterp/nested-fields3/script.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Copyright 2011 David Malcolm <dmalcolm at 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)
diff --git a/tests/cpychecker/absinterp/nested-fields3/stderr.txt \
b/tests/cpychecker/absinterp/nested-fields3/stderr.txt new file mode 100644
index 0000000..9efbc58
--- /dev/null
+++ b/tests/cpychecker/absinterp/nested-fields3/stderr.txt
@@ -0,0 +1,3 @@
+tests/cpychecker/absinterp/nested-fields3/input.c: In function 'test_nested':
+tests/cpychecker/absinterp/nested-fields3/input.c:42:5: error: dereferencing \
uninitialized pointer: D.nnnnn->field at \
tests/cpychecker/absinterp/nested-fields3/input.c:42 \
+tests/cpychecker/absinterp/nested-fields3/input.c:34:1: note: graphical error report \
for function 'test_nested' written out to \
'tests/cpychecker/absinterp/nested-fields3/input.c.test_nested-refcount-errors.html'
diff --git a/tests/cpychecker/absinterp/nested-fields3/stdout.txt \
b/tests/cpychecker/absinterp/nested-fields3/stdout.txt new file mode 100644
index 0000000..be7c4c9
--- /dev/null
+++ b/tests/cpychecker/absinterp/nested-fields3/stdout.txt
@@ -0,0 +1,6 @@
+Trace 0:
+ Transitions:
+ error: UsageOfUninitializedData()
+ error: dereferencing uninitialized pointer: D.nnnnn->field at \
tests/cpychecker/absinterp/nested-fields3/input.c:42 + Exception:
+ (struct PyObject *)0 from tests/cpychecker/absinterp/nested-fields3/input.c:34
diff --git a/tests/cpychecker/absinterp/string-constants/stdout.txt \
b/tests/cpychecker/absinterp/string-constants/stdout.txt index eea84e3..12d881e \
100644
--- a/tests/cpychecker/absinterp/string-constants/stdout.txt
+++ b/tests/cpychecker/absinterp/string-constants/stdout.txt
@@ -3,8 +3,8 @@ Trace 0:
'when taking True path'
'returning'
Return value:
- repr(): PointerToRegion(gcctype='char[6] *', \
loc=gcc.Location(file='tests/cpychecker/absinterp/string-constants/input.c', \
line=28), region=RegionForStringConstant('Hello'))
- str(): (char[6] *)&RegionForStringConstant('Hello') from \
tests/cpychecker/absinterp/string-constants/input.c:28 + repr(): \
PointerToRegion(gcctype='char[6] *', \
loc=gcc.Location(file='tests/cpychecker/absinterp/string-constants/input.c', \
line=28), region=ArrayElementRegion('Hello[0]')) + str(): (char[6] \
*)&ArrayElementRegion('Hello[0]') from \
tests/cpychecker/absinterp/string-constants/input.c:28 r->ob_refcnt: None
r->ob_type: None
Exception:
@@ -15,8 +15,8 @@ Trace 1:
'when taking False path'
'returning'
Return value:
- repr(): PointerToRegion(gcctype='char[8] *', \
loc=gcc.Location(file='tests/cpychecker/absinterp/string-constants/input.c', \
line=30), region=RegionForStringConstant('Goodbye'))
- str(): (char[8] *)&RegionForStringConstant('Goodbye') from \
tests/cpychecker/absinterp/string-constants/input.c:30 + repr(): \
PointerToRegion(gcctype='char[8] *', \
loc=gcc.Location(file='tests/cpychecker/absinterp/string-constants/input.c', \
line=30), region=ArrayElementRegion('Goodbye[0]')) + str(): (char[8] \
*)&ArrayElementRegion('Goodbye[0]') from \
tests/cpychecker/absinterp/string-constants/input.c:30 r->ob_refcnt: None
r->ob_type: None
Exception:
diff --git a/tests/cpychecker/absinterp/switch/stdout.txt \
b/tests/cpychecker/absinterp/switch/stdout.txt index 71856ec..3ace78e 100644
--- a/tests/cpychecker/absinterp/switch/stdout.txt
+++ b/tests/cpychecker/absinterp/switch/stdout.txt
@@ -3,8 +3,8 @@ Trace 0:
'when following default'
'returning'
Return value:
- repr(): PointerToRegion(gcctype='char[6] *', \
loc=gcc.Location(file='tests/cpychecker/absinterp/switch/input.c', line=32), \
region=RegionForStringConstant('Green'))
- str(): (char[6] *)&RegionForStringConstant('Green') from \
tests/cpychecker/absinterp/switch/input.c:32 + repr(): \
PointerToRegion(gcctype='char[6] *', \
loc=gcc.Location(file='tests/cpychecker/absinterp/switch/input.c', line=32), \
region=ArrayElementRegion('Green[0]')) + str(): (char[6] \
*)&ArrayElementRegion('Green[0]') from tests/cpychecker/absinterp/switch/input.c:32 \
r->ob_refcnt: None r->ob_type: None
Exception:
@@ -15,8 +15,8 @@ Trace 1:
'when following case 0'
'returning'
Return value:
- repr(): PointerToRegion(gcctype='char[4] *', \
loc=gcc.Location(file='tests/cpychecker/absinterp/switch/input.c', line=29), \
region=RegionForStringConstant('Red'))
- str(): (char[4] *)&RegionForStringConstant('Red') from \
tests/cpychecker/absinterp/switch/input.c:29 + repr(): \
PointerToRegion(gcctype='char[4] *', \
loc=gcc.Location(file='tests/cpychecker/absinterp/switch/input.c', line=29), \
region=ArrayElementRegion('Red[0]')) + str(): (char[4] \
*)&ArrayElementRegion('Red[0]') from tests/cpychecker/absinterp/switch/input.c:29 \
r->ob_refcnt: None r->ob_type: None
Exception:
@@ -27,8 +27,8 @@ Trace 2:
'when following case 2'
'returning'
Return value:
- repr(): PointerToRegion(gcctype='char[5] *', \
loc=gcc.Location(file='tests/cpychecker/absinterp/switch/input.c', line=34), \
region=RegionForStringConstant('Blue'))
- str(): (char[5] *)&RegionForStringConstant('Blue') from \
tests/cpychecker/absinterp/switch/input.c:34 + repr(): \
PointerToRegion(gcctype='char[5] *', \
loc=gcc.Location(file='tests/cpychecker/absinterp/switch/input.c', line=34), \
region=ArrayElementRegion('Blue[0]')) + str(): (char[5] \
*)&ArrayElementRegion('Blue[0]') from tests/cpychecker/absinterp/switch/input.c:34 \
r->ob_refcnt: None r->ob_type: None
Exception:
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic