Skip to content

fix(pkg/cast): avoid panic on trailing quote - #4124

Open
zjncs wants to merge 1 commit into
lf-edge:masterfrom
zjncs:fix-convertformat-trailing-quote
Open

zjncs wants to merge 1 commit into
lf-edge:masterfrom
zjncs:fix-convertformat-trailing-quote

Conversation

@zjncs

@zjncs zjncs commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Description

A time format string ending with a single quote made convertFormat panic:

convertFormat("yyyy'")
panic: runtime error: index out of range [5] with length 5

convertFormat is the converter behind format_time(now(), fmt) (the format argument is a user string literal) and the SQL sink's datetime format option, so a malformed format string currently crashes the rule instead of producing an error.

Root cause

In the quote case of pkg/cast/time.go, the real-quote lookahead reads formatRune[i+1] without checking i+1 < lenFormat:

case '\'': // ' (text delimiter)  or '' (real quote)
    // real quote
    if formatRune[i+1] == r {   // panics when the quote is the last rune

Every other case in the function bounds-checks its lookahead (i+j < lenFormat); only this one does not. When the quote is the last character of the format, i+1 is out of range.

Changes

  • Add the missing i+1 < lenFormat bound check. A trailing single quote now falls through to the text-delimiter branch and is consumed as an unterminated delimiter — the same lenient behavior the function already applies to unterminated quotes in the middle of a format (e.g. "yyyy'abc""2006abc", matching Java SimpleDateFormat semantics this converter mimics).
  • Extend TestConvertFormat with quote cases: trailing quote (no panic, consumed), quoted text 'day 'yyyy, escaped quote yyyy'', and unterminated mid-format quote.

How has this been tested?

Fail-before / pass-after (master @ 7a27fb5):

$ go test ./pkg/cast/ -run TestConvertFormat -count=1
# before fix:
--- FAIL: TestConvertFormat (0.00s)
panic: runtime error: index out of range [5] with length 5
# after fix:
ok      github.com/lf-edge/ekuiper/v2/pkg/cast

Full package after the fix:

$ go test ./pkg/cast/... -count=1
ok      github.com/lf-edge/ekuiper/v2/pkg/cast

go vet ./pkg/cast/ and go fmt clean.

Behavior change

None for valid formats. A format ending in a single quote changes from panic to being treated like any other unterminated quote (consumed), instead of crashing the calling rule.

AI assistance disclosure

This change was prepared with the assistance of an AI coding agent; the bug, reproduction, fix, and test were all verified locally by me as described above.

A time format ending with a single quote, such as "yyyy'", made
convertFormat read formatRune[i+1] past the end of the slice and panic.
Bounds-check the real-quote lookahead like the other cases; a trailing
quote is then consumed as an unterminated text delimiter, consistent
with the existing lenient handling of unterminated quotes mid-format.

Signed-off-by: zjncs <18910855655@163.com>
@zjncs
zjncs marked this pull request as ready for review September 4, 2026 12:13
Copilot AI lite review requested due to automatic review settings September 4, 2026 12:13

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@codecov

codecov Bot commented Sep 7, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 70.93%. Comparing base (7a27fb5) to head (7e4ec4f).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #4124      +/-   ##
==========================================
+ Coverage   70.89%   70.93%   +0.05%     
==========================================
  Files         471      471              
  Lines       55430    55430              
==========================================
+ Hits        39292    39318      +26     
+ Misses      13101    13084      -17     
+ Partials     3037     3028       -9     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ngjaying ngjaying left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for fixing the out-of-bounds panic. The bounds check itself looks correct, but I think the resulting behavior for unmatched quotes should be changed before merge.

convertFormat already returns an error, and both ParseTime and FormatTime propagate that error. Instead of silently accepting malformed formats such as yyyy' as 2006 or yyyy'abc as 2006abc, please return an error for an unterminated quote.

That would fix the panic while preserving invalid-format detection for callers.

Suggested test expectations:

  • yyyy' → error
  • yyyy'abc → error
  • 'day 'yyyyday 2006
  • yyyy''2006'

Also, the PR description says this lenient behavior matches Java SimpleDateFormat semantics, but SimpleDateFormat treats an unterminated quote as an invalid pattern rather than silently consuming it.

Non-blocking: doubled quotes inside quoted text, for example 'o''clock', also appear worth checking separately, but that does not need to be part of this fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants