[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