Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ func (p Parser) Parse(spec string) (Schedule, error) {
if strings.HasPrefix(spec, "TZ=") || strings.HasPrefix(spec, "CRON_TZ=") {
var err error
i := strings.Index(spec, " ")
if i < 0 {
return nil, fmt.Errorf("timezone prefix missing schedule fields: %v", spec)
}
eq := strings.Index(spec, "=")
if loc, err = time.LoadLocation(spec[eq+1 : i]); err != nil {
return nil, fmt.Errorf("provided bad location %s: %v", spec[eq+1:i], err)
Expand Down Expand Up @@ -313,6 +316,9 @@ func getRange(expr string, r bounds) (uint64, error) {
if step == 0 {
return 0, fmt.Errorf("step of range should be a positive number: %s", expr)
}
if step > r.max-r.min {
return 0, fmt.Errorf("step (%d) above maximum (%d): %s", step, r.max-r.min, expr)
}

return getBits(start, end, step) | extra, nil
}
Expand Down
24 changes: 24 additions & 0 deletions parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,18 @@ func TestStandardSpecSchedule(t *testing.T) {
expr: "* * * *",
err: "expected exactly 5 fields",
},
{
// Step value larger than the field range should be rejected.
// */90 in the minute field (range 0-59) would only ever fire at
// minute 0, silently ignoring the intent. See issue #543.
expr: "*/90 * * * *",
err: "step (90) above maximum (59)",
},
{
// Same check for hours: */30 is the max valid step (0-23 → range 23).
expr: "* */30 * * *",
err: "step (30) above maximum (23)",
},
}

for _, c := range entries {
Expand Down Expand Up @@ -362,6 +374,18 @@ func every5min(loc *time.Location) *SpecSchedule {
return &SpecSchedule{1 << 0, 1 << 5, all(hours), all(dom), all(months), all(dow), loc}
}

// TestParseTZMissingFields verifies that a TZ/CRON_TZ prefix with no
// trailing schedule fields returns an error rather than panicking with a
// slice-bounds-out-of-range crash. See GitHub issue #554.
func TestParseTZMissingFields(t *testing.T) {
cases := []string{"TZ=0", "TZ=UTC", "CRON_TZ=America/New_York"}
for _, spec := range cases {
if _, err := ParseStandard(spec); err == nil {
t.Errorf("ParseStandard(%q): expected error for missing schedule fields, got nil", spec)
}
}
}

func every5min5s(loc *time.Location) *SpecSchedule {
return &SpecSchedule{1 << 5, 1 << 5, all(hours), all(dom), all(months), all(dow), loc}
}
Expand Down