Skip to content

Commit 781fb53

Browse files
authored
Merge pull request #8719 from MegaMek/fix/academy-curriculum-index-bounds-check
Fix IndexOutOfBoundsException in Academy.getTooltip() for mismatched curriculum data (Sentry)
2 parents 6e0beee + 5472ce0 commit 781fb53

File tree

2 files changed

+33
-0
lines changed

2 files changed

+33
-0
lines changed

MekHQ/src/mekhq/campaign/personnel/education/Academy.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,26 @@ public List<Integer> getQualificationStartYears() {
549549
return qualificationStartYears;
550550
}
551551

552+
/**
553+
* Validates that the parallel lists (qualifications, curriculums, qualificationStartYears) have matching sizes.
554+
* Logs a warning if they don't match.
555+
*
556+
* @return true if lists are valid (same size or all null/empty), false if mismatched
557+
*/
558+
public boolean validateListSizes() {
559+
int qualCount = (qualifications == null) ? 0 : qualifications.size();
560+
int currCount = (curriculums == null) ? 0 : curriculums.size();
561+
int yearCount = (qualificationStartYears == null) ? 0 : qualificationStartYears.size();
562+
563+
if (qualCount != currCount || qualCount != yearCount) {
564+
LOGGER.warn("Academy '{}' has mismatched list sizes: qualifications={}, curriculums={}, startYears={}. "
565+
+ "This may cause errors when viewing course tooltips.",
566+
name, qualCount, currCount, yearCount);
567+
return false;
568+
}
569+
return true;
570+
}
571+
552572
/**
553573
* Retrieves the base skill level granted by this academy.
554574
*
@@ -812,6 +832,13 @@ public String getTooltip(Campaign campaign, List<Person> personnel, int courseIn
812832
MekHQ.getMHQOptions().getLocale());
813833

814834
try {
835+
// Bounds check: ensure courseIndex is valid for curriculums list
836+
if (curriculums == null || courseIndex < 0 || courseIndex >= curriculums.size()) {
837+
LOGGER.error("Invalid courseIndex {} for academy '{}' with {} curriculums",
838+
courseIndex, name, curriculums == null ? 0 : curriculums.size());
839+
return "<html><body style='width: 200px'><i>Error: Invalid course data</i></body></html>";
840+
}
841+
815842
StringBuilder tooltip = new StringBuilder().append("<html><body style='width: 200px'>");
816843
tooltip.append("<i>").append(description).append("</i><br><br>");
817844
tooltip.append("<b>").append(resources.getString("curriculum.text")).append("</b><br>");

MekHQ/src/mekhq/campaign/personnel/education/AcademyFactory.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@ public void loadAcademyFromStream(InputStream inputStream, String fileName) {
140140
academy.setId(id);
141141
id++;
142142
academy.setSet(currentSetName);
143+
// Validate that parallel lists have matching sizes, skip invalid academies
144+
if (!academy.validateListSizes()) {
145+
LOGGER.warn("Skipping academy '{}' in set '{}' from file '{}' due to invalid list sizes.",
146+
academy.getName(), currentSetName, fileName);
147+
continue;
148+
}
143149
tempAcademyMap.put(academy.getName(), academy);
144150
}
145151
academyMap.put(currentSetName, tempAcademyMap);

0 commit comments

Comments
 (0)