Skip to content

Commit 2b8b524

Browse files
authored
[#11346] [#11348] Fix NPE/array OOB in logs and OOM in session published email cron job (#11349)
* Add branches to cater for exceptions with no stack trace and logs with no source * Add time limit when querying sessions to be sent published email
1 parent 993139e commit 2b8b524

File tree

9 files changed

+42
-24
lines changed

9 files changed

+42
-24
lines changed

src/main/appengine/index.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,11 @@ indexes:
3535
name: isPublishedEmailEnabled
3636
- direction: asc
3737
name: sentPublishedEmail
38+
- kind: FeedbackSession
39+
properties:
40+
- direction: asc
41+
name: isPublishedEmailEnabled
42+
- direction: asc
43+
name: sentPublishedEmail
44+
- direction: asc
45+
name: resultsVisibleFromTime

src/main/java/teammates/common/util/Logger.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -141,17 +141,21 @@ public void severe(String message, Throwable t) {
141141
}
142142

143143
private String getLogMessageWithStackTrace(String message, Throwable t, LogSeverity severity) {
144-
String logMessage;
145144
if (Config.isDevServer()) {
146145
StringWriter sw = new StringWriter();
147146
try (PrintWriter pw = new PrintWriter(sw)) {
148147
t.printStackTrace(pw);
149148
}
150149

151-
logMessage = formatLogMessageForHumanDisplay(message) + " stack_trace: "
150+
return formatLogMessageForHumanDisplay(message) + " stack_trace: "
152151
+ System.lineSeparator() + sw.toString();
153-
} else {
154-
StackTraceElement tSource = t.getStackTrace()[0];
152+
}
153+
154+
StackTraceElement[] stackTraces = t.getStackTrace();
155+
Map<String, Object> payload = getBaseCloudLoggingPayload(message, severity);
156+
157+
if (stackTraces.length > 0) {
158+
StackTraceElement tSource = stackTraces[0];
155159
SourceLocation tSourceLocation = new SourceLocation(
156160
tSource.getClassName(), (long) tSource.getLineNumber(), tSource.getMethodName());
157161

@@ -168,8 +172,6 @@ private String getLogMessageWithStackTrace(String message, Throwable t, LogSever
168172
currentT = currentT.getCause();
169173
}
170174

171-
Map<String, Object> payload = getBaseCloudLoggingPayload(message, severity);
172-
173175
// Replace the source location with the Throwable's source location instead
174176
SourceLocation loggerSourceLocation = (SourceLocation) payload.get("logging.googleapis.com/sourceLocation");
175177
payload.put("logging.googleapis.com/sourceLocation", tSourceLocation);
@@ -184,11 +186,9 @@ private String getLogMessageWithStackTrace(String message, Throwable t, LogSever
184186
Map<String, Object> detailsSpecificPayload =
185187
JsonUtils.fromJson(JsonUtils.toCompactJson(details), new TypeToken<Map<String, Object>>(){}.getType());
186188
payload.putAll(detailsSpecificPayload);
187-
188-
logMessage = JsonUtils.toCompactJson(payload);
189189
}
190190

191-
return logMessage;
191+
return JsonUtils.toCompactJson(payload);
192192
}
193193

194194
private List<String> getStackTraceToDisplay(Throwable t) {

src/main/java/teammates/logic/core/GoogleCloudLoggingService.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,17 @@ public QueryLogsResults queryLogs(QueryLogsParams queryLogsParams) throws LogSer
155155
Payload<?> payload = entry.getPayload();
156156
long timestamp = entry.getTimestamp();
157157

158+
String file = "";
159+
Long line = 0L;
160+
String function = "";
161+
if (sourceLocation != null) {
162+
file = sourceLocation.getFile();
163+
line = sourceLocation.getLine();
164+
function = sourceLocation.getFunction();
165+
}
166+
158167
GeneralLogEntry logEntry = new GeneralLogEntry(convertSeverity(severity), trace, insertId,
159-
resourceIdentifier, new SourceLocation(sourceLocation.getFile(),
160-
sourceLocation.getLine(), sourceLocation.getFunction()), timestamp);
168+
resourceIdentifier, new SourceLocation(file, line, function), timestamp);
161169
if (payload.getType() == Payload.Type.JSON) {
162170
Map<String, Object> jsonPayloadMap = ((Payload.JsonPayload) payload).getDataAsMap();
163171
logEntry.setDetails(JsonUtils.fromJson(JsonUtils.toCompactJson(jsonPayloadMap), LogDetails.class));

src/main/java/teammates/storage/api/FeedbackSessionsDb.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ private List<FeedbackSession> getFeedbackSessionEntitiesPossiblyNeedingClosedEma
376376

377377
private List<FeedbackSession> getFeedbackSessionEntitiesPossiblyNeedingPublishedEmail() {
378378
return load()
379+
.filter("resultsVisibleFromTime >", TimeHelper.getInstantDaysOffsetFromNow(-2))
379380
.filter("sentPublishedEmail =", false)
380381
.filter("isPublishedEmailEnabled =", true)
381382
.list();

src/main/java/teammates/storage/entity/FeedbackSession.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ public class FeedbackSession extends BaseEntity {
5252
@Translate(InstantTranslatorFactory.class)
5353
private Instant sessionVisibleFromTime;
5454

55-
@Unindex
5655
@Translate(InstantTranslatorFactory.class)
5756
private Instant resultsVisibleFromTime;
5857

src/test/java/teammates/storage/api/FeedbackSessionsDbTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ public void testGetFeedbackSessionsPossiblyNeedingPublishedEmail() throws Except
385385

386386
List<FeedbackSessionAttributes> fsaList = fsDb.getFeedbackSessionsPossiblyNeedingPublishedEmail();
387387

388-
assertEquals(11, fsaList.size());
388+
assertEquals(8, fsaList.size());
389389
for (FeedbackSessionAttributes fsa : fsaList) {
390390
assertFalse(fsa.isSentPublishedEmail());
391391
assertTrue(fsa.isPublishedEmailEnabled());
@@ -399,7 +399,7 @@ public void testGetFeedbackSessionsPossiblyNeedingPublishedEmail() throws Except
399399
fsDb.softDeleteFeedbackSession(feedbackSession.getFeedbackSessionName(), feedbackSession.getCourseId());
400400

401401
fsaList = fsDb.getFeedbackSessionsPossiblyNeedingPublishedEmail();
402-
assertEquals(10, fsaList.size());
402+
assertEquals(7, fsaList.size());
403403
}
404404

405405
@Test

src/test/java/teammates/storage/search/StudentSearchTest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package teammates.storage.search;
22

3-
import java.util.ArrayList;
43
import java.util.Arrays;
4+
import java.util.Collections;
55
import java.util.List;
66

77
import org.testng.annotations.Test;
@@ -141,8 +141,10 @@ public void testSearchStudents_noSearchService_shouldThrowException() {
141141
return;
142142
}
143143

144+
List<InstructorAttributes> ins1OfCourse1 = Collections.singletonList(
145+
dataBundle.instructors.get("instructor1OfCourse1"));
144146
assertThrows(SearchServiceException.class,
145-
() -> studentsDb.search("anything", new ArrayList<>()));
147+
() -> studentsDb.search("anything", ins1OfCourse1));
146148
assertThrows(SearchServiceException.class,
147149
() -> studentsDb.searchStudentsInWholeSystem("anything"));
148150
}

src/test/java/teammates/ui/webapi/FeedbackSessionPublishedRemindersActionTest.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ protected void testAccessControl() {
3232
@Test
3333
public void testExecute() throws Exception {
3434

35-
______TS("default state of typical data bundle: 1 session published with email unsent");
35+
______TS("default state of typical data bundle: no sessions needing published email");
3636

3737
FeedbackSessionPublishedRemindersAction action = getAction();
3838
action.execute();
3939

40-
verifySpecifiedTasksAdded(Const.TaskQueue.FEEDBACK_SESSION_PUBLISHED_EMAIL_QUEUE_NAME, 2);
40+
verifyNoTasksAdded();
4141

4242
______TS("1 session published by moving automated publish time, "
4343
+ "1 session published similarly with disabled published reminder, "
@@ -84,7 +84,7 @@ public void testExecute() throws Exception {
8484
action = getAction();
8585
action.execute();
8686

87-
verifySpecifiedTasksAdded(Const.TaskQueue.FEEDBACK_SESSION_PUBLISHED_EMAIL_QUEUE_NAME, 4);
87+
verifySpecifiedTasksAdded(Const.TaskQueue.FEEDBACK_SESSION_PUBLISHED_EMAIL_QUEUE_NAME, 2);
8888

8989
______TS("1 session unpublished manually");
9090

@@ -93,7 +93,7 @@ public void testExecute() throws Exception {
9393
action = getAction();
9494
action.execute();
9595

96-
verifySpecifiedTasksAdded(Const.TaskQueue.FEEDBACK_SESSION_PUBLISHED_EMAIL_QUEUE_NAME, 3);
96+
verifySpecifiedTasksAdded(Const.TaskQueue.FEEDBACK_SESSION_PUBLISHED_EMAIL_QUEUE_NAME, 1);
9797

9898
______TS("1 session published with emails sent");
9999

@@ -107,7 +107,7 @@ public void testExecute() throws Exception {
107107
action = getAction();
108108
action.execute();
109109

110-
verifySpecifiedTasksAdded(Const.TaskQueue.FEEDBACK_SESSION_PUBLISHED_EMAIL_QUEUE_NAME, 2);
110+
verifyNoTasksAdded();
111111

112112
}
113113

src/test/resources/emails/sessionReminderEmailForInstructorNotJoinedYet.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
<ul>
5555
<li>
5656
<strong>To submit, edit or view your feedback for the above session, please go to this Web address: </strong>
57-
<a href="http://localhost:4200/web/instructor/sessions/submission?courseid=idOfTypicalCourse1&fsname=First%20feedback%20session">http://localhost:4200/web/instructor/sessions/submission?courseid=idOfTypicalCourse1&fsname=First%20feedback%20session</a>
57+
<a href="${app.url}/web/instructor/sessions/submission?courseid=idOfTypicalCourse1&fsname=First%20feedback%20session">${app.url}/web/instructor/sessions/submission?courseid=idOfTypicalCourse1&fsname=First%20feedback%20session</a>
5858
</li>
5959
<li>
6060
The above link is unique to you. Please do not share it with others.
@@ -75,7 +75,7 @@
7575
<p>=====</p>
7676
<p>
7777
<strong>To "join" the course, please go to this Web address: </strong>
78-
<a href="http://localhost:4200/web/join?key=${regkey.enc}&entitytype=instructor">http://localhost:4200/web/join?key=${regkey.enc}&entitytype=instructor</a>
78+
<a href="${app.url}/web/join?key=${regkey.enc}&entitytype=instructor">${app.url}/web/join?key=${regkey.enc}&entitytype=instructor</a>
7979
<ul>
8080
<li>
8181
If prompted to log in, use your Google account to log in.
@@ -97,7 +97,7 @@
9797
</li>
9898
<li>
9999
<strong>Technical help regarding TEAMMATES</strong> (e.g. submission link is not working):
100-
Email TEAMMATES support team at app_admin@gmail.com.
100+
Email TEAMMATES support team at ${support.email}.
101101
</li>
102102
</ul>
103103
</p>

0 commit comments

Comments
 (0)