Exemplo n.º 1
0
def check_arg_types(stmt, messageName):
    entry = registeredMessages[messageName]

    for i in range(0, len(entry)):
        arg = stmt.args[i+2]

        expectedTy = entry[i]
        givenTy    = str(arg.type)

        if type_alias(expectedTy) != type_alias(givenTy):
            # An integer literal works for any kind of expected integer type,
            # regardless of if we're expecting signed or not.
            if isinstance(arg, gcc.IntegerCst) and is_integer_type(expectedTy):
                return True

            # FIXME: This is happening in crm_mon and I can't figure out why it
            # doesn't understand the uint32_t is right.
            if expectedTy == "uint32_t" and givenTy == "unsigned int":
                return True

            # We were given a "void *" but expected some other kind of pointer.
            # That should be fine.
            # FIXME:  But really, there should be some way of seeing if there's
            # a cast involved and check that if so.
            if isinstance(arg.type, gcc.PointerType) and isinstance(arg.type.dereference, gcc.VoidType) and is_pointer_type(expectedTy):
                return True

            gcc.error(stmt.loc, "Expected '%s', but got '%s' in argument %d" % (expectedTy, givenTy, i+3))
            return False

    return True
Exemplo n.º 2
0
def check_arg_count(stmt, messageName):
    entry = registeredMessages[messageName]

    if len(stmt.args) != len(entry) + 2:
        gcc.error(stmt.loc, "Expected %d arguments to message %s, but got %d" %
                  (len(entry), messageName, len(stmt.args)-2))
        return False

    return True
Exemplo n.º 3
0
def output_args_cb(fn, messageName, *args):
    types = [x.constant for x in args]

    try:
        with open(gcc.argument_dict["messages"], "rb") as f:
            registeredMessages = pickle.load(f)
    except FileNotFoundError:
        registeredMessages = {}

    if messageName.constant in registeredMessages:
        if types != registeredMessages[messageName.constant]:
            gcc.error(fn.location,
                      "Argument list is different from previous definition")
    else:
        registeredMessages[messageName.constant] = types

    with open(gcc.argument_dict["messages"], "wb") as f:
        pickle.dump(registeredMessages, f, pickle.DEFAULT_PROTOCOL)
Exemplo n.º 4
0
def on_pass_execution(p, fn):
    if p.name == '*warn_function_return':
        gcc.error(fn.start, 'this is an error (with positional args)')
        gcc.error(location=fn.start,
                  message='this is an error (with keyword args)')
        gcc.warning(fn.end, 'this is a warning (with positional args)',
                    gcc.Option('-Wdiv-by-zero'))
        gcc.warning(location=fn.end,
                    message='this is a warning (with keyword args)',
                    option=gcc.Option('-Wdiv-by-zero'))
        gcc.error(
            fn.start,
            # These should be passed through, without triggering errors:
            'a warning with some embedded format strings %s and %i')

        # Verify that -Wno-format was honored
        # The behavior of these flags changed in 4.8, so skip this part
        # on gcc 4.8 onwards:
        if gcc.GCCPLUGINS_API_VERSION <= 4007:
            gcc.warning(fn.end, 'this warning ought not to appear',
                        gcc.Option('-Wformat'))

        # Verify that we can issue an unconditional warning, with no option
        # (as per https://fedorahosted.org/gcc-python-plugin/ticket/8 ):
        gcc.warning(fn.end, 'this is an unconditional warning')
        gcc.warning(fn.end, 'this is another unconditional warning', None)

        # Verify that gcc.warning handles an object of the wrong type by
        # raising a TypeError
        try:
            gcc.warning(
                fn.end, 'this is another unconditional warning',
                'this should have been a gcc.Option instance, or None')
        except TypeError:
            err = sys.exc_info()[1]
            sys.stderr.write('expected error was found: %s\n' % err)
        else:
            raise RuntimeError('expected exception was not raised')

        # Exercise gcc.inform:
        gcc.inform(fn.start, 'This is the start of the function')
        gcc.inform(fn.end, 'This is the end of the function')
Exemplo n.º 5
0
def on_pass_execution(p, fn):
    if p.name == '*warn_function_return':
        gcc.error(fn.start, 'this is an error (with positional args)')
        gcc.error(location=fn.start,
                  message='this is an error (with keyword args)')
        gcc.warning(fn.end, 'this is a warning (with positional args)',
                    gcc.Option('-Wdiv-by-zero'))
        gcc.warning(location=fn.end,
                    message='this is a warning (with keyword args)',
                    option=gcc.Option('-Wdiv-by-zero'))
        gcc.error(fn.start,
                  # These should be passed through, without triggering errors:
                  'a warning with some embedded format strings %s and %i')

        # Verify that -Wno-format was honored
        # The behavior of these flags changed in 4.8, so skip this part
        # on gcc 4.8 onwards:
        if gcc.GCCPLUGINS_API_VERSION <= 4007:
            gcc.warning(fn.end,
                        'this warning ought not to appear',
                        gcc.Option('-Wformat'))

        # Verify that we can issue an unconditional warning, with no option
        # (as per https://fedorahosted.org/gcc-python-plugin/ticket/8 ):
        gcc.warning(fn.end, 'this is an unconditional warning')
        gcc.warning(fn.end, 'this is another unconditional warning', None)

        # Verify that gcc.warning handles an object of the wrong type by
        # raising a TypeError
        try:
            gcc.warning(fn.end, 'this is another unconditional warning',
                        'this should have been a gcc.Option instance, or None')
        except TypeError:
            err = sys.exc_info()[1]
            sys.stderr.write('expected error was found: %s\n' % err)
        else:
            raise RuntimeError('expected exception was not raised')

        # Exercise gcc.inform:
        gcc.inform(fn.start, 'This is the start of the function')
        gcc.inform(fn.end, 'This is the end of the function')
Exemplo n.º 6
0
def find_function_calls(p, fn):
    if p.name != "*warn_function_return":
        return

    for bb in fn.cfg.basic_blocks:
        if not bb.gimple:
            continue

        for stmt in bb.gimple:
            # Filter out anything that's not a function call.
            if not isinstance(stmt, gcc.GimpleCall):
                continue

            # Filter out anything that's not a function pointer reference.  We're only
            # looking for "out->message" function calls, which go through a pointer.
            if not isinstance(stmt.fn, gcc.SsaName):
                continue

            if not isinstance(stmt.fn.def_stmt, gcc.GimpleAssign):
                continue

            if len(stmt.fn.def_stmt.rhs) != 1:
                continue

            # Filter out anything that's not a pcmk__output_t and that's not a reference
            # to the message field.
            if not hasattr(stmt.fn.def_stmt.rhs[0], "target") or not hasattr(stmt.fn.def_stmt.rhs[0], "field"):
                continue

            target = stmt.fn.def_stmt.rhs[0].target
            field  = stmt.fn.def_stmt.rhs[0].field

            if str(target.type) != "struct pcmk__output_t" or field.name != "message":
                continue

            # The first two arguments are the pcmk__output_t and the name of the message
            # being called.  The compiler should have caught any cases where this is
            # wrong, but just in case...
            if len(stmt.args) < 2:
                continue

            if isinstance(stmt.args[1], gcc.SsaName) and message_from_fn_call(stmt.args[1]):
                # This is a call to the message function that figures out the message
                # name by calling some function.  We can't figure out exactly which
                # message will be called at compile time, but it's almost certainly
                # going to be one of these four.  Iterate over each and check.  They
                # should all have the same arguments.
                for messageName in ["bundle", "clone", "group", "primitive"]:
                    if messageName not in registeredMessages:
                        gcc.error(stmt.loc, "Message not registered: %s" % messageName)
                        break

                    if not check_arg_count(stmt, messageName):
                        break

                    if not check_arg_types(stmt, messageName):
                        break
            elif not isinstance(stmt.args[1], gcc.AddrExpr):
                # This is a call to the message function that uses some other method
                # to determine the message name.  We can't figure it out, so just
                # print a note and keep going.
                gcc.inform(stmt.loc, "Cannot figure out message name")
                continue
            else:
                # This is a call to the message function that uses a string literal
                # for the message name.  That's easy.
                messageName = str(stmt.args[1]).replace('"', '')

                if messageName not in registeredMessages:
                    gcc.error(stmt.loc, "Unknown format message: %s" % messageName)
                    continue

                # Check that enough arguments were provided.  The expected length does
                # not include the first two arguments, which are not for the message.
                if not check_arg_count(stmt, messageName):
                    continue

                # Check that the types are as expected.
                check_arg_types(stmt, messageName)