Skip to content

GH-39149: [C++][Compute] Fix replace_substring hang on empty pattern - #55442

Open
novain-shibu wants to merge 1 commit into
apache:mainfrom
novain-shibu:GH-39149-empty-pattern
Open

novain-shibu wants to merge 1 commit into
apache:mainfrom
novain-shibu:GH-39149-empty-pattern

Conversation

@novain-shibu

Copy link
Copy Markdown

Rationale for this change

replace_substring with an empty pattern never returns. With an empty pattern, the search matches at the current position, the cursor advances by the pattern length (0), and with the default unlimited max_replacements the loop appends the replacement forever. Memory grows until the process is killed (about 100 MB/s on a one-element array). This still happens on main.

replace_substring_regex has a related hang: with a pattern that can match empty text and a negative max_replacements other than -1 (for example -3), the counter never reaches 0 and the position doesn't advance.

pandas worked around the first case on its side (pandas-dev/pandas#64941, pandas-dev/pandas#65147).

What changes are included in this PR?

  • replace_substring: return Invalid when the pattern is empty. This follows the suggestion in GH-39149: [C++] replace_substring_regex hangs indefinitely for negative max_replacements #39264 to start with an error, since other systems disagree on the expected result: Python, Java and R's gsub insert the replacement at every position, Postgres leaves the string unchanged, and stringr raises.
  • replace_substring_regex: treat any negative max_replacements as unlimited, using the existing global-replace path that -1 already takes.
  • Tests for both cases.

Are these changes tested?

Yes. New cases in scalar_string_test.cc. On a Linux Release build of main (7299fdc):

  • arrow-compute-scalar-type-test: 361/361 pass before and after the change
  • *ReplaceSubstring*: 12/12 pass with the change
  • with the new tests but the old kernel, the run hangs at the first empty-pattern case (killed after 240 s)

Are there any user-facing changes?

Yes. replace_substring with an empty pattern now raises ArrowInvalid. Before, it hung with unlimited replacements, and with a positive max_replacements it returned the replacement repeated at the start (for example "-ab"). Negative max_replacements other than -1 in replace_substring_regex now behaves like -1 instead of hanging.

This PR contains a "Critical Fix". The empty-pattern case loops forever and allocates memory without bound, which can bring down the process.

Was AI used for this PR?

In accordance to the AI generation guidelines, please disclose below whether and how AI was used in this PR.

PR code and description written by:

  • Human
  • AI

Reviewed before submission by:

  • Human
  • AI
  • Not reviewed

…ttern

Return Invalid for an empty pattern in replace_substring, and treat any
negative max_replacements as unlimited in replace_substring_regex.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 8, 2026

Copy link
Copy Markdown

⚠️ GitHub issue #39149 has been automatically assigned in GitHub to PR creator.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants