LibAFL icon indicating copy to clipboard operation
LibAFL copied to clipboard

GSoC'25: Tool for Automated generic/bounds simplification

Open addisoncrump opened this issue 11 months ago • 13 comments

As commented by many users and maintainers of LibAFL, our codebase is absolutely full of complicated generics. We use these to allow for structured and statically-checked compatibility between various components provided in our codebase, and is a critical part of how LibAFL is structured.

Unfortunately, these can be very difficult to maintain. Our goal is to develop a tool capable of assisting developers in this maintenance process.


Consider a code sequence like the following:

trait Trait1 {}
trait Trait2<A>
where
  A: Trait1
{}

struct Thing1;
struct Thing2<I>(I);

impl<A> Trait2<A> for Thing1
where
  A: Trait1
{}

impl<A> Trait2<A> for Thing2<Thing1>
where
  A: Trait1,
{
  // implement using Thing1's implementation
}

Suppose we change Trait2 now to not include the bound A: Trait1:

2,5c2
< trait Trait2<A>
< where
<     A: Trait1
< {}
---
> trait Trait2<A> {}

Maybe Thing1's implementation of Trait2 doesn't internally depend on A: Trait1; then neither does Thing2's! So, our actual diff should be:

2,5c2
< trait Trait2<A>
< where
<     A: Trait1
< {}
---
> trait Trait2<A> {}
10,13c7
< impl<A> Trait2<A> for Thing1
< where
<     A: Trait1
< {}
---
> impl<A> Trait2<A> for Thing1 {}
15,18c9
< impl<A> Trait2<A> for Thing2<Thing1>
< where
<     A: Trait1,
< {
---
> impl<A> Trait2<A> for Thing2<Thing1> {

Consider another case, shown below, where we have a mutually recursive pair of functions:

trait Trait {}

fn first<A>(should: bool)
where
    A: Trait,
{
    if should {
        second::<A>(!should)
    }
}

fn second<A>(should: bool)
where
    A: Trait,
{
    if should {
        first::<A>(!should)
    }
}

If neither of the functions actually use the bound, then it should be dropped. But this requires the knowledge that they can both be simultaneously dropped:

3,6c3
< fn first<A>(should: bool)
< where
<     A: Trait,
< {
---
> fn first<A>(should: bool) {
12,15c9
< fn second<A>(should: bool)
< where
<     A: Trait,
< {
---
> fn second<A>(should: bool) {

Furthermore, neither function even uses the generic argument! So this could itself be rewritten:

3,6c3
< fn first<A>(should: bool)
< where
<     A: Trait,
< {
---
> fn first(should: bool) {
8c5
<         second::<A>(!should)
---
>         second(!should)
12,15c9
< fn second<A>(should: bool)
< where
<     A: Trait,
< {
---
> fn second(should: bool) {
17c11
<         first::<A>(!should)
---
>         first(!should)

In short, these issues cause numerous maintenance issues, several of which are outlined in CONTRIBUTING.md, but are in reality very hard to enforce. For this reason, we are opening a GSOC project, which we would like to supervise into potentially a bachelor's/master's thesis or workshop paper, in which we will implement a tool to perform "generic shaking". This entails:

  1. Removes overspecified generic bounds.
  2. Removes overspecified associated types (e.g., instead of <A, B<Thing=A>>, just <B>).
  3. Removes overspecified generics, including in PhantomData declarations.
  4. Removes overspecified lifetimes.
  5. Successfully is able to do both of the above in the presence of dependency cycles (see example 2).

This is a project that likely requires some background in Rust compiler infrastructure and type theory in general. For this reason, we are opening this up specifically to candidates who already have some experience in one or preferably both. If a suitable candidate is not identified for GSoC, we will postpone the project; the current maintainers do not currently have the time to execute this project ourselves.

To ensure that the project is well-considered before beginning, I have marked this issue with "rfc"; community input, especially from Rust maintainers who have previously interacted with our code, will considerably support any candidate picking this up will be suitably prepared for potential problems along the way. We believe that, written well, such a tool would be useful for many organisations using component-based Rust codebases.

To contact us, please send an email to [email protected]

addisoncrump avatar Jan 20 '25 12:01 addisoncrump

Historically, we had considered doing this incrementally -- by progressively deleting bounds and attempting recompilation in a very-low optimisation mode -- but mutual recursion (or, really, dependency cycles in general) makes this potentially ineffective in some cases. As a "first effort", this probably would be worth trying.

There is another case we would like to solve as well, e.g.:

trait Trait1 {}
trait Trait2 {}

trait Trait3: Trait1 + Trait2 {}

fn thing<A: Trait3>() {...}

If the bound A: Trait3 is not necessary, but Trait2 is, then we would want to replace the trait with its constituent requirements, then continue. But this makes the process once again rather complicated...

addisoncrump avatar Jan 20 '25 13:01 addisoncrump

I am interested in solving this problem ,I have mailed you about my progress.Can you check it and guide me further

Gulshan1-3 avatar Jan 29 '25 08:01 Gulshan1-3

Hey @Gulshan1-3, thanks for letting us know. We aren't currently asking for work to be completed on this, and anything completed in advance will not be considered for the application process as a matter of fairness.

While extracting the traits and lifetime data (like your examples in the email you sent show) will be necessary, this is one of potentially many steps necessary to accomplish this. Again, out of fairness, we will not be supervising any progress before the application and acceptance process is complete.

addisoncrump avatar Jan 29 '25 14:01 addisoncrump

Can I work on it on my own though as you wont be able to help I am thinking of figuring out things on my own n proceed further, thanks for replying

Gulshan1-3 avatar Jan 29 '25 14:01 Gulshan1-3

Of course. We will likely host conversations here about our preferred design, which may diverge from yours quite a bit by the time the application process completes.

addisoncrump avatar Jan 29 '25 14:01 addisoncrump

Thanks for the help, have a great day!! @addisoncrump

Gulshan1-3 avatar Jan 29 '25 14:01 Gulshan1-3

https://blog.guillaume-gomez.fr/articles/2024-01-18+Writing+your+own+Rust+linter

https://github.com/rust-lang/rust-clippy/pull/10632/files#diff-5429e5f64cae893e6384da197605dc8bfbe85f93e495c15eb4b2717ef9594d63

this two should be a good start

tokatoka avatar Mar 03 '25 17:03 tokatoka

Just a thought, but would this functionality be useful more widely than just the LibAFL project? Could it apply to other projects also? Is it worth considering whether additional rules could be added to clippy to help detect some of these issues?

WorksButNotTested avatar Mar 04 '25 13:03 WorksButNotTested

Could it apply to other projects also?

Yes, I think absolutely. This would serve as a demo and prototypical implementation, and we can organise a proper RFC for clippy later. I suspect that a project like this might also just need to be standalone, since it will likely have fairly major computational requirements compared to existing clippy lints.

addisoncrump avatar Mar 04 '25 13:03 addisoncrump

Would using chalk for static analysis (at least partly) be acceptable? My main concerns are that this is not really a "library" for general use, and I don't have much idea about the future of this project, i.e., whether chalk would be deprecated after integration into rustc or if it would break too often since it is still in development (as far as I know), etc.

dhanvithnayak avatar Mar 13 '25 16:03 dhanvithnayak

Hi @addisoncrump @tokatoka 👋

I'm interested in applying for GSoC 2025 and this proposal on simplifying generics and bounds in Rust really caught my attention.

I've been learning Rust and working with procedural macros and trait bounds, and I'd love to contribute to this idea.

Would it be okay if I shared a draft proposal with you or asked a few questions about the expectations for this project?

Thanks in advance! Sayyad Farhan Haider Rizvi

Farhanhaider11 avatar Apr 08 '25 18:04 Farhanhaider11

The application period is already over

tokatoka avatar Apr 08 '25 18:04 tokatoka

Just to be clear, the GSoC application period was not communicated here but was made available by Google here: https://opensource.googleblog.com/2025/03/google-summer-of-code-2025-contributor.html

Sadly, your notice came just one day after this deadline @Farhanhaider11, so we can't accept it for GSoC. If this issue is not completed during GSoC and you'd otherwise like to contribute, then we would happily welcome your contribution.

addisoncrump avatar Apr 11 '25 05:04 addisoncrump