Skip to content

LLM found bugs #380

Description

@elharo

Bug Analysis: maven-help-plugin

These were all pulled out by throwing the code at an LLM. This issue lists multiple independent bugs. If anyone wants to work on any of these, note it here and open a new issue just for that bug. Be careful that some of these are likely false reports, though closing those is also useful work.

All 26 unit tests pass. Below are bugs found by code inspection, ordered by severity.


HIGH Severity

1. EffectivePomMojo.cleanModel() mutates the live project's Model in-place

File: src/main/java/org/apache/maven/plugins/help/EffectivePomMojo.java:210-213

private static void cleanModel(Model pom) {
    Properties properties = new SortedProperties();
    properties.putAll(pom.getProperties());
    pom.setProperties(properties);
}

Called from writeEffectivePom() at line 182 on project.getModel(). This permanently replaces the project's Properties with a SortedProperties instance, altering property iteration order for the remainder of the build. This is a data corruption side effect in what should be a read-only display operation.

2. EffectiveSettingsMojo mutates the original Settings object when showPasswords=true

File: src/main/java/org/apache/maven/plugins/help/EffectiveSettingsMojo.java:87-94

if (showPasswords) {
    copySettings = settings;  // uses original, not a copy
} else {
    copySettings = copySettings(settings);
}
writeEffectiveSettings(copySettings, writer); // calls cleanSettings() which modifies profiles

When -DshowPasswords=true, the original Maven Settings object is used directly. writeEffectiveSettingscleanSettings() then replaces each profile's Properties with a SortedProperties instance (same pattern as bug #1), mutating the global shared settings object.

3. DescribeMojo.lookupPluginDescriptor() error message references null mojo fields instead of PluginInfo

File: src/main/java/org/apache/maven/plugins/help/DescribeMojo.java:333-338

throw new MojoExecutionException(
    "Error retrieving plugin descriptor for:" + LS + LS + "groupId: '"
        + groupId + "'" + LS + "artifactId: '" + artifactId + "'" + LS + "version: '" + version + "'" + LS + LS, e);

When the plugin was specified by prefix (e.g., -Dplugin=help), the mojo fields groupId, artifactId, version are all null. The method parameter PluginInfo pi contains the actual values but the error message ignores them. Output: groupId: 'null'\nartifactId: 'null'\nversion: 'null' — misleading and unhelpful for debugging.


MEDIUM Severity

4. AllProfilesMojo.addProjectPomProfiles() uses parent build context for active profiles

File: src/main/java/org/apache/maven/plugins/help/AllProfilesMojo.java:153-156

if (project.getActiveProfiles() != null) {
    for (Profile profile : project.getActiveProfiles()) {
        activeProfiles.put(profile.getId(), profile);
    }
}
project = project.getParent();  // walks up to parent

When the loop reaches a parent POM, project.getActiveProfiles() returns profiles active in the parent's build context. These may not be active for the child project (different JDK, OS, properties). The output can incorrectly mark parent profiles as active when they do not apply to the child.

5. EffectiveSettingsMojo.copySettings() does not deep-copy profiles

File: src/main/java/org/apache/maven/plugins/help/EffectiveSettingsMojo.java:156-198

Only servers and proxies are manually deep-copied. The profiles list is shared with the original via the shallow SettingsUtils.copySettings(). Profiles can contain sensitive data (passwords in properties) that would be exposed if the original settings object is later queried expecting the copy to be isolated.

6. ListDependencyTypesMojo, ListLifecyclePhasesMojo, ListPackagingMojo write to console AND file simultaneously

Files:

  • ListDependencyTypesMojo.java:95-96
  • ListLifecyclePhasesMojo.java:76-77
  • ListPackagingMojo.java:110-111
getLog().info(LS + "Maven Dependency Types defined:" + LS + LS + descriptionBuffer);
writeFile(output, descriptionBuffer);  // always called, even when output is null

These three mojos always log to console AND unconditionally call writeFile(output, ...) (no-op when null). Every other mojo uses if (output != null) { ... } else { getLog().info(...); }. The dual-write means content is always printed to console even when writing to file. They also do not prepend the "Generated by Maven Help Plugin" header that ActiveProfilesMojo and SystemMojo add.


LOW Severity

7. DescribeMojo.toLines() delegates to generated HelpMojo via fragile reflection

File: src/main/java/org/apache/maven/plugins/help/DescribeMojo.java:747-778

Method m = HelpMojo.class.getDeclaredMethod("toLines", String.class, Integer.TYPE, Integer.TYPE, Integer.TYPE);
m.setAccessible(true);
List<String> output = (List<String>) m.invoke(HelpMojo.class, text, indent, indentSize, lineLength);

HelpMojo is generated by maven-plugin-tools at compile time (in target/generated-sources/). It IS available at runtime, but this reflection is brittle: any change in the generated code's toLines signature silently breaks all describe output formatting. The HelpMojo.toLines internally calls repeat() with new StringBuilder(repeat * str.length()) — a classic integer overflow risk that can throw NegativeArraySizeException.

8. AbstractHelpMojo.LS uses System.getProperty("line.separator")

File: src/main/java/org/apache/maven/plugins/help/AbstractHelpMojo.java:55

protected static final String LS = System.getProperty("line.separator");

Should use System.lineSeparator() (Java 7+), which falls back to "\n" if the property is missing. DescribeMojoTest inconsistently uses both System.getProperty("line.separator") (line 88) and System.lineSeparator() (line 110).

9. SortedProperties uses raw types

File: src/main/java/org/apache/maven/plugins/help/AbstractEffectiveMojo.java:147-148

List list = new ArrayList(keynames);
Collections.sort(list);

The @SuppressWarnings({"rawtypes", "unchecked"}) annotation masks the issue rather than using List<Object>.

10. AbstractHelpMojo.getAetherArtifact() uses deprecated Artifact.LATEST_VERSION

File: src/main/java/org/apache/maven/plugins/help/AbstractHelpMojo.java:147

version = Artifact.LATEST_VERSION;

Deprecated in favor of null (which means "latest") in the Aether API.

11. EffectivePomMojo encoding fallback can return null

File: src/main/java/org/apache/maven/plugins/help/EffectivePomMojo.java:110

String encoding = output != null ? project.getModel().getModelEncoding() : System.getProperty("file.encoding");

System.getProperty("file.encoding") can theoretically return null.

12. AllProfilesMojo — settings profiles never tracked for active status

File: src/main/java/org/apache/maven/plugins/help/AllProfilesMojo.java:167-173

private void addSettingsProfiles(Map<String, Profile> allProfiles) {
    for (org.apache.maven.settings.Profile settingsProfile : settingsProfiles) {
        Profile profile = SettingsUtils.convertFromSettingsProfile(settingsProfile);
        allProfiles.put(profile.getId(), profile);
    }
}

addSettingsProfiles() only populates allProfilesByIds, never activeProfilesByIds. Active detection relies on project.getActiveProfiles() which may or may not include converted settings profiles depending on Maven version and activation mechanisms. This can under-report active settings profiles.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions