Affects: 5.2.5-RELEASE
and probably others as well
CronSequenceGenerator.next()
throws a StackOverflowError
for certain particular combinations of cron pattern, time zone, and date.
This is 100% reproducible, but I have not yet figured out exactly what is going on. Originally I saw the bug happen in production but could not reproduce it, so I wrote a test program to try zillions of combinations and it quickly identified the one below as an example.
One thing that is interesting is it won't happen if the time zone is GMT, or if you change the */3
to a */2
.
Test program:
import java.util.Date;
import java.util.TimeZone;
import org.springframework.scheduling.support.CronSequenceGenerator;
public class CronBug {
public static void main(String[] args) throws Exception {
final String pattern = "* * */3 * * *";
final TimeZone timeZone = TimeZone.getTimeZone("America/Chicago");
final CronSequenceGenerator generator = new CronSequenceGenerator(pattern, timeZone);
final Date date = new Date(3225083777139L);
try {
generator.next(date);
System.err.println("SUCCESS");
} catch (StackOverflowError e) {
System.err.println("STACK OVERFLOW");
}
}
}
Expected output:
SUCCESS
Actual output:
STACK OVERFLOW
Aside: Could this explain the StackOverflowError
reported in bug #12463 after it was supposedly fixed?
Also:
$ java -version
openjdk version "1.8.0_282"
OpenJDK Runtime Environment (IcedTea 3.18.0) (build 1.8.0_282-b07 suse-lp152.2.9.1-x86_64)
OpenJDK 64-Bit Server VM (build 25.282-b08, mixed mode)
Comment From: archiecobbs
I just realized that the date new Date(3225083777139L) = Sun Mar 13 02:36:17 CST 2072
is within the DST springtime transition hour. That shouldn't matter of course but it may be a clue to the underlying problem.
Here's another date that triggers the bug but that is not within the DST transition hour (but is very close to it): new Date(2183614779812L) = Sun Mar 13 01:39:39 CST 2039
.
Comment From: archiecobbs
Here's another variant that is not related to DST:
import java.util.Date;
import java.util.TimeZone;
import org.springframework.scheduling.support.CronSequenceGenerator;
public class CronBug {
public static void main(String[] args) throws Exception {
final String pattern = "0 0 6 25 DEC SAT";
final TimeZone timeZone = TimeZone.getTimeZone("UTC");
final CronSequenceGenerator generator = new CronSequenceGenerator(pattern, timeZone);
final Date date = new Date(1308425503952L); // Sat Jun 18 19:31:43 UTC 2011
try {
generator.next(date);
System.err.println("SUCCESS");
} catch (StackOverflowError e) {
System.err.println("STACK OVERFLOW");
}
}
}
Expected output:
SUCCESS
Actual output:
Exception in thread "main" java.lang.IllegalArgumentException: Invalid cron expression "0 0 6 25 DEC SAT" led to runaway search for next trigger
at org.springframework.scheduling.support.CronSequenceGenerator.doNext(CronSequenceGenerator.java:201)
at org.springframework.scheduling.support.CronSequenceGenerator.doNext(CronSequenceGenerator.java:184)
at org.springframework.scheduling.support.CronSequenceGenerator.doNext(CronSequenceGenerator.java:194)
at org.springframework.scheduling.support.CronSequenceGenerator.doNext(CronSequenceGenerator.java:184)
at org.springframework.scheduling.support.CronSequenceGenerator.doNext(CronSequenceGenerator.java:204)
at org.springframework.scheduling.support.CronSequenceGenerator.doNext(CronSequenceGenerator.java:184)
at org.springframework.scheduling.support.CronSequenceGenerator.doNext(CronSequenceGenerator.java:194)
at org.springframework.scheduling.support.CronSequenceGenerator.doNext(CronSequenceGenerator.java:184)
at org.springframework.scheduling.support.CronSequenceGenerator.doNext(CronSequenceGenerator.java:204)
at org.springframework.scheduling.support.CronSequenceGenerator.doNext(CronSequenceGenerator.java:184)
at org.springframework.scheduling.support.CronSequenceGenerator.doNext(CronSequenceGenerator.java:194)
at org.springframework.scheduling.support.CronSequenceGenerator.doNext(CronSequenceGenerator.java:184)
at org.springframework.scheduling.support.CronSequenceGenerator.doNext(CronSequenceGenerator.java:204)
at org.springframework.scheduling.support.CronSequenceGenerator.doNext(CronSequenceGenerator.java:184)
at org.springframework.scheduling.support.CronSequenceGenerator.doNext(CronSequenceGenerator.java:194)
at org.springframework.scheduling.support.CronSequenceGenerator.doNext(CronSequenceGenerator.java:184)
at org.springframework.scheduling.support.CronSequenceGenerator.doNext(CronSequenceGenerator.java:204)
at org.springframework.scheduling.support.CronSequenceGenerator.doNext(CronSequenceGenerator.java:184)
at org.springframework.scheduling.support.CronSequenceGenerator.doNext(CronSequenceGenerator.java:194)
at org.springframework.scheduling.support.CronSequenceGenerator.doNext(CronSequenceGenerator.java:184)
at org.springframework.scheduling.support.CronSequenceGenerator.doNext(CronSequenceGenerator.java:204)
at org.springframework.scheduling.support.CronSequenceGenerator.doNext(CronSequenceGenerator.java:184)
at org.springframework.scheduling.support.CronSequenceGenerator.doNext(CronSequenceGenerator.java:194)
at org.springframework.scheduling.support.CronSequenceGenerator.doNext(CronSequenceGenerator.java:184)
at org.springframework.scheduling.support.CronSequenceGenerator.doNext(CronSequenceGenerator.java:175)
at org.springframework.scheduling.support.CronSequenceGenerator.next(CronSequenceGenerator.java:148)
at CronBug.main(CronBug.java:12)
Is "At 6am on every Christmas that falls on a Saturday" really not a valid cron expression?
Comment From: poutsma
As of Spring Framework 5.3, we have deprecated CronSequenceGenerator
, and replaced it with CronExpression
.
When running the sample patterns and test dates you provided, I did not run into any problems with CronExpression
. For instance, the following code runs fine:
String pattern = "0 0 6 25 DEC SAT";
Instant instant = Instant.ofEpochMilli(1308425503952L); // // Sat Jun 18 19:31:43 UTC 2011
ZonedDateTime dateTime = ZonedDateTime.ofInstant(instant, ZoneId.of("UTC"));
CronExpression expression = CronExpression.parse(pattern);
ZonedDateTime result = expression.next(dateTime);
System.out.println(result);
and prints out: 2021-12-25T06:00Z[UTC]
.
Comment From: archiecobbs
Awesome, thanks for having already fixed this :)
Comment From: viniciusao
As of Spring Framework 5.3, we have deprecated
CronSequenceGenerator
, and replaced it withCronExpression
.When running the sample patterns and test dates you provided, I did not run into any problems with
CronExpression
. For instance, the following code runs fine:
String pattern = "0 0 6 25 DEC SAT"; Instant instant = Instant.ofEpochMilli(1308425503952L); // // Sat Jun 18 19:31:43 UTC 2011 ZonedDateTime dateTime = ZonedDateTime.ofInstant(instant, ZoneId.of("UTC")); CronExpression expression = CronExpression.parse(pattern); ZonedDateTime result = expression.next(dateTime); System.out.println(result);
and prints out:
2021-12-25T06:00Z[UTC]
.
Is there some workaround for those who can't upgrade spring?