Exemplo n.º 1
0
    def execute(self, fun):
        if fun:
            log('%s', fun)
            if self.verify_pyargs:
                check_pyargs(fun)

            if self.only_on_python_code:
                # Only run the refcount checker on code that
                # includes <Python.h>:
                if not get_PyObject():
                    return

            # The refcount code is too buggy for now to be on by default:
            if self.verify_refcounting:
                if 0:
                    # Profiled version:
                    import cProfile
                    prof_filename = '%s.%s.refcount-profile' % (gcc.get_dump_base_name(),
                                                                fun.decl.name)
                    cProfile.runctx('self._check_refcounts(fun)',
                                    globals(), locals(),
                                    filename=prof_filename)
                    import pstats
                    prof = pstats.Stats(prof_filename)
                    prof.sort_stats('cumulative').print_stats(20)
                else:
                    # Normal mode (without profiler):
                    self._check_refcounts(fun)
Exemplo n.º 2
0
def describe_trace(trace, report, annotator):
    """
    Buffer up more details about the path through the function that
    leads to the error, using report.add_inform()
    """
    awaiting_target = None
    for t in trace.transitions:
        log('transition: %s', t)
        srcloc = t.src.get_gcc_loc_or_none()
        if t.desc:
            if srcloc:
                report.add_inform(t.src.get_gcc_loc(report.fun),
                                  ('%s at: %s'
                                   % (t.desc, get_src_for_loc(srcloc))))
            else:
                report.add_inform(t.src.get_gcc_loc(report.fun),
                                  '%s' % t.desc)

            if t.src.loc.bb != t.dest.loc.bb:
                # Tell the user where conditionals reach:
                destloc = t.dest.get_gcc_loc_or_none()
                if destloc:
                    report.add_inform(destloc,
                                      'reaching: %s' % get_src_for_loc(destloc))

        if annotator:
            notes = annotator.get_notes(t)
            for note in notes:
                if note.loc and note.loc == srcloc:
                    report.add_inform(note.loc, note.msg)
Exemplo n.º 3
0
def describe_trace(trace, report, annotator):
    """
    Buffer up more details about the path through the function that
    leads to the error, using report.add_inform()
    """
    awaiting_target = None
    for t in trace.transitions:
        log('transition: %s', t)
        srcloc = t.src.get_gcc_loc_or_none()
        if t.desc:
            if srcloc:
                report.add_inform(t.src.get_gcc_loc(report.fun),
                                  ('%s at: %s' %
                                   (t.desc, get_src_for_loc(srcloc))))
            else:
                report.add_inform(t.src.get_gcc_loc(report.fun), '%s' % t.desc)

            if t.src.stmtnode.bb != t.dest.stmtnode.bb:
                # Tell the user where conditionals reach:
                destloc = t.dest.get_gcc_loc_or_none()
                if destloc:
                    report.add_inform(
                        destloc, 'reaching: %s' % get_src_for_loc(destloc))

        if annotator:
            notes = annotator.get_notes(t)
            for note in notes:
                if note.loc and note.loc == srcloc:
                    report.add_inform(note.loc, note.msg)
Exemplo n.º 4
0
    def is_compatible(self, actual_type, actual_arg):
        # We should be encountering a function pointer of type:
        #   int (fn)(PyObject *, T*)
        # The result type (next argument) should be a T*
        if not isinstance(actual_type, gcc.PointerType):
            return False

        signature = actual_type.dereference
        if not isinstance(signature, gcc.FunctionType):
            return False

        # Check return type:
        if signature.type != gcc.Type.int():
            return False

        # Check argument types:
        if len(signature.argument_types) != 2:
            return False

        if not compatible_type(signature.argument_types[0],
                               get_PyObject().pointer):
            return False

        if not isinstance(signature.argument_types[1], gcc.PointerType):
            return False

        # Write back to the ConverterResultType with the second arg:
        log('2nd argument of converter should be of type %s',
            signature.argument_types[1])
        self.conv.result.type = signature.argument_types[1]
        self.actual_type = actual_type

        return True
    def is_compatible(self, actual_type, actual_arg):
        # We should be encountering a function pointer of type:
        #   int (fn)(PyObject *, T*)
        # The result type (next argument) should be a T*
        if not isinstance(actual_type, gcc.PointerType):
            return False

        signature = actual_type.dereference
        if not isinstance(signature, gcc.FunctionType):
            return False

        # Check return type:
        if signature.type != gcc.Type.int():
            return False

        # Check argument types:
        if len(signature.argument_types) != 2:
            return False

        if not compatible_type(signature.argument_types[0],
                               get_PyObject().pointer):
            return False

        if not isinstance(signature.argument_types[1], gcc.PointerType):
            return False

        # Write back to the ConverterResultType with the second arg:
        log('2nd argument of converter should be of type %s', signature.argument_types[1])
        self.conv.result.type = signature.argument_types[1]
        self.actual_type = actual_type

        return True
Exemplo n.º 6
0
def get_all_PyMethodDef_initializers():
    """
    Locate all initializers for PyMethodDef, returning a list
    of StructInitializer instances
    """
    log('get_all_PyMethodDef_initializers')

    result = []
    vars = gcc.get_variables()
    for var in vars:
        if isinstance(var.decl, gcc.VarDecl):
            if isinstance(var.decl.type, gcc.ArrayType):
                if str(var.decl.type.type) == 'struct PyMethodDef':
                    if var.decl.initial:
                        table = []
                        for idx, ctor in var.decl.initial.elements:
                            #print idx, ctor
                            si = PyMethodDefInitializer(ctor)
                            table.append(si)
                        # Warn about missing sentinel entry with
                        #   ml->ml_name == NULL
                        ml_name = table[-1].char_ptr_field('ml_name')
                        if 0:
                            print('final ml_name: %r' % ml_name)
                        if ml_name is not None:
                            gcc.warning(table[-1].get_location(),
                                        'missing NULL sentinel value at end of PyMethodDef table')
                        result += table
    return result
Exemplo n.º 7
0
    def execute(self, fun):
        if fun:
            log('%s', fun)
            if self.verify_pyargs:
                check_pyargs(fun)

            if self.only_on_python_code:
                # Only run the refcount checker on code that
                # includes <Python.h>:
                if not get_PyObject():
                    return

            # The refcount code is too buggy for now to be on by default:
            if self.verify_refcounting:
                if 0:
                    # Profiled version:
                    import cProfile
                    prof_filename = '%s.%s.refcount-profile' % (
                        gcc.get_dump_base_name(), fun.decl.name)
                    cProfile.runctx('self._check_refcounts(fun)',
                                    globals(),
                                    locals(),
                                    filename=prof_filename)
                    import pstats
                    prof = pstats.Stats(prof_filename)
                    prof.sort_stats('cumulative').print_stats(20)
                else:
                    # Normal mode (without profiler):
                    self._check_refcounts(fun)
Exemplo n.º 8
0
def get_all_PyMethodDef_initializers():
    """
    Locate all initializers for PyMethodDef, returning a list
    of StructInitializer instances
    """
    log('get_all_PyMethodDef_initializers')

    result = []
    vars = gcc.get_variables()
    for var in vars:
        if isinstance(var.decl, gcc.VarDecl):
            if isinstance(var.decl.type, gcc.ArrayType):
                if str(var.decl.type.type) == 'struct PyMethodDef':
                    if var.decl.initial:
                        table = []
                        for idx, ctor in var.decl.initial.elements:
                            #print idx, ctor
                            si = PyMethodDefInitializer(ctor)
                            table.append(si)
                        # Warn about missing sentinel entry with
                        #   ml->ml_name == NULL
                        ml_name = table[-1].char_ptr_field('ml_name')
                        if 0:
                            print('final ml_name: %r' % ml_name)
                        if ml_name is not None:
                            gcc.warning(
                                table[-1].get_location(),
                                'missing NULL sentinel value at end of PyMethodDef table'
                            )
                        result += table
    return result
Exemplo n.º 9
0
    def check_callsite(stmt, parser, funcname, format_idx, varargs_idx,
                       with_size_t):
        log('got call at %s', stmt.loc)
        log(get_src_for_loc(stmt.loc))
        # log('stmt: %r %s', (stmt, stmt))
        # log('args: %r', stmt.args)
        # for arg in stmt.args:
        #    # log('  arg: %s %r', (arg, arg))

        # We expect the following args:
        #   args[0]: PyObject *input_tuple
        #   args[1]: char * format
        #   args[2...]: output pointers

        if len(stmt.args) >= format_idx:
            fmt_string = get_format_string(stmt, format_idx)
            if fmt_string:
                log('fmt_string: %r', fmt_string)

                loc = stmt.loc

                # Figure out expected types, based on the format string...
                try:
                    fmt = parser.from_string(fmt_string, with_size_t)
                except FormatStringWarning:
                    err = sys.exc_info()[1]
                    err.emit_as_warning(stmt.loc)
                    return
                log('fmt: %r', fmt.args)

                exp_types = list(fmt.iter_exp_types())
                log('exp_types: %r', exp_types)

                # ...then compare them against the actual types:
                varargs = stmt.args[varargs_idx:]
                # log('varargs: %r', varargs)
                if len(varargs) < len(exp_types):
                    NotEnoughVars(funcname, fmt, varargs).emit_as_warning(loc)
                    return

                if len(varargs) > len(exp_types):
                    TooManyVars(funcname, fmt, varargs).emit_as_warning(loc)
                    return

                for index, ((exp_arg, exp_type),
                            vararg) in enumerate(zip(exp_types, varargs)):
                    if not compatible_type(
                            exp_type, vararg.type, actualarg=vararg):
                        err = MismatchingType(funcname, fmt,
                                              index + varargs_idx + 1,
                                              exp_arg.code, exp_type, vararg)
                        if hasattr(vararg, 'location'):
                            loc = vararg.location
                        else:
                            loc = stmt.loc
                        err.emit_as_warning(loc)
Exemplo n.º 10
0
    def check_callsite(stmt, parser, funcname, format_idx, varargs_idx, with_size_t):
        log('got call at %s', stmt.loc)
        log(get_src_for_loc(stmt.loc))
        # log('stmt: %r %s', (stmt, stmt))
        # log('args: %r', stmt.args)
        # for arg in stmt.args:
        #    # log('  arg: %s %r', (arg, arg))
            

        # We expect the following args:
        #   args[0]: PyObject *input_tuple
        #   args[1]: char * format
        #   args[2...]: output pointers

        if len(stmt.args) >= format_idx:
            fmt_string = get_format_string(stmt, format_idx)
            if fmt_string:
                log('fmt_string: %r', fmt_string)

                loc = stmt.loc

                # Figure out expected types, based on the format string...
                try:
                    fmt = parser.from_string(fmt_string, with_size_t)
                except FormatStringWarning:
                    err = sys.exc_info()[1]
                    err.emit_as_warning(stmt.loc)
                    return
                log('fmt: %r', fmt.args)

                exp_types = list(fmt.iter_exp_types())
                log('exp_types: %r', exp_types)

                # ...then compare them against the actual types:
                varargs = stmt.args[varargs_idx:]
                # log('varargs: %r', varargs)
                if len(varargs) < len(exp_types):
                    NotEnoughVars(funcname, fmt, varargs).emit_as_warning(loc)
                    return

                if len(varargs) > len(exp_types):
                    TooManyVars(funcname, fmt, varargs).emit_as_warning(loc)
                    return

                for index, ((exp_arg, exp_type), vararg) in enumerate(zip(exp_types, varargs)):
                    if not compatible_type(exp_type, vararg.type, actualarg=vararg):
                        err = MismatchingType(funcname, fmt,
                                              index + varargs_idx + 1,
                                              exp_arg.code, exp_type, vararg)
                        if hasattr(vararg, 'location'):
                            loc = vararg.location
                        else:
                            loc = stmt.loc
                        err.emit_as_warning(loc)
Exemplo n.º 11
0
def get_all_PyTypeObject_initializers():
    """
    Locate all initializers for PyTypeObject, returning a list
    of PyTypeObjectInitializer instances
    """
    log('get_all_PyTypeObject_initializers')

    result = []
    vars = gcc.get_variables()
    for var in vars:
        if isinstance(var.decl, gcc.VarDecl):
            if str(var.decl.type) == 'struct PyTypeObject':
                ctor = var.decl.initial
                if ctor:
                    si = PyTypeObjectInitializer(ctor)
                    result.append(si)
    return result
Exemplo n.º 12
0
def get_all_PyTypeObject_initializers():
    """
    Locate all initializers for PyTypeObject, returning a list
    of PyTypeObjectInitializer instances
    """
    log('get_all_PyTypeObject_initializers')

    result = []
    vars = gcc.get_variables()
    for var in vars:
        if isinstance(var.decl, gcc.VarDecl):
            if str(var.decl.type) == 'struct PyTypeObject':
                ctor = var.decl.initial
                if ctor:
                    si = PyTypeObjectInitializer(ctor)
                    result.append(si)
    return result
Exemplo n.º 13
0
def compatible_type(exp_type, actual_type, actualarg=None):
    log('comparing exp_type: %s (%r) with actual_type: %s (%r)', exp_type, exp_type, actual_type, actual_type)
    log('type(exp_type): %r %s', type(exp_type), type(exp_type))
    log('actualarg: %s (%r)', actualarg, actualarg)

    # Support exp_type being actually a tuple of expected types (we need this
    # for "S" and "U"):
    if isinstance(exp_type, tuple):
        for exp in exp_type:
            if compatible_type(exp, actual_type, actualarg):
                return True
        # Didn't match any of them:
        return False

    # Support the "O!" and "O&" converter codes:
    if isinstance(exp_type, AwkwardType):
        return exp_type.is_compatible(actual_type, actualarg)

    # Support the codes that can accept NULL:
    if isinstance(exp_type, NullPointer):
        if isinstance(actual_type, gcc.PointerType):
            if isinstance(actual_type.dereference, gcc.VoidType):
                # We have a (void*), double-check that it's actually NULL:
                if actualarg:
                    if isinstance(actualarg, gcc.IntegerCst):
                        if actualarg.constant == 0:
                            # We have NULL:
                            return True
        return False

    assert isinstance(exp_type, gcc.Type) or isinstance(exp_type, gcc.TypeDecl)
    assert isinstance(actual_type, gcc.Type) or isinstance(actual_type, gcc.TypeDecl)

    # Try direct comparison:
    if actual_type == exp_type:
        return True

    # Sometimes we get the typedef rather than the type, for both exp and
    # actual.  Compare using the actual types, but report using the typedefs
    # so that we can report that e.g.
    #   PyObject * *
    # was expected, rather than:
    #   struct PyObject * *
    if isinstance(exp_type, gcc.TypeDecl):
        if compatible_type(exp_type.type, actual_type):
            return True

    if isinstance(actual_type, gcc.TypeDecl):
        if compatible_type(exp_type, actual_type.type):
            return True

    # Dereference for pointers (and ptrs to ptrs etc):
    if isinstance(actual_type, gcc.PointerType) and isinstance(exp_type, gcc.PointerType):
        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;
    # gives a different IntegerType instance to that of
    #   gcc.Type.long_long().unsigned_equivalent
    # As long as the size, signedness etc are the same, let it go
    if isinstance(actual_type, gcc.IntegerType) and isinstance(exp_type, gcc.IntegerType):
        def compare_int_types():
            for attr in ('precision', 'unsigned',
                         'const', 'volatile', 'restrict'):
                if getattr(actual_type, attr) != getattr(exp_type, attr):
                    return False
            return True
        if compare_int_types():
            return True

    # 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():
                    return True

    return False
Exemplo n.º 14
0
def compatible_type(exp_type, actual_type, actualarg=None):
    log('comparing exp_type: %s (%r) with actual_type: %s (%r)', exp_type,
        exp_type, actual_type, actual_type)
    log('type(exp_type): %r %s', type(exp_type), type(exp_type))
    log('actualarg: %s (%r)', actualarg, actualarg)

    # Support exp_type being actually a tuple of expected types (we need this
    # for "S" and "U"):
    if isinstance(exp_type, tuple):
        for exp in exp_type:
            if compatible_type(exp, actual_type, actualarg):
                return True
        # Didn't match any of them:
        return False

    # Support the "O!" and "O&" converter codes:
    if isinstance(exp_type, AwkwardType):
        return exp_type.is_compatible(actual_type, actualarg)

    # Support the codes that can accept NULL:
    if isinstance(exp_type, NullPointer):
        if isinstance(actual_type, gcc.PointerType):
            if isinstance(actual_type.dereference, gcc.VoidType):
                # We have a (void*), double-check that it's actually NULL:
                if actualarg:
                    if isinstance(actualarg, gcc.IntegerCst):
                        if actualarg.constant == 0:
                            # We have NULL:
                            return True
        return False

    assert isinstance(exp_type, gcc.Type) or isinstance(exp_type, gcc.TypeDecl)
    assert isinstance(actual_type, gcc.Type) or isinstance(
        actual_type, gcc.TypeDecl)

    # Try direct comparison:
    if actual_type == exp_type:
        return True

    # Sometimes we get the typedef rather than the type, for both exp and
    # actual.  Compare using the actual types, but report using the typedefs
    # so that we can report that e.g.
    #   PyObject * *
    # was expected, rather than:
    #   struct PyObject * *
    if isinstance(exp_type, gcc.TypeDecl):
        if compatible_type(exp_type.type, actual_type):
            return True

    if isinstance(actual_type, gcc.TypeDecl):
        if compatible_type(exp_type, actual_type.type):
            return True

    # Dereference for pointers (and ptrs to ptrs etc):
    if isinstance(actual_type, gcc.PointerType) and isinstance(
            exp_type, gcc.PointerType):
        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;
    # gives a different IntegerType instance to that of
    #   gcc.Type.long_long().unsigned_equivalent
    # As long as the size, signedness etc are the same, let it go
    if isinstance(actual_type, gcc.IntegerType) and isinstance(
            exp_type, gcc.IntegerType):

        def compare_int_types():
            for attr in ('precision', 'unsigned', 'const', 'volatile',
                         'restrict'):
                if getattr(actual_type, attr) != getattr(exp_type, attr):
                    return False
            return True

        if compare_int_types():
            return True

    # 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():
                    return True

    return False