From 9d5fccd68c80291fe02b9ab9872d5cacfdba3c89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ngh=C4=A9a=20Nguy=E1=BB=85n=20Ng=E1=BB=8Dc?= Date: Sat, 9 May 2026 13:47:49 +0700 Subject: [PATCH 1/2] fix: validate that step does not exceed field range in getRange A step value larger than the field's own range (e.g. */90 in minutes where max=59) would silently accept the expression and schedule the job only at the range minimum, hiding a likely user error. Add a validation check after the step is parsed: if step > r.max-r.min { return 0, fmt.Errorf("step (%d) above maximum (%d): ...", ...) } This mirrors the existing checks for start/end bounds and returns a clear error rather than silently mis-scheduling. Add two test cases to TestStandardSpecSchedule exercising the new validation for the minute and hour fields. Fixes #543 --- parser.go | 3 +++ parser_test.go | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/parser.go b/parser.go index 8da6547a..9a294fba 100644 --- a/parser.go +++ b/parser.go @@ -313,6 +313,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 } diff --git a/parser_test.go b/parser_test.go index 41c8c520..8d48a46b 100644 --- a/parser_test.go +++ b/parser_test.go @@ -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 { From cd6aede619903796adf79fc2c9f6e73fee26426e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ngh=C4=A9a=20Nguy=E1=BB=85n=20Ng=E1=BB=8Dc?= Date: Sat, 9 May 2026 15:09:01 +0700 Subject: [PATCH 2/2] parser: return error instead of panic when TZ prefix has no fields When spec is 'TZ=' with no trailing schedule fields, Index(' ') returns -1 and the slice expression spec[eq+1 : -1] panics. Add an explicit check: if there is no space separator after the timezone prefix, return a descriptive error immediately. Fixes #554 --- parser.go | 3 +++ parser_test.go | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/parser.go b/parser.go index 9a294fba..910bd019 100644 --- a/parser.go +++ b/parser.go @@ -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) diff --git a/parser_test.go b/parser_test.go index 8d48a46b..b97b9b3c 100644 --- a/parser_test.go +++ b/parser_test.go @@ -374,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} }