Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exception in thread "main" java.lang.IllegalStateException: Never found a JavaCodeUnit that matches supposed origin CodeUnit #1194

Closed
heyuxiang1996 opened this issue Nov 16, 2023 · 5 comments · Fixed by #1203
Assignees
Labels

Comments

@heyuxiang1996
Copy link

heyuxiang1996 commented Nov 16, 2023

	at com.tngtech.archunit.core.importer.RawAccessRecord$CodeUnit.resolveFrom(RawAccessRecord.java:132)
	at com.tngtech.archunit.core.importer.AccessRecord$Factory.lambda$createOriginSupplier$0(AccessRecord.java:294)
	at com.tngtech.archunit.thirdparty.com.google.common.base.Suppliers$NonSerializableMemoizingSupplier.get(Suppliers.java:181)
	at com.tngtech.archunit.core.importer.AccessRecord$Factory$RawAccessRecordProcessed.getOrigin(AccessRecord.java:255)
	at com.tngtech.archunit.core.importer.ClassGraphCreator.tryProcess(ClassGraphCreator.java:147)
	at com.tngtech.archunit.core.importer.ClassGraphCreator.lambda$completeCodeUnitDependencies$2(ClassGraphCreator.java:131)
	at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
	at java.util.stream.Streams$StreamBuilderImpl.forEachRemaining(Streams.java:419)
	at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:647)
	at java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:272)
	at java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1580)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
	at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
	at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:485)
	at com.tngtech.archunit.core.importer.ClassFileImportRecord.forEachRawConstructorCallRecord(ClassFileImportRecord.java:268)
	at com.tngtech.archunit.core.importer.ClassGraphCreator.completeCodeUnitDependencies(ClassGraphCreator.java:130)
	at com.tngtech.archunit.core.importer.ClassGraphCreator.complete(ClassGraphCreator.java:109)
	at com.tngtech.archunit.core.importer.ClassFileProcessor.process(ClassFileProcessor.java:75)
	at com.tngtech.archunit.core.importer.ClassFileImporter.importLocations(ClassFileImporter.java:325)
	at com.transsion.admtool.Main.main(Main.java:17)```
@heyuxiang1996
Copy link
Author

heyuxiang1996 commented Nov 16, 2023

I am using version 1.2 of archUnit

@heyuxiang1996 heyuxiang1996 reopened this Nov 16, 2023
@hankem
Copy link
Member

hankem commented Nov 17, 2023

Thanks for reporting the issue! I've started to look at your byte code and saw that the failure during the class file import

java.lang.IllegalStateException:
Never found a JavaCodeUnit that matches supposed origin CodeUnit{
    name='access$084',
    descriptor=(Lcom/transsion/auto/bluetooth/BluetoothUtils;Ljava/lang/Object;)Ljava/lang/String;,
    declaringClassName='com.transsion.auto.bluetooth.BluetoothUtils'
}

seems to be caused by

BluetoothUtils's synthetic method access$084
  static java.lang.String access$084(com.transsion.auto.bluetooth.BluetoothUtils, java.lang.Object);
    descriptor: (Lcom/transsion/auto/bluetooth/BluetoothUtils;Ljava/lang/Object;)Ljava/lang/String;
    flags: (0x1008) ACC_STATIC, ACC_SYNTHETIC
    Code:
      stack=3, locals=2, args_size=2
         0: new           #5                  // class java/lang/StringBuilder
         3: dup
         4: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V
         7: aload_0
         8: dup_x1
         9: getfield      #7                  // Field dev_mac_address:Ljava/lang/String;
        12: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        15: aload_1
        16: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
        19: invokevirtual #10                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        22: dup_x1
        23: putfield      #7                  // Field dev_mac_address:Ljava/lang/String;
        26: areturn
      LineNumberTable:
        line 28: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      27     0    x0   Lcom/transsion/auto/bluetooth/BluetoothUtils;
            0      27     1    x1   Ljava/lang/Object;
(which is called from BluetoothUtils$1's method onReceive)
  public void onReceive(android.content.Context, android.content.Intent);
    descriptor: (Landroid/content/Context;Landroid/content/Intent;)V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=6, locals=6, args_size=3
         0: ldc           #4                  // String BT
         2: new           #5                  // class java/lang/StringBuilder
         5: dup
         6: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V
         9: ldc           #7                  // String onReceive:
        11: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        14: aload_2
        15: invokevirtual #9                  // Method android/content/Intent.getAction:()Ljava/lang/String;
        18: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        21: invokevirtual #10                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        24: invokestatic  #11                 // Method android/util/Log.i:(Ljava/lang/String;Ljava/lang/String;)I
        27: pop
        28: ldc           #13                 // String android.bluetooth.device.action.FOUND
        30: aload_2
        31: invokevirtual #9                  // Method android/content/Intent.getAction:()Ljava/lang/String;
        34: invokevirtual #14                 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
        37: ifeq          289
        40: aload_2
        41: ldc           #15                 // String android.bluetooth.device.extra.DEVICE
        43: invokevirtual #16                 // Method android/content/Intent.getParcelableExtra:(Ljava/lang/String;)Landroid/os/Parcelable;
        46: checkcast     #12                 // class android/bluetooth/BluetoothDevice
        49: astore_3
        50: aload_3
        51: invokevirtual #17                 // Method android/bluetooth/BluetoothDevice.getName:()Ljava/lang/String;
        54: ifnull        286
        57: aload_0
        58: getfield      #2                  // Field this$0:Lcom/transsion/auto/bluetooth/BluetoothUtils;
        61: invokestatic  #18                 // Method com/transsion/auto/bluetooth/BluetoothUtils.access$000:(Lcom/transsion/auto/bluetooth/BluetoothUtils;)Ljava/lang/String;
        64: aload_3
        65: invokevirtual #19                 // Method android/bluetooth/BluetoothDevice.getAddress:()Ljava/lang/String;
        68: invokevirtual #20                 // Method java/lang/String.contains:(Ljava/lang/CharSequence;)Z
        71: ifne          286
        74: aload_0
        75: getfield      #2                  // Field this$0:Lcom/transsion/auto/bluetooth/BluetoothUtils;
        78: aload_3
        79: invokevirtual #19                 // Method android/bluetooth/BluetoothDevice.getAddress:()Ljava/lang/String;
        82: invokestatic  #21                 // Method com/transsion/auto/bluetooth/BluetoothUtils.access$084:(Lcom/transsion/auto/bluetooth/BluetoothUtils;Ljava/lang/Object;)Ljava/lang/String;
        // ...

I need to look deeper into the problem, but already want to ask:

  • How did you compile these classes?
  • Can you share the source code BluetoothUtils.java (maybe it's enough to include the private field dev_mac_address and the code that uses the anonymous android.content.BroadcastReceiver)?

@heyuxiang1996
Copy link
Author

This is my Java file. The class file is an intermediate product of compiling APK using Gradle

@hankem
Copy link
Member

hankem commented Nov 17, 2023

It's the same problem as in #1146, which occurs when inner classes use += on a private String field of the outer class.

Minimal example:

class Outer {
    private String privateString = "";

    class Inner {
        void method() {
            privateString += "+";
        }
    }
}

Some compiler( configuration)s, e.g. OpenJDK 11 with -source 8 -target 8, may produce a synthetic method that uses a StringBuilder, which ArchUnit at the moment unfortunately cannot handle correctly:

static java.lang.String access$084(Outer, java.lang.Object);
  descriptor: (LOuter;Ljava/lang/Object;)Ljava/lang/String;
  flags: (0x1008) ACC_STATIC, ACC_SYNTHETIC
  Code:
    stack=3, locals=2, args_size=2
       0: new           #1  // class java/lang/StringBuilder
       3: dup
       4: invokespecial #2  // Method java/lang/StringBuilder."<init>":()V
       7: aload_0
       8: dup_x1
       9: getfield      #3  // Field privateString:Ljava/lang/String;
      12: invokevirtual #4  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      15: aload_1
      16: invokevirtual #5  // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
      19: invokevirtual #6  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      22: dup_x1
      23: putfield      #3  // Field privateString:Ljava/lang/String;
      26: areturn

@hankem
Copy link
Member

hankem commented Nov 17, 2023

@heyuxiang1996, as a workaround, you can probably replace your dev_mac_address += device.getAddress(); with dev_mac_address = dev_mac_address + device.getAddress();.

@codecholeric codecholeric self-assigned this Nov 26, 2023
codecholeric added a commit that referenced this issue Dec 3, 2023
We weren't aware that the compiler occasionally generates synthetic
`access$123` methods that call constructors. More precisely for the
following constellation
```
class Outer {
  String field = "";
  class Inner {
    void concat() {
      field += "any";
    }
  }
}
```
the compiler generates bytecode instantiating and using a
`StringBuilder`. But for constructor calls the synthetic access
resolution was not hooked in, because we assumed that those methods
would never call a constructor. This in turn lead to the bug
```
java.lang.IllegalStateException: Never found a JavaCodeUnit that matches supposed origin CodeUnit{name='access$123'...
```
I.e. the method `access$123` was filtered out as synthetic, but the
origin of the constructor call had not been resolved to the actual
`Inner.concat` method.

Resolves: #1146
Resolves: #1194
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants