Example #1
0
def test_default_bytecode_transforms():
    cl = ClassLoader(bytecode_transforms=[simple_swap])

    cf = ClassFile.create('TestClass')
    cl.update(cf)

    test_method = cf.methods.create('test', '(V)V;', code=True)
    test_method.code.max_stack = 2
    test_method.code.max_locals = 0

    test_method.code.assemble(assemble([
        ('iconst_0',),
        ('pop',),
        ('return',)
    ]))

    # Load from the ClassLoader to bind to it.
    cf = cl.load('TestClass')

    # Ensure the defaults apply.
    ins_iter = test_method.code.disassemble()
    ins = next(ins_iter)
    assert ins.mnemonic == 'bipush'
    assert len(ins.operands) == 1
    assert ins.operands[0].value == 0

    # Ensure we can override the default.
    ins_iter = test_method.code.disassemble(transforms=[])
    ins = next(ins_iter)
    assert ins.mnemonic == 'iconst_0'
    assert len(ins.operands) == 0
Example #2
0
def test_default_bytecode_transforms():
    cl = ClassLoader(bytecode_transforms=[simple_swap])

    cf = ClassFile.create('TestClass')
    cl.update(cf)

    test_method = cf.methods.create('test', '(V)V;', code=True)
    test_method.code.max_stack = 2
    test_method.code.max_locals = 0

    test_method.code.assemble(
        assemble([('iconst_0', ), ('pop', ), ('return', )]))

    # Load from the ClassLoader to bind to it.
    cf = cl.load('TestClass')

    # Ensure the defaults apply.
    ins_iter = test_method.code.disassemble()
    ins = next(ins_iter)
    assert ins.mnemonic == 'bipush'
    assert len(ins.operands) == 1
    assert ins.operands[0].value == 0

    # Ensure we can override the default.
    ins_iter = test_method.code.disassemble(transforms=[])
    ins = next(ins_iter)
    assert ins.mnemonic == 'iconst_0'
    assert len(ins.operands) == 0
Example #3
0
def test_load_from_class():
    """Ensure we can add ClassFile's directly to the ClassLoader."""
    cl = ClassLoader()

    cf = ClassFile.create('TestClass')
    cl.update(cf)

    assert cl.load('TestClass') is cf
Example #4
0
def test_load_from_class():
    """Ensure we can add ClassFile's directly to the ClassLoader."""
    cl = ClassLoader()

    cf = ClassFile.create('TestClass')
    cl.update(cf)

    assert cl.load('TestClass') is cf
Example #5
0
def test_sourcefile_write():
    """
    Ensure SourceFileAttribute can be written and read back.
    """
    cf_one = ClassFile.create(u'SourceFileTest')

    sfa = cf_one.attributes.create(SourceFileAttribute)
    sfa.source_file = cf_one.constants.create_utf8(u'SourceFileTest.java')

    fout = BytesIO()
    cf_one.save(fout)

    fin = BytesIO(fout.getvalue())
    cf_two = ClassFile(fin)

    source_file = cf_two.attributes.find_one(name=u'SourceFile')
    assert(source_file.source_file.value == u'SourceFileTest.java')
Example #6
0
def test_sourcefile_write():
    """
    Ensure SourceFileAttribute can be written and read back.
    """
    cf_one = ClassFile.create(u'SourceFileTest')

    sfa = cf_one.attributes.create(SourceFileAttribute)
    sfa.source_file = cf_one.constants.create_utf8(u'SourceFileTest.java')

    fout = BytesIO()
    cf_one.save(fout)

    fin = BytesIO(fout.getvalue())
    cf_two = ClassFile(fin)

    source_file = cf_two.attributes.find_one(name=u'SourceFile')
    assert (source_file.source_file.value == u'SourceFileTest.java')
Example #7
0
def test_conversion():
    cf = ClassFile.create('some_class')
    exception_name = 'some_name'
    exception_class = cf.constants.create_class(exception_name)
    method = cf.methods.create('some_method', '()V', code=True)
    method.code.assemble([])

    method.code.exception_table.append(
        CodeException(start_pc=0,
                      end_pc=2,
                      handler_pc=3,
                      catch_type=exception_class.index))

    jvm_class = convert_class_file(cf)
    method = jvm_class.methods[key_from_method(method)]
    handlers = method.exception_handlers.handlers
    assert len(handlers) == 1
    handler = handlers[0]
    assert handler.catch_type == exception_name
Example #8
0
def test_printable_classes():
    cf = ClassFile.create('HelloWorld')
    assert repr(cf) == '<ClassFile(this=\'HelloWorld\')>'
    assert repr(cf.version) == 'ClassVersion(major=50, minor=0)'
Example #9
0
"""
An example showing how to create a "Hello World" class from scratch.
"""
from jawa.cf import ClassFile
from jawa.assemble import assemble

cf = ClassFile.create('HelloWorld')

main = cf.methods.create('main', '([Ljava/lang/String;)V', code=True)
main.access_flags.acc_static = True
main.code.max_locals = 1
main.code.max_stack = 2

main.code.assemble(
    assemble([('getstatic',
               cf.constants.create_field_ref('java/lang/System', 'out',
                                             'Ljava/io/PrintStream;')),
              ('ldc', cf.constants.create_string('Hello World!')),
              ('invokevirtual',
               cf.constants.create_method_ref('java/io/PrintStream', 'println',
                                              '(Ljava/lang/String;)V')),
              ('return', )]))

with open('HelloWorld.class', 'wb') as fout:
    cf.save(fout)
Example #10
0
    def create_method(self):
        """
        Creates a Method that corresponds to the generated function call.
        It will be part of a class that implements the right interface, and will
        have the appropriate name and signature.
        """
        assert self.stored_args != None
        if self.generated_method != None:
            return (self.generated_cf, self.generated_method)

        class_name = self._cf.this.name.value + "_lambda_" + str(self._ins.pos)
        self.generated_cf = ClassFile.create(class_name)
        # Jawa doesn't seem to expose this cleanly.  Technically we don't need
        # to implement the interface because the caller doesn't actually care,
        # but it's better to implement it anyways for the future.
        # (Due to the hacks below, the interface isn't even implemented properly
        # since the method we create has additional parameters and is static.)
        iface_const = self.generated_cf.constants.create_class(self.implemented_iface)
        self.generated_cf._interfaces.append(iface_const.index)

        # HACK: This officially should use instantiated_desc.descriptor,
        # but instead use a combination of the stored arguments and the
        # instantiated descriptor to make packetinstructions work better
        # (otherwise we'd need to generate and load fields in a way that
        # packetinstructions understands)
        descriptor = "(" + self.dynamic_desc.args_descriptor + \
                        self.instantiated_desc.args_descriptor + ")" + \
                        self.instantiated_desc.returns_descriptor
        method = self.generated_cf.methods.create(self.dynamic_name,
                                                  descriptor, code=True)
        self.generated_method = method
        # Similar hack: make the method static, so that packetinstructions
        # doesn't look for the corresponding instance.
        method.access_flags.acc_static = True
        # Third hack: the extra arguments are in the local variables/arguments
        # list, not on the stack.  So we need to move them to the stack.
        # (In a real implementation, these would probably be getfield instructions)
        # Also, this uses aload for everything, instead of using the appropriate
        # instruction for each type.
        instructions = []
        for i in range(len(method.args)):
            instructions.append(("aload", i))

        cls_ref = self.generated_cf.constants.create_class(self.method_class)
        if self.ref_kind in FIELD_REFS:
            # This case is not currently hit, but provided for future use
            # (Likely method_name and method_descriptor would no longer be used though)
            ref = self.generated_cf.constants.create_field_ref(
                    self.method_class, self.method_name, self.method_desc.descriptor)
        elif self.ref_kind == REF_invokeInterface:
            ref = self.generated_cf.constants.create_interface_method_ref(
                    self.method_class, self.method_name, self.method_desc.descriptor)
        else:
            ref = self.generated_cf.constants.create_method_ref(
                    self.method_class, self.method_name, self.method_desc.descriptor)

        # See https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.5
        if self.ref_kind == REF_getField:
            instructions.append(("getfield", ref))
        elif self.ref_kind == REF_getStatic:
            instructions.append(("getstatic", ref))
        elif self.ref_kind == REF_putField:
            instructions.append(("putfield", ref))
        elif self.ref_kind == REF_putStatic:
            instructions.append(("putstatic", ref))
        elif self.ref_kind == REF_invokeVirtual:
            instructions.append(("invokevirtual", ref))
        elif self.ref_kind == REF_invokeStatic:
            instructions.append(("invokestatic", ref))
        elif self.ref_kind == REF_invokeSpecial:
            instructions.append(("invokespecial", ref))
        elif self.ref_kind == REF_newInvokeSpecial:
            instructions.append(("new", cls_ref))
            instructions.append(("dup",))
            instructions.append(("invokespecial", ref))
        elif self.ref_kind == REF_invokeInterface:
            instructions.append(("invokeinterface", ref))

        method.code.assemble(assemble(instructions))

        return (self.generated_cf, self.generated_method)
Example #11
0
def test_printable_classes():
    cf = ClassFile.create('HelloWorld')
    assert repr(cf) == '<ClassFile(this=\'HelloWorld\')>'
    assert repr(cf.version) == 'ClassVersion(major=50, minor=0)'