Byte code manipulation of descriptor classes?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Byte code manipulation of descriptor classes?

Ulli Hafner
I’m currently struggling with an architecture test for my descriptor classes.
Does the Jenkins maven HPI plugin somehow manipulates the byte code of descriptor classes?

Given the following setup:

BaseDescriptor {
   public void method() {}
}

ConcreteDescriptor extends BaseDescriptor {
   
}

In my architecture tests it looks like that the ConcreteDescriptor contains a byte code method that simply invokes the base method. I.e., the code seems to be

BaseDescriptor {
   public void method() {}
}

ConcreteDescriptor extends BaseDescriptor {
   public void method() {super.method()}
}

--
You received this message because you are subscribed to the Google Groups "Jenkins Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-dev/BD64655D-1CE7-4938-A0EF-AAA84A7A0C21%40gmail.com.
Reply | Threaded
Open this post in threaded view
|

Re: Byte code manipulation of descriptor classes?

Jesse Glick-4

On Tue, Jan 5, 2021 at 11:04 AM Ullrich Hafner ullrich.hafner@... wrote:

Does the Jenkins maven HPI plugin somehow manipulates the byte code of descriptor classes?

Not in this respect Sounds like something being done by javac, though I am not sure what offhand. Did you confirm via javap?

--
You received this message because you are subscribed to the Google Groups "Jenkins Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-dev/CANfRfr03TcOgvzXtXU_XvAg7GRjd1Ck%3D%3D0JX%3DEy7mYq%2Bp93S2w%40mail.gmail.com.
Reply | Threaded
Open this post in threaded view
|

Re: Byte code manipulation of descriptor classes?

John Patrick
That sounds like standard java to me.

If ConcreteDescriptor does not contain method() then the 1st method in
the inheritance hierarchy will be executes and from your code above
that would be BaseDescriptor.method. That is how java is designed to
work.

But if you are saying you have a method in both BaseDescriptor and
ConcreteDescriptor which have the exact same method signature, then
the version in BaseDescriptor could only be called if super.method()
is called. So that could be from within ConcreteDescriptor.method() of
another method in ConcreteDescriptor could also do that call as super
would override the the version in the same class.

BaseDescriptor {
    public void method() { // A }
}
ConcreteDescriptor extends BaseDescriptor {
    public void method() { // B }
    public void qwerty() { super.method(); }
}

Calling new ConcreteDescriptor().method() would trigger code B and not code A.
Calling new ConcreteDescriptor().qwerty() would trigger code A.

That is how inheritance, super and this work.

Yeah some class processing tool or byte code manipulator could be
injecting the code super.method(). Using javap will show you what that
code is doing but is hard to understand the raw byte code translation.

Simpler option, put a debug point into method() of BaseDescriptor and
run your test in debug mode, you'll quickly the call hierarchy and
what triggered the call.

John

On Tue, 5 Jan 2021 at 20:38, Jesse Glick <[hidden email]> wrote:

>
> On Tue, Jan 5, 2021 at 11:04 AM Ullrich Hafner [hidden email] wrote:
>>
>> Does the Jenkins maven HPI plugin somehow manipulates the byte code of descriptor classes?
>
> Not in this respect Sounds like something being done by javac, though I am not sure what offhand. Did you confirm via javap?
>
> --
> You received this message because you are subscribed to the Google Groups "Jenkins Developers" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
> To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-dev/CANfRfr03TcOgvzXtXU_XvAg7GRjd1Ck%3D%3D0JX%3DEy7mYq%2Bp93S2w%40mail.gmail.com.

--
You received this message because you are subscribed to the Google Groups "Jenkins Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-dev/CAH9u10mY7vGGvz2XcRksE8s0xZJ%3DXVNA4dxU432dPfYtJTLNrw%40mail.gmail.com.
Reply | Threaded
Open this post in threaded view
|

Re: Byte code manipulation of descriptor classes?

Ulli Hafner
Ok, thanks for the tip with javap. After analyzing the problem it seems that javac creates a new method in ConcreteDescriptor (that simply calls the base class method) as soon I mark the base class as package private:

abstract class A {
public void method() {

}
}
public class B extends A {

}

Output of javap:

Compiled from "B.java"
public class io.jenkins.plugins.analysis.warnings.B extends io.jenkins.plugins.analysis.warnings.A {
  public io.jenkins.plugins.analysis.warnings.B();
  public void method();
}

public abstract class A {
public void method() {

}
}
public class B extends A {

}

Output of javap:

Compiled from "B.java"
public class io.jenkins.plugins.analysis.warnings.B extends io.jenkins.plugins.analysis.warnings.A {
  public io.jenkins.plugins.analysis.warnings.B();
}



Am 05.01.2021 um 22:13 schrieb John Patrick <[hidden email]>:

That sounds like standard java to me.

If ConcreteDescriptor does not contain method() then the 1st method in
the inheritance hierarchy will be executes and from your code above
that would be BaseDescriptor.method. That is how java is designed to
work.

But if you are saying you have a method in both BaseDescriptor and
ConcreteDescriptor which have the exact same method signature, then
the version in BaseDescriptor could only be called if super.method()
is called. So that could be from within ConcreteDescriptor.method() of
another method in ConcreteDescriptor could also do that call as super
would override the the version in the same class.

BaseDescriptor {
   public void method() { // A }
}
ConcreteDescriptor extends BaseDescriptor {
   public void method() { // B }
   public void qwerty() { super.method(); }
}

Calling new ConcreteDescriptor().method() would trigger code B and not code A.
Calling new ConcreteDescriptor().qwerty() would trigger code A.

That is how inheritance, super and this work.

Yeah some class processing tool or byte code manipulator could be
injecting the code super.method(). Using javap will show you what that
code is doing but is hard to understand the raw byte code translation.

Simpler option, put a debug point into method() of BaseDescriptor and
run your test in debug mode, you'll quickly the call hierarchy and
what triggered the call.

John

On Tue, 5 Jan 2021 at 20:38, Jesse Glick <[hidden email]> wrote:

On Tue, Jan 5, 2021 at 11:04 AM Ullrich Hafner [hidden email] wrote:

Does the Jenkins maven HPI plugin somehow manipulates the byte code of descriptor classes?

Not in this respect Sounds like something being done by javac, though I am not sure what offhand. Did you confirm via javap?

--
You received this message because you are subscribed to the Google Groups "Jenkins Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-dev/CANfRfr03TcOgvzXtXU_XvAg7GRjd1Ck%3D%3D0JX%3DEy7mYq%2Bp93S2w%40mail.gmail.com.

--
You received this message because you are subscribed to the Google Groups "Jenkins Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-dev/CAH9u10mY7vGGvz2XcRksE8s0xZJ%3DXVNA4dxU432dPfYtJTLNrw%40mail.gmail.com.

--
You received this message because you are subscribed to the Google Groups "Jenkins Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-dev/4E35D2CF-860A-4D73-8C70-7DB2CF2F2367%40gmail.com.
Reply | Threaded
Open this post in threaded view
|

Re: Byte code manipulation of descriptor classes?

John Patrick
But both version of what you show above, if I execute 'new
B().method();' will trigger method in class A to be executed. Using
'javap' might change between the two versions.

That is how the language is designed to work regarding inheritance.
It's similar to how the compiler added a no-args constructor into your
class which calls the super no args constructor if you have not
defined a constructor yourself

If you don't want method in class A to be executed you'll need to
explicitly override it in class B. As not defining method in class B
will effectively make a method like 'public void method()
{super.method();}' as you have highlighted, but that is as expected
and isn't any bytecode manipulation tool, it's how the language is
designed to work.

John

On Wed, 6 Jan 2021 at 11:53, Ullrich Hafner <[hidden email]> wrote:

>
> Ok, thanks for the tip with javap. After analyzing the problem it seems that javac creates a new method in ConcreteDescriptor (that simply calls the base class method) as soon I mark the base class as package private:
>
> abstract class A {
>     public void method() {
>
>     }
> }
>
> public class B extends A {
>
> }
>
>
> Output of javap:
>
> Compiled from "B.java"
> public class io.jenkins.plugins.analysis.warnings.B extends io.jenkins.plugins.analysis.warnings.A {
>   public io.jenkins.plugins.analysis.warnings.B();
>   public void method();
> }
>
> public abstract class A {
>     public void method() {
>
>     }
> }
>
> public class B extends A {
>
> }
>
>
> Output of javap:
>
> Compiled from "B.java"
> public class io.jenkins.plugins.analysis.warnings.B extends io.jenkins.plugins.analysis.warnings.A {
>   public io.jenkins.plugins.analysis.warnings.B();
> }
>
>
>
> Am 05.01.2021 um 22:13 schrieb John Patrick <[hidden email]>:
>
> That sounds like standard java to me.
>
> If ConcreteDescriptor does not contain method() then the 1st method in
> the inheritance hierarchy will be executes and from your code above
> that would be BaseDescriptor.method. That is how java is designed to
> work.
>
> But if you are saying you have a method in both BaseDescriptor and
> ConcreteDescriptor which have the exact same method signature, then
> the version in BaseDescriptor could only be called if super.method()
> is called. So that could be from within ConcreteDescriptor.method() of
> another method in ConcreteDescriptor could also do that call as super
> would override the the version in the same class.
>
> BaseDescriptor {
>    public void method() { // A }
> }
> ConcreteDescriptor extends BaseDescriptor {
>    public void method() { // B }
>    public void qwerty() { super.method(); }
> }
>
> Calling new ConcreteDescriptor().method() would trigger code B and not code A.
> Calling new ConcreteDescriptor().qwerty() would trigger code A.
>
> That is how inheritance, super and this work.
>
> Yeah some class processing tool or byte code manipulator could be
> injecting the code super.method(). Using javap will show you what that
> code is doing but is hard to understand the raw byte code translation.
>
> Simpler option, put a debug point into method() of BaseDescriptor and
> run your test in debug mode, you'll quickly the call hierarchy and
> what triggered the call.
>
> John
>
> On Tue, 5 Jan 2021 at 20:38, Jesse Glick <[hidden email]> wrote:
>
>
> On Tue, Jan 5, 2021 at 11:04 AM Ullrich Hafner [hidden email] wrote:
>
>
> Does the Jenkins maven HPI plugin somehow manipulates the byte code of descriptor classes?
>
>
> Not in this respect Sounds like something being done by javac, though I am not sure what offhand. Did you confirm via javap?
>
> --
> You received this message because you are subscribed to the Google Groups "Jenkins Developers" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
> To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-dev/CANfRfr03TcOgvzXtXU_XvAg7GRjd1Ck%3D%3D0JX%3DEy7mYq%2Bp93S2w%40mail.gmail.com.
>
>
> --
> You received this message because you are subscribed to the Google Groups "Jenkins Developers" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
> To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-dev/CAH9u10mY7vGGvz2XcRksE8s0xZJ%3DXVNA4dxU432dPfYtJTLNrw%40mail.gmail.com.
>
>
> --
> You received this message because you are subscribed to the Google Groups "Jenkins Developers" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
> To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-dev/4E35D2CF-860A-4D73-8C70-7DB2CF2F2367%40gmail.com.

--
You received this message because you are subscribed to the Google Groups "Jenkins Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-dev/CAH9u10nixBmGTQUJAZPSJY5-K%3DSkCYpv0BjurVq4ZUg-0gbVHg%40mail.gmail.com.
Reply | Threaded
Open this post in threaded view
|

Re: Byte code manipulation of descriptor classes?

Ulli Hafner

Am 06.01.2021 um 14:27 schrieb John Patrick <[hidden email]>:

But both version of what you show above, if I execute 'new
B().method();' will trigger method in class A to be executed. Using
'javap' might change between the two versions.

That is how the language is designed to work regarding inheritance.
It's similar to how the compiler added a no-args constructor into your
class which calls the super no args constructor if you have not
defined a constructor yourself

If you don't want method in class A to be executed you'll need to
explicitly override it in class B. As not defining method in class B
will effectively make a method like 'public void method()
{super.method();}' as you have highlighted, but that is as expected
and isn't any bytecode manipulation tool, it's how the language is
designed to work.


Well, the problem I was referring to is not related to the concept of how Java implements calls in inheritance hierarchies from the user perspective. 
Maybe I forgot to add some more context: I want to check the byte code of all methods in a given class. Actually I have an architecture test that verifies that I have a call to Jenkins.hasPermission in any method that is accessible by Stapler. Sometimes that check worked, and sometimes not. As it turned out, javac only sometimes generates a synthetic method (for package private parent classes). And this synthetic method did just call the super method (and obviously does contain the permission check only in an indirect way).
 
But I solved it now, I simply ignore all methods that are marked as synthetic (i.e., generated by javac). 
Solution:


John

On Wed, 6 Jan 2021 at 11:53, Ullrich Hafner <[hidden email]> wrote:

Ok, thanks for the tip with javap. After analyzing the problem it seems that javac creates a new method in ConcreteDescriptor (that simply calls the base class method) as soon I mark the base class as package private:

abstract class A {
   public void method() {

   }
}

public class B extends A {

}


Output of javap:

Compiled from "B.java"
public class io.jenkins.plugins.analysis.warnings.B extends io.jenkins.plugins.analysis.warnings.A {
 public io.jenkins.plugins.analysis.warnings.B();
 public void method();
}

public abstract class A {
   public void method() {

   }
}

public class B extends A {

}


Output of javap:

Compiled from "B.java"
public class io.jenkins.plugins.analysis.warnings.B extends io.jenkins.plugins.analysis.warnings.A {
 public io.jenkins.plugins.analysis.warnings.B();
}



Am 05.01.2021 um 22:13 schrieb John Patrick <[hidden email]>:

That sounds like standard java to me.

If ConcreteDescriptor does not contain method() then the 1st method in
the inheritance hierarchy will be executes and from your code above
that would be BaseDescriptor.method. That is how java is designed to
work.

But if you are saying you have a method in both BaseDescriptor and
ConcreteDescriptor which have the exact same method signature, then
the version in BaseDescriptor could only be called if super.method()
is called. So that could be from within ConcreteDescriptor.method() of
another method in ConcreteDescriptor could also do that call as super
would override the the version in the same class.

BaseDescriptor {
  public void method() { // A }
}
ConcreteDescriptor extends BaseDescriptor {
  public void method() { // B }
  public void qwerty() { super.method(); }
}

Calling new ConcreteDescriptor().method() would trigger code B and not code A.
Calling new ConcreteDescriptor().qwerty() would trigger code A.

That is how inheritance, super and this work.

Yeah some class processing tool or byte code manipulator could be
injecting the code super.method(). Using javap will show you what that
code is doing but is hard to understand the raw byte code translation.

Simpler option, put a debug point into method() of BaseDescriptor and
run your test in debug mode, you'll quickly the call hierarchy and
what triggered the call.

John

On Tue, 5 Jan 2021 at 20:38, Jesse Glick <[hidden email]> wrote:


On Tue, Jan 5, 2021 at 11:04 AM Ullrich Hafner [hidden email] wrote:


Does the Jenkins maven HPI plugin somehow manipulates the byte code of descriptor classes?


Not in this respect Sounds like something being done by javac, though I am not sure what offhand. Did you confirm via javap?

--
You received this message because you are subscribed to the Google Groups "Jenkins Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-dev/CANfRfr03TcOgvzXtXU_XvAg7GRjd1Ck%3D%3D0JX%3DEy7mYq%2Bp93S2w%40mail.gmail.com.


--
You received this message because you are subscribed to the Google Groups "Jenkins Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-dev/CAH9u10mY7vGGvz2XcRksE8s0xZJ%3DXVNA4dxU432dPfYtJTLNrw%40mail.gmail.com.


--
You received this message because you are subscribed to the Google Groups "Jenkins Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-dev/4E35D2CF-860A-4D73-8C70-7DB2CF2F2367%40gmail.com.

--
You received this message because you are subscribed to the Google Groups "Jenkins Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-dev/CAH9u10nixBmGTQUJAZPSJY5-K%3DSkCYpv0BjurVq4ZUg-0gbVHg%40mail.gmail.com.

--
You received this message because you are subscribed to the Google Groups "Jenkins Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-dev/80AB70B7-ABD9-45BC-8DD1-98677FF33EBC%40gmail.com.
Reply | Threaded
Open this post in threaded view
|

Re: Byte code manipulation of descriptor classes?

Jesse Glick-4
On Wed, Jan 6, 2021 at 3:44 PM Ullrich Hafner <[hidden email]> wrote:
I have an architecture test that verifies that I have a call to Jenkins.hasPermission in any method that is accessible by Stapler.

Does not suffice to check CodeQL for violations? https://groups.google.com/g/jenkinsci-dev/c/0hw97zAdUMw/m/zt4TeGV7AQAJ

This smells like a generic check which really belongs in `InjectedTest` or something.

--
You received this message because you are subscribed to the Google Groups "Jenkins Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-dev/CANfRfr10%3D_CwgCZ6EwD4EkqLP21EN8S3cK546LcgEwB7505v%2Bg%40mail.gmail.com.
Reply | Threaded
Open this post in threaded view
|

Re: Byte code manipulation of descriptor classes?

Ulli Hafner
Yes, I already discussed that with Daniel. His check is simple not yet ready (see https://github.com/jenkinsci/jenkins-test-harness/pull/133).

Am 06.01.2021 um 21:59 schrieb Jesse Glick <[hidden email]>:

On Wed, Jan 6, 2021 at 3:44 PM Ullrich Hafner <[hidden email]> wrote:
I have an architecture test that verifies that I have a call to Jenkins.hasPermission in any method that is accessible by Stapler.

Does not suffice to check CodeQL for violations? https://groups.google.com/g/jenkinsci-dev/c/0hw97zAdUMw/m/zt4TeGV7AQAJ

This smells like a generic check which really belongs in `InjectedTest` or something.

--
You received this message because you are subscribed to the Google Groups "Jenkins Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-dev/CANfRfr10%3D_CwgCZ6EwD4EkqLP21EN8S3cK546LcgEwB7505v%2Bg%40mail.gmail.com.

--
You received this message because you are subscribed to the Google Groups "Jenkins Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-dev/0B07976E-EECC-424A-8DDD-CEE86AA1A19C%40gmail.com.