GH-36388: [C++][Python] Return error from MakeArrayFromScalar on offset overflow - #50024

Open
Sriniketh24 wants to merge 3 commits into
apache:mainfrom
Sriniketh24:fix/repeat-offset-overflow
Open

GH-36388: [C++][Python] Return error from MakeArrayFromScalar on offset overflow#50024
Sriniketh24 wants to merge 3 commits into
apache:mainfrom
Sriniketh24:fix/repeat-offset-overflow

Conversation

@Sriniketh24

@Sriniketh24Sriniketh24 commented May 23, 2026

Copy link
Copy Markdown

Rationale

pyarrow.repeat (backed by MakeArrayFromScalar in C++) silently created an invalid array with negative offsets when the total data size (value_size * repetition_count) exceeded INT32_MAX for 32-bit offset types (StringType, BinaryType). The resulting array passed creation without error but failed validation with a cryptic "Negative offsets in binary array" or "non-monotonic offset" message.

What changed

Added an early overflow check in RepeatedArrayFactory::CreateOffsetsBuffer that computes the total data size in int64_t and returns Status::Invalid with an actionable error message when it would exceed the offset type's maximum. The error message suggests using large_* types (e.g. large_string, large_binary) for data exceeding 2 GB.

Are these changes tested?

Yes.

  • C++ test: TestMakeArrayFromScalarOffsetOverflow in array_test.cc — tests string, binary, and large_string scalars
  • Python test: test_repeat_offset_overflow in test_array.py — verifies pa.repeat raises ArrowInvalid on overflow

Are there any user-facing changes?

Yes. MakeArrayFromScalar (and pyarrow.repeat) now raises ArrowInvalid early with a clear error message instead of silently returning a corrupt array. This is a strictly better user experience.

Closes: #36388


This is AI-assisted work by Claude.

…n offset overflow
MakeArrayFromScalar silently created an invalid array with negative
offsets when the total data size (value_size * repetition_count)
exceeded the maximum value of the offset type. For 32-bit offset types
like StringType and BinaryType, this threshold is INT32_MAX (~2 GB).
The root cause was in CreateOffsetsBuffer where the running offset
accumulated via OffsetType addition without checking for overflow,
wrapping around to negative values.
Added an early overflow check in CreateOffsetsBuffer that computes the
total size in int64_t and compares against the offset type's maximum.
On overflow, a Status::Invalid error is returned with a message
suggesting the use of large_* types.
This is AI-assisted work by Claude.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses GH-36388 by preventing MakeArrayFromScalar (and therefore pyarrow.repeat) from silently constructing invalid binary/string arrays when the repeated total byte size would exceed the maximum representable value of 32-bit offsets, returning an Invalid status with a clearer error instead.

Changes:

  • Added an offset overflow check in RepeatedArrayFactory::CreateOffsetsBuffer for variable-size offset types.
  • Added a C++ regression test covering string/binary offset overflow cases.
  • Added a Python regression test verifying pa.repeat raises ArrowInvalid on overflow.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

FileDescription
python/pyarrow/tests/test_array.pyAdds Python coverage ensuring pa.repeat raises on 32-bit offset overflow.
cpp/src/arrow/array/util.ccIntroduces early offset overflow detection when creating offsets for repeated variable-size values.
cpp/src/arrow/array/array_test.ccAdds a C++ regression test for MakeArrayFromScalar offset overflow behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadcpp/src/arrow/array/util.cc Outdated
Comment on lines +860 to +864
if (value_length > 0 && length_ > 0) {
int64_t total_size = static_cast<int64_t>(value_length) * length_;
if (total_size > static_cast<int64_t>(std::numeric_limits<OffsetType>::max())) {
return Status::Invalid(
"Cannot create array: total data size (", total_size,
Comment threadcpp/src/arrow/array/util.cc Outdated
Comment on lines +856 to +860
// Check that the total data size does not overflow the offset type.
// For 32-bit offset types (e.g. StringType, BinaryType), value_length * length_
// must fit in int32_t, otherwise the offsets wrap around and produce an invalid
// array with negative offsets.
if (value_length > 0 && length_ > 0) {

@AlenkaFAlenkaF left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@Sriniketh24 I think it would be worth looking at the work already done in #38504 and continue from there.

… length checks
Per @AlenkaF's suggestion to build on the approach from apache#38504:
- Replace the manual int64_t multiplication (which could itself silently
overflow for 64-bit offset types like large_string/large_binary) with
arrow::internal::MultiplyWithOverflow, which is correct for both 32-bit
and 64-bit OffsetType.
- Reject length > numeric_limits<OffsetType>::max() up front, independent
of value size (e.g. an empty string repeated too many times).
- Reject negative length in MakeArrayFromScalar itself.
- Add C++ test cases for the length-exceeds-offset-type and negative-length
paths, on top of the existing overflow tests and the Python-level
pa.repeat() regression test.
Credit to @llama90's work in apache#38504, which reviewer @js8544 had already
validated this approach on before it went stale.
@Sriniketh24

Copy link
Copy Markdown
Author

Hi @AlenkaF — thanks for the pointer to #38504, that was a good approach that just ran out of the original author's time (credit to @llama90 for the initial work, and @js8544 for reviewing it there).

Reworked this PR to build on that approach:

Note: I wasn't able to run the full C++ test suite in my local environment (no existing build directory / ninja), so I only syntax-checked the changed file directly against the local headers (clean, no errors). CI here will be the real validation — flagging that up front rather than claiming more confidence than I have.

@AlenkaF

Copy link
Copy Markdown
Member

Could you have a look at this comment from the linked PR: #38504 (comment) and let me know what you think of the suggestion?

Note: I wasn't able to run the full C++ test suite in my local environment (no existing build directory / ninja), so I only syntax-checked the changed file directly against the local headers (clean, no errors). CI here will be the real validation — flagging that up front rather than claiming more confidence than I have.

And please, don't use agents to communicate with us. It is OK to use the tools for development provided you understand the changes. Also, you could point your agent to the development docs so it can help with building from source and testing: https://arrow.apache.org/docs/developers/python/building.html#build-pyarrow.

Per @bkietz's review on apache#38504 (discussion_r1394400239): checking
length_ alone against OffsetType::max() is wrong, since it rejects
valid cases like an empty string repeated more than OffsetType::max()
times (total data size stays 0, so it can never actually overflow).
Only the product value_length * length_ needs to fit in OffsetType.
Compute that product in int64_t and compare against OffsetType::max()
directly, exactly as bkietz suggested.
Moved the two cases that need multi-GB allocations to succeed (as
opposed to fail-fast) into a separate LARGE_MEMORY_TEST-gated test,
matching the convention used elsewhere in this file (see table_test.cc).
@Sriniketh24

Copy link
Copy Markdown
Author

Thanks for the pointer @AlenkaF — that discussion was exactly the missing piece. @bkietz caught a real bug in the approach I'd pushed: checking length_ alone against OffsetType::max() is a false positive — an empty string repeated more than int32::max() times is perfectly valid (every offset stays 0), so that check would have incorrectly rejected it.

Applied bkietz's suggested fix directly: compute value_length * length_ in int64_t and compare the product against OffsetType::max(), rather than checking either operand individually.

Also added the boundary tests js8544 asked for (empty string at length > int32::max, and "aa" at exactly int32::max/2) — these need multi-GB allocations to actually succeed rather than fail-fast, so I gated them behind LARGE_MEMORY_TEST like the rest of the codebase does (e.g. table_test.cc) rather than adding that cost to every CI run.

Local syntax check (now with gmock available) is clean on both files.

Sign up for freeto 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.

[Python][C++] pyarrow.repeat returns an invalid array when a chunked array is required.

3 participants

@Sriniketh24@AlenkaF
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks"); } } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); } })(); (function(){ try { var __m = "github.com"; var __re = new RegExp('^' + "github\\.com" + '
Skip to content

GH-36388: [C++][Python] Return error from MakeArrayFromScalar on offset overflow - #50024

Open
Sriniketh24 wants to merge 3 commits into
apache:mainfrom
Sriniketh24:fix/repeat-offset-overflow
Open

GH-36388: [C++][Python] Return error from MakeArrayFromScalar on offset overflow#50024
Sriniketh24 wants to merge 3 commits into
apache:mainfrom
Sriniketh24:fix/repeat-offset-overflow

Conversation

@Sriniketh24

@Sriniketh24Sriniketh24 commented May 23, 2026

Copy link
Copy Markdown

Rationale

pyarrow.repeat (backed by MakeArrayFromScalar in C++) silently created an invalid array with negative offsets when the total data size (value_size * repetition_count) exceeded INT32_MAX for 32-bit offset types (StringType, BinaryType). The resulting array passed creation without error but failed validation with a cryptic "Negative offsets in binary array" or "non-monotonic offset" message.

What changed

Added an early overflow check in RepeatedArrayFactory::CreateOffsetsBuffer that computes the total data size in int64_t and returns Status::Invalid with an actionable error message when it would exceed the offset type's maximum. The error message suggests using large_* types (e.g. large_string, large_binary) for data exceeding 2 GB.

Are these changes tested?

Yes.

  • C++ test: TestMakeArrayFromScalarOffsetOverflow in array_test.cc — tests string, binary, and large_string scalars
  • Python test: test_repeat_offset_overflow in test_array.py — verifies pa.repeat raises ArrowInvalid on overflow

Are there any user-facing changes?

Yes. MakeArrayFromScalar (and pyarrow.repeat) now raises ArrowInvalid early with a clear error message instead of silently returning a corrupt array. This is a strictly better user experience.

Closes: #36388


This is AI-assisted work by Claude.

…n offset overflow
MakeArrayFromScalar silently created an invalid array with negative
offsets when the total data size (value_size * repetition_count)
exceeded the maximum value of the offset type. For 32-bit offset types
like StringType and BinaryType, this threshold is INT32_MAX (~2 GB).
The root cause was in CreateOffsetsBuffer where the running offset
accumulated via OffsetType addition without checking for overflow,
wrapping around to negative values.
Added an early overflow check in CreateOffsetsBuffer that computes the
total size in int64_t and compares against the offset type's maximum.
On overflow, a Status::Invalid error is returned with a message
suggesting the use of large_* types.
This is AI-assisted work by Claude.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses GH-36388 by preventing MakeArrayFromScalar (and therefore pyarrow.repeat) from silently constructing invalid binary/string arrays when the repeated total byte size would exceed the maximum representable value of 32-bit offsets, returning an Invalid status with a clearer error instead.

Changes:

  • Added an offset overflow check in RepeatedArrayFactory::CreateOffsetsBuffer for variable-size offset types.
  • Added a C++ regression test covering string/binary offset overflow cases.
  • Added a Python regression test verifying pa.repeat raises ArrowInvalid on overflow.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

FileDescription
python/pyarrow/tests/test_array.pyAdds Python coverage ensuring pa.repeat raises on 32-bit offset overflow.
cpp/src/arrow/array/util.ccIntroduces early offset overflow detection when creating offsets for repeated variable-size values.
cpp/src/arrow/array/array_test.ccAdds a C++ regression test for MakeArrayFromScalar offset overflow behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadcpp/src/arrow/array/util.cc Outdated
Comment on lines +860 to +864
if (value_length > 0 && length_ > 0) {
int64_t total_size = static_cast<int64_t>(value_length) * length_;
if (total_size > static_cast<int64_t>(std::numeric_limits<OffsetType>::max())) {
return Status::Invalid(
"Cannot create array: total data size (", total_size,
Comment threadcpp/src/arrow/array/util.cc Outdated
Comment on lines +856 to +860
// Check that the total data size does not overflow the offset type.
// For 32-bit offset types (e.g. StringType, BinaryType), value_length * length_
// must fit in int32_t, otherwise the offsets wrap around and produce an invalid
// array with negative offsets.
if (value_length > 0 && length_ > 0) {

@AlenkaFAlenkaF left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@Sriniketh24 I think it would be worth looking at the work already done in #38504 and continue from there.

… length checks
Per @AlenkaF's suggestion to build on the approach from apache#38504:
- Replace the manual int64_t multiplication (which could itself silently
overflow for 64-bit offset types like large_string/large_binary) with
arrow::internal::MultiplyWithOverflow, which is correct for both 32-bit
and 64-bit OffsetType.
- Reject length > numeric_limits<OffsetType>::max() up front, independent
of value size (e.g. an empty string repeated too many times).
- Reject negative length in MakeArrayFromScalar itself.
- Add C++ test cases for the length-exceeds-offset-type and negative-length
paths, on top of the existing overflow tests and the Python-level
pa.repeat() regression test.
Credit to @llama90's work in apache#38504, which reviewer @js8544 had already
validated this approach on before it went stale.
@Sriniketh24

Copy link
Copy Markdown
Author

Hi @AlenkaF — thanks for the pointer to #38504, that was a good approach that just ran out of the original author's time (credit to @llama90 for the initial work, and @js8544 for reviewing it there).

Reworked this PR to build on that approach:

Note: I wasn't able to run the full C++ test suite in my local environment (no existing build directory / ninja), so I only syntax-checked the changed file directly against the local headers (clean, no errors). CI here will be the real validation — flagging that up front rather than claiming more confidence than I have.

@AlenkaF

Copy link
Copy Markdown
Member

Could you have a look at this comment from the linked PR: #38504 (comment) and let me know what you think of the suggestion?

Note: I wasn't able to run the full C++ test suite in my local environment (no existing build directory / ninja), so I only syntax-checked the changed file directly against the local headers (clean, no errors). CI here will be the real validation — flagging that up front rather than claiming more confidence than I have.

And please, don't use agents to communicate with us. It is OK to use the tools for development provided you understand the changes. Also, you could point your agent to the development docs so it can help with building from source and testing: https://arrow.apache.org/docs/developers/python/building.html#build-pyarrow.

Per @bkietz's review on apache#38504 (discussion_r1394400239): checking
length_ alone against OffsetType::max() is wrong, since it rejects
valid cases like an empty string repeated more than OffsetType::max()
times (total data size stays 0, so it can never actually overflow).
Only the product value_length * length_ needs to fit in OffsetType.
Compute that product in int64_t and compare against OffsetType::max()
directly, exactly as bkietz suggested.
Moved the two cases that need multi-GB allocations to succeed (as
opposed to fail-fast) into a separate LARGE_MEMORY_TEST-gated test,
matching the convention used elsewhere in this file (see table_test.cc).
@Sriniketh24

Copy link
Copy Markdown
Author

Thanks for the pointer @AlenkaF — that discussion was exactly the missing piece. @bkietz caught a real bug in the approach I'd pushed: checking length_ alone against OffsetType::max() is a false positive — an empty string repeated more than int32::max() times is perfectly valid (every offset stays 0), so that check would have incorrectly rejected it.

Applied bkietz's suggested fix directly: compute value_length * length_ in int64_t and compare the product against OffsetType::max(), rather than checking either operand individually.

Also added the boundary tests js8544 asked for (empty string at length > int32::max, and "aa" at exactly int32::max/2) — these need multi-GB allocations to actually succeed rather than fail-fast, so I gated them behind LARGE_MEMORY_TEST like the rest of the codebase does (e.g. table_test.cc) rather than adding that cost to every CI run.

Local syntax check (now with gmock available) is clean on both files.

Sign up for freeto 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.

[Python][C++] pyarrow.repeat returns an invalid array when a chunked array is required.

3 participants

@Sriniketh24@AlenkaF
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

GH-36388: [C++][Python] Return error from MakeArrayFromScalar on offset overflow - #50024

Open
Sriniketh24 wants to merge 3 commits into
apache:mainfrom
Sriniketh24:fix/repeat-offset-overflow
Open

GH-36388: [C++][Python] Return error from MakeArrayFromScalar on offset overflow#50024
Sriniketh24 wants to merge 3 commits into
apache:mainfrom
Sriniketh24:fix/repeat-offset-overflow

Conversation

@Sriniketh24

@Sriniketh24Sriniketh24 commented May 23, 2026

Copy link
Copy Markdown

Rationale

pyarrow.repeat (backed by MakeArrayFromScalar in C++) silently created an invalid array with negative offsets when the total data size (value_size * repetition_count) exceeded INT32_MAX for 32-bit offset types (StringType, BinaryType). The resulting array passed creation without error but failed validation with a cryptic "Negative offsets in binary array" or "non-monotonic offset" message.

What changed

Added an early overflow check in RepeatedArrayFactory::CreateOffsetsBuffer that computes the total data size in int64_t and returns Status::Invalid with an actionable error message when it would exceed the offset type's maximum. The error message suggests using large_* types (e.g. large_string, large_binary) for data exceeding 2 GB.

Are these changes tested?

Yes.

  • C++ test: TestMakeArrayFromScalarOffsetOverflow in array_test.cc — tests string, binary, and large_string scalars
  • Python test: test_repeat_offset_overflow in test_array.py — verifies pa.repeat raises ArrowInvalid on overflow

Are there any user-facing changes?

Yes. MakeArrayFromScalar (and pyarrow.repeat) now raises ArrowInvalid early with a clear error message instead of silently returning a corrupt array. This is a strictly better user experience.

Closes: #36388


This is AI-assisted work by Claude.

…n offset overflow
MakeArrayFromScalar silently created an invalid array with negative
offsets when the total data size (value_size * repetition_count)
exceeded the maximum value of the offset type. For 32-bit offset types
like StringType and BinaryType, this threshold is INT32_MAX (~2 GB).
The root cause was in CreateOffsetsBuffer where the running offset
accumulated via OffsetType addition without checking for overflow,
wrapping around to negative values.
Added an early overflow check in CreateOffsetsBuffer that computes the
total size in int64_t and compares against the offset type's maximum.
On overflow, a Status::Invalid error is returned with a message
suggesting the use of large_* types.
This is AI-assisted work by Claude.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses GH-36388 by preventing MakeArrayFromScalar (and therefore pyarrow.repeat) from silently constructing invalid binary/string arrays when the repeated total byte size would exceed the maximum representable value of 32-bit offsets, returning an Invalid status with a clearer error instead.

Changes:

  • Added an offset overflow check in RepeatedArrayFactory::CreateOffsetsBuffer for variable-size offset types.
  • Added a C++ regression test covering string/binary offset overflow cases.
  • Added a Python regression test verifying pa.repeat raises ArrowInvalid on overflow.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

FileDescription
python/pyarrow/tests/test_array.pyAdds Python coverage ensuring pa.repeat raises on 32-bit offset overflow.
cpp/src/arrow/array/util.ccIntroduces early offset overflow detection when creating offsets for repeated variable-size values.
cpp/src/arrow/array/array_test.ccAdds a C++ regression test for MakeArrayFromScalar offset overflow behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadcpp/src/arrow/array/util.cc Outdated
Comment on lines +860 to +864
if (value_length > 0 && length_ > 0) {
int64_t total_size = static_cast<int64_t>(value_length) * length_;
if (total_size > static_cast<int64_t>(std::numeric_limits<OffsetType>::max())) {
return Status::Invalid(
"Cannot create array: total data size (", total_size,
Comment threadcpp/src/arrow/array/util.cc Outdated
Comment on lines +856 to +860
// Check that the total data size does not overflow the offset type.
// For 32-bit offset types (e.g. StringType, BinaryType), value_length * length_
// must fit in int32_t, otherwise the offsets wrap around and produce an invalid
// array with negative offsets.
if (value_length > 0 && length_ > 0) {

@AlenkaFAlenkaF left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@Sriniketh24 I think it would be worth looking at the work already done in #38504 and continue from there.

… length checks
Per @AlenkaF's suggestion to build on the approach from apache#38504:
- Replace the manual int64_t multiplication (which could itself silently
overflow for 64-bit offset types like large_string/large_binary) with
arrow::internal::MultiplyWithOverflow, which is correct for both 32-bit
and 64-bit OffsetType.
- Reject length > numeric_limits<OffsetType>::max() up front, independent
of value size (e.g. an empty string repeated too many times).
- Reject negative length in MakeArrayFromScalar itself.
- Add C++ test cases for the length-exceeds-offset-type and negative-length
paths, on top of the existing overflow tests and the Python-level
pa.repeat() regression test.
Credit to @llama90's work in apache#38504, which reviewer @js8544 had already
validated this approach on before it went stale.
@Sriniketh24

Copy link
Copy Markdown
Author

Hi @AlenkaF — thanks for the pointer to #38504, that was a good approach that just ran out of the original author's time (credit to @llama90 for the initial work, and @js8544 for reviewing it there).

Reworked this PR to build on that approach:

Note: I wasn't able to run the full C++ test suite in my local environment (no existing build directory / ninja), so I only syntax-checked the changed file directly against the local headers (clean, no errors). CI here will be the real validation — flagging that up front rather than claiming more confidence than I have.

@AlenkaF

Copy link
Copy Markdown
Member

Could you have a look at this comment from the linked PR: #38504 (comment) and let me know what you think of the suggestion?

Note: I wasn't able to run the full C++ test suite in my local environment (no existing build directory / ninja), so I only syntax-checked the changed file directly against the local headers (clean, no errors). CI here will be the real validation — flagging that up front rather than claiming more confidence than I have.

And please, don't use agents to communicate with us. It is OK to use the tools for development provided you understand the changes. Also, you could point your agent to the development docs so it can help with building from source and testing: https://arrow.apache.org/docs/developers/python/building.html#build-pyarrow.

Per @bkietz's review on apache#38504 (discussion_r1394400239): checking
length_ alone against OffsetType::max() is wrong, since it rejects
valid cases like an empty string repeated more than OffsetType::max()
times (total data size stays 0, so it can never actually overflow).
Only the product value_length * length_ needs to fit in OffsetType.
Compute that product in int64_t and compare against OffsetType::max()
directly, exactly as bkietz suggested.
Moved the two cases that need multi-GB allocations to succeed (as
opposed to fail-fast) into a separate LARGE_MEMORY_TEST-gated test,
matching the convention used elsewhere in this file (see table_test.cc).
@Sriniketh24

Copy link
Copy Markdown
Author

Thanks for the pointer @AlenkaF — that discussion was exactly the missing piece. @bkietz caught a real bug in the approach I'd pushed: checking length_ alone against OffsetType::max() is a false positive — an empty string repeated more than int32::max() times is perfectly valid (every offset stays 0), so that check would have incorrectly rejected it.

Applied bkietz's suggested fix directly: compute value_length * length_ in int64_t and compare the product against OffsetType::max(), rather than checking either operand individually.

Also added the boundary tests js8544 asked for (empty string at length > int32::max, and "aa" at exactly int32::max/2) — these need multi-GB allocations to actually succeed rather than fail-fast, so I gated them behind LARGE_MEMORY_TEST like the rest of the codebase does (e.g. table_test.cc) rather than adding that cost to every CI run.

Local syntax check (now with gmock available) is clean on both files.

Sign up for freeto 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.

[Python][C++] pyarrow.repeat returns an invalid array when a chunked array is required.

3 participants

@Sriniketh24@AlenkaF
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length \u003e 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

GH-36388: [C++][Python] Return error from MakeArrayFromScalar on offset overflow - #50024

Open
Sriniketh24 wants to merge 3 commits into
apache:mainfrom
Sriniketh24:fix/repeat-offset-overflow
Open

GH-36388: [C++][Python] Return error from MakeArrayFromScalar on offset overflow#50024
Sriniketh24 wants to merge 3 commits into
apache:mainfrom
Sriniketh24:fix/repeat-offset-overflow

Conversation

@Sriniketh24

@Sriniketh24Sriniketh24 commented May 23, 2026

Copy link
Copy Markdown

Rationale

pyarrow.repeat (backed by MakeArrayFromScalar in C++) silently created an invalid array with negative offsets when the total data size (value_size * repetition_count) exceeded INT32_MAX for 32-bit offset types (StringType, BinaryType). The resulting array passed creation without error but failed validation with a cryptic "Negative offsets in binary array" or "non-monotonic offset" message.

What changed

Added an early overflow check in RepeatedArrayFactory::CreateOffsetsBuffer that computes the total data size in int64_t and returns Status::Invalid with an actionable error message when it would exceed the offset type's maximum. The error message suggests using large_* types (e.g. large_string, large_binary) for data exceeding 2 GB.

Are these changes tested?

Yes.

  • C++ test: TestMakeArrayFromScalarOffsetOverflow in array_test.cc — tests string, binary, and large_string scalars
  • Python test: test_repeat_offset_overflow in test_array.py — verifies pa.repeat raises ArrowInvalid on overflow

Are there any user-facing changes?

Yes. MakeArrayFromScalar (and pyarrow.repeat) now raises ArrowInvalid early with a clear error message instead of silently returning a corrupt array. This is a strictly better user experience.

Closes: #36388


This is AI-assisted work by Claude.

…n offset overflow
MakeArrayFromScalar silently created an invalid array with negative
offsets when the total data size (value_size * repetition_count)
exceeded the maximum value of the offset type. For 32-bit offset types
like StringType and BinaryType, this threshold is INT32_MAX (~2 GB).
The root cause was in CreateOffsetsBuffer where the running offset
accumulated via OffsetType addition without checking for overflow,
wrapping around to negative values.
Added an early overflow check in CreateOffsetsBuffer that computes the
total size in int64_t and compares against the offset type's maximum.
On overflow, a Status::Invalid error is returned with a message
suggesting the use of large_* types.
This is AI-assisted work by Claude.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses GH-36388 by preventing MakeArrayFromScalar (and therefore pyarrow.repeat) from silently constructing invalid binary/string arrays when the repeated total byte size would exceed the maximum representable value of 32-bit offsets, returning an Invalid status with a clearer error instead.

Changes:

  • Added an offset overflow check in RepeatedArrayFactory::CreateOffsetsBuffer for variable-size offset types.
  • Added a C++ regression test covering string/binary offset overflow cases.
  • Added a Python regression test verifying pa.repeat raises ArrowInvalid on overflow.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

FileDescription
python/pyarrow/tests/test_array.pyAdds Python coverage ensuring pa.repeat raises on 32-bit offset overflow.
cpp/src/arrow/array/util.ccIntroduces early offset overflow detection when creating offsets for repeated variable-size values.
cpp/src/arrow/array/array_test.ccAdds a C++ regression test for MakeArrayFromScalar offset overflow behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadcpp/src/arrow/array/util.cc Outdated
Comment on lines +860 to +864
if (value_length > 0 && length_ > 0) {
int64_t total_size = static_cast<int64_t>(value_length) * length_;
if (total_size > static_cast<int64_t>(std::numeric_limits<OffsetType>::max())) {
return Status::Invalid(
"Cannot create array: total data size (", total_size,
Comment threadcpp/src/arrow/array/util.cc Outdated
Comment on lines +856 to +860
// Check that the total data size does not overflow the offset type.
// For 32-bit offset types (e.g. StringType, BinaryType), value_length * length_
// must fit in int32_t, otherwise the offsets wrap around and produce an invalid
// array with negative offsets.
if (value_length > 0 && length_ > 0) {

@AlenkaFAlenkaF left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@Sriniketh24 I think it would be worth looking at the work already done in #38504 and continue from there.

… length checks
Per @AlenkaF's suggestion to build on the approach from apache#38504:
- Replace the manual int64_t multiplication (which could itself silently
overflow for 64-bit offset types like large_string/large_binary) with
arrow::internal::MultiplyWithOverflow, which is correct for both 32-bit
and 64-bit OffsetType.
- Reject length > numeric_limits<OffsetType>::max() up front, independent
of value size (e.g. an empty string repeated too many times).
- Reject negative length in MakeArrayFromScalar itself.
- Add C++ test cases for the length-exceeds-offset-type and negative-length
paths, on top of the existing overflow tests and the Python-level
pa.repeat() regression test.
Credit to @llama90's work in apache#38504, which reviewer @js8544 had already
validated this approach on before it went stale.
@Sriniketh24

Copy link
Copy Markdown
Author

Hi @AlenkaF — thanks for the pointer to #38504, that was a good approach that just ran out of the original author's time (credit to @llama90 for the initial work, and @js8544 for reviewing it there).

Reworked this PR to build on that approach:

Note: I wasn't able to run the full C++ test suite in my local environment (no existing build directory / ninja), so I only syntax-checked the changed file directly against the local headers (clean, no errors). CI here will be the real validation — flagging that up front rather than claiming more confidence than I have.

@AlenkaF

Copy link
Copy Markdown
Member

Could you have a look at this comment from the linked PR: #38504 (comment) and let me know what you think of the suggestion?

Note: I wasn't able to run the full C++ test suite in my local environment (no existing build directory / ninja), so I only syntax-checked the changed file directly against the local headers (clean, no errors). CI here will be the real validation — flagging that up front rather than claiming more confidence than I have.

And please, don't use agents to communicate with us. It is OK to use the tools for development provided you understand the changes. Also, you could point your agent to the development docs so it can help with building from source and testing: https://arrow.apache.org/docs/developers/python/building.html#build-pyarrow.

Per @bkietz's review on apache#38504 (discussion_r1394400239): checking
length_ alone against OffsetType::max() is wrong, since it rejects
valid cases like an empty string repeated more than OffsetType::max()
times (total data size stays 0, so it can never actually overflow).
Only the product value_length * length_ needs to fit in OffsetType.
Compute that product in int64_t and compare against OffsetType::max()
directly, exactly as bkietz suggested.
Moved the two cases that need multi-GB allocations to succeed (as
opposed to fail-fast) into a separate LARGE_MEMORY_TEST-gated test,
matching the convention used elsewhere in this file (see table_test.cc).
@Sriniketh24

Copy link
Copy Markdown
Author

Thanks for the pointer @AlenkaF — that discussion was exactly the missing piece. @bkietz caught a real bug in the approach I'd pushed: checking length_ alone against OffsetType::max() is a false positive — an empty string repeated more than int32::max() times is perfectly valid (every offset stays 0), so that check would have incorrectly rejected it.

Applied bkietz's suggested fix directly: compute value_length * length_ in int64_t and compare the product against OffsetType::max(), rather than checking either operand individually.

Also added the boundary tests js8544 asked for (empty string at length > int32::max, and "aa" at exactly int32::max/2) — these need multi-GB allocations to actually succeed rather than fail-fast, so I gated them behind LARGE_MEMORY_TEST like the rest of the codebase does (e.g. table_test.cc) rather than adding that cost to every CI run.

Local syntax check (now with gmock available) is clean on both files.

Sign up for freeto 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.

[Python][C++] pyarrow.repeat returns an invalid array when a chunked array is required.

3 participants

@Sriniketh24@AlenkaF
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

GH-36388: [C++][Python] Return error from MakeArrayFromScalar on offset overflow - #50024

Open
Sriniketh24 wants to merge 3 commits into
apache:mainfrom
Sriniketh24:fix/repeat-offset-overflow
Open

GH-36388: [C++][Python] Return error from MakeArrayFromScalar on offset overflow#50024
Sriniketh24 wants to merge 3 commits into
apache:mainfrom
Sriniketh24:fix/repeat-offset-overflow

Conversation

@Sriniketh24

@Sriniketh24Sriniketh24 commented May 23, 2026

Copy link
Copy Markdown

Rationale

pyarrow.repeat (backed by MakeArrayFromScalar in C++) silently created an invalid array with negative offsets when the total data size (value_size * repetition_count) exceeded INT32_MAX for 32-bit offset types (StringType, BinaryType). The resulting array passed creation without error but failed validation with a cryptic "Negative offsets in binary array" or "non-monotonic offset" message.

What changed

Added an early overflow check in RepeatedArrayFactory::CreateOffsetsBuffer that computes the total data size in int64_t and returns Status::Invalid with an actionable error message when it would exceed the offset type's maximum. The error message suggests using large_* types (e.g. large_string, large_binary) for data exceeding 2 GB.

Are these changes tested?

Yes.

  • C++ test: TestMakeArrayFromScalarOffsetOverflow in array_test.cc — tests string, binary, and large_string scalars
  • Python test: test_repeat_offset_overflow in test_array.py — verifies pa.repeat raises ArrowInvalid on overflow

Are there any user-facing changes?

Yes. MakeArrayFromScalar (and pyarrow.repeat) now raises ArrowInvalid early with a clear error message instead of silently returning a corrupt array. This is a strictly better user experience.

Closes: #36388


This is AI-assisted work by Claude.

…n offset overflow
MakeArrayFromScalar silently created an invalid array with negative
offsets when the total data size (value_size * repetition_count)
exceeded the maximum value of the offset type. For 32-bit offset types
like StringType and BinaryType, this threshold is INT32_MAX (~2 GB).
The root cause was in CreateOffsetsBuffer where the running offset
accumulated via OffsetType addition without checking for overflow,
wrapping around to negative values.
Added an early overflow check in CreateOffsetsBuffer that computes the
total size in int64_t and compares against the offset type's maximum.
On overflow, a Status::Invalid error is returned with a message
suggesting the use of large_* types.
This is AI-assisted work by Claude.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses GH-36388 by preventing MakeArrayFromScalar (and therefore pyarrow.repeat) from silently constructing invalid binary/string arrays when the repeated total byte size would exceed the maximum representable value of 32-bit offsets, returning an Invalid status with a clearer error instead.

Changes:

  • Added an offset overflow check in RepeatedArrayFactory::CreateOffsetsBuffer for variable-size offset types.
  • Added a C++ regression test covering string/binary offset overflow cases.
  • Added a Python regression test verifying pa.repeat raises ArrowInvalid on overflow.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

FileDescription
python/pyarrow/tests/test_array.pyAdds Python coverage ensuring pa.repeat raises on 32-bit offset overflow.
cpp/src/arrow/array/util.ccIntroduces early offset overflow detection when creating offsets for repeated variable-size values.
cpp/src/arrow/array/array_test.ccAdds a C++ regression test for MakeArrayFromScalar offset overflow behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadcpp/src/arrow/array/util.cc Outdated
Comment on lines +860 to +864
if (value_length > 0 && length_ > 0) {
int64_t total_size = static_cast<int64_t>(value_length) * length_;
if (total_size > static_cast<int64_t>(std::numeric_limits<OffsetType>::max())) {
return Status::Invalid(
"Cannot create array: total data size (", total_size,
Comment threadcpp/src/arrow/array/util.cc Outdated
Comment on lines +856 to +860
// Check that the total data size does not overflow the offset type.
// For 32-bit offset types (e.g. StringType, BinaryType), value_length * length_
// must fit in int32_t, otherwise the offsets wrap around and produce an invalid
// array with negative offsets.
if (value_length > 0 && length_ > 0) {

@AlenkaFAlenkaF left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@Sriniketh24 I think it would be worth looking at the work already done in #38504 and continue from there.

… length checks
Per @AlenkaF's suggestion to build on the approach from apache#38504:
- Replace the manual int64_t multiplication (which could itself silently
overflow for 64-bit offset types like large_string/large_binary) with
arrow::internal::MultiplyWithOverflow, which is correct for both 32-bit
and 64-bit OffsetType.
- Reject length > numeric_limits<OffsetType>::max() up front, independent
of value size (e.g. an empty string repeated too many times).
- Reject negative length in MakeArrayFromScalar itself.
- Add C++ test cases for the length-exceeds-offset-type and negative-length
paths, on top of the existing overflow tests and the Python-level
pa.repeat() regression test.
Credit to @llama90's work in apache#38504, which reviewer @js8544 had already
validated this approach on before it went stale.
@Sriniketh24

Copy link
Copy Markdown
Author

Hi @AlenkaF — thanks for the pointer to #38504, that was a good approach that just ran out of the original author's time (credit to @llama90 for the initial work, and @js8544 for reviewing it there).

Reworked this PR to build on that approach:

Note: I wasn't able to run the full C++ test suite in my local environment (no existing build directory / ninja), so I only syntax-checked the changed file directly against the local headers (clean, no errors). CI here will be the real validation — flagging that up front rather than claiming more confidence than I have.

@AlenkaF

Copy link
Copy Markdown
Member

Could you have a look at this comment from the linked PR: #38504 (comment) and let me know what you think of the suggestion?

Note: I wasn't able to run the full C++ test suite in my local environment (no existing build directory / ninja), so I only syntax-checked the changed file directly against the local headers (clean, no errors). CI here will be the real validation — flagging that up front rather than claiming more confidence than I have.

And please, don't use agents to communicate with us. It is OK to use the tools for development provided you understand the changes. Also, you could point your agent to the development docs so it can help with building from source and testing: https://arrow.apache.org/docs/developers/python/building.html#build-pyarrow.

Per @bkietz's review on apache#38504 (discussion_r1394400239): checking
length_ alone against OffsetType::max() is wrong, since it rejects
valid cases like an empty string repeated more than OffsetType::max()
times (total data size stays 0, so it can never actually overflow).
Only the product value_length * length_ needs to fit in OffsetType.
Compute that product in int64_t and compare against OffsetType::max()
directly, exactly as bkietz suggested.
Moved the two cases that need multi-GB allocations to succeed (as
opposed to fail-fast) into a separate LARGE_MEMORY_TEST-gated test,
matching the convention used elsewhere in this file (see table_test.cc).
@Sriniketh24

Copy link
Copy Markdown
Author

Thanks for the pointer @AlenkaF — that discussion was exactly the missing piece. @bkietz caught a real bug in the approach I'd pushed: checking length_ alone against OffsetType::max() is a false positive — an empty string repeated more than int32::max() times is perfectly valid (every offset stays 0), so that check would have incorrectly rejected it.

Applied bkietz's suggested fix directly: compute value_length * length_ in int64_t and compare the product against OffsetType::max(), rather than checking either operand individually.

Also added the boundary tests js8544 asked for (empty string at length > int32::max, and "aa" at exactly int32::max/2) — these need multi-GB allocations to actually succeed rather than fail-fast, so I gated them behind LARGE_MEMORY_TEST like the rest of the codebase does (e.g. table_test.cc) rather than adding that cost to every CI run.

Local syntax check (now with gmock available) is clean on both files.

Sign up for freeto 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.

[Python][C++] pyarrow.repeat returns an invalid array when a chunked array is required.

3 participants

@Sriniketh24@AlenkaF
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

GH-36388: [C++][Python] Return error from MakeArrayFromScalar on offset overflow - #50024

Open
Sriniketh24 wants to merge 3 commits into
apache:mainfrom
Sriniketh24:fix/repeat-offset-overflow
Open

GH-36388: [C++][Python] Return error from MakeArrayFromScalar on offset overflow#50024
Sriniketh24 wants to merge 3 commits into
apache:mainfrom
Sriniketh24:fix/repeat-offset-overflow

Conversation

@Sriniketh24

@Sriniketh24Sriniketh24 commented May 23, 2026

Copy link
Copy Markdown

Rationale

pyarrow.repeat (backed by MakeArrayFromScalar in C++) silently created an invalid array with negative offsets when the total data size (value_size * repetition_count) exceeded INT32_MAX for 32-bit offset types (StringType, BinaryType). The resulting array passed creation without error but failed validation with a cryptic "Negative offsets in binary array" or "non-monotonic offset" message.

What changed

Added an early overflow check in RepeatedArrayFactory::CreateOffsetsBuffer that computes the total data size in int64_t and returns Status::Invalid with an actionable error message when it would exceed the offset type's maximum. The error message suggests using large_* types (e.g. large_string, large_binary) for data exceeding 2 GB.

Are these changes tested?

Yes.

  • C++ test: TestMakeArrayFromScalarOffsetOverflow in array_test.cc — tests string, binary, and large_string scalars
  • Python test: test_repeat_offset_overflow in test_array.py — verifies pa.repeat raises ArrowInvalid on overflow

Are there any user-facing changes?

Yes. MakeArrayFromScalar (and pyarrow.repeat) now raises ArrowInvalid early with a clear error message instead of silently returning a corrupt array. This is a strictly better user experience.

Closes: #36388


This is AI-assisted work by Claude.

…n offset overflow
MakeArrayFromScalar silently created an invalid array with negative
offsets when the total data size (value_size * repetition_count)
exceeded the maximum value of the offset type. For 32-bit offset types
like StringType and BinaryType, this threshold is INT32_MAX (~2 GB).
The root cause was in CreateOffsetsBuffer where the running offset
accumulated via OffsetType addition without checking for overflow,
wrapping around to negative values.
Added an early overflow check in CreateOffsetsBuffer that computes the
total size in int64_t and compares against the offset type's maximum.
On overflow, a Status::Invalid error is returned with a message
suggesting the use of large_* types.
This is AI-assisted work by Claude.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses GH-36388 by preventing MakeArrayFromScalar (and therefore pyarrow.repeat) from silently constructing invalid binary/string arrays when the repeated total byte size would exceed the maximum representable value of 32-bit offsets, returning an Invalid status with a clearer error instead.

Changes:

  • Added an offset overflow check in RepeatedArrayFactory::CreateOffsetsBuffer for variable-size offset types.
  • Added a C++ regression test covering string/binary offset overflow cases.
  • Added a Python regression test verifying pa.repeat raises ArrowInvalid on overflow.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

FileDescription
python/pyarrow/tests/test_array.pyAdds Python coverage ensuring pa.repeat raises on 32-bit offset overflow.
cpp/src/arrow/array/util.ccIntroduces early offset overflow detection when creating offsets for repeated variable-size values.
cpp/src/arrow/array/array_test.ccAdds a C++ regression test for MakeArrayFromScalar offset overflow behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadcpp/src/arrow/array/util.cc Outdated
Comment on lines +860 to +864
if (value_length > 0 && length_ > 0) {
int64_t total_size = static_cast<int64_t>(value_length) * length_;
if (total_size > static_cast<int64_t>(std::numeric_limits<OffsetType>::max())) {
return Status::Invalid(
"Cannot create array: total data size (", total_size,
Comment threadcpp/src/arrow/array/util.cc Outdated
Comment on lines +856 to +860
// Check that the total data size does not overflow the offset type.
// For 32-bit offset types (e.g. StringType, BinaryType), value_length * length_
// must fit in int32_t, otherwise the offsets wrap around and produce an invalid
// array with negative offsets.
if (value_length > 0 && length_ > 0) {

@AlenkaFAlenkaF left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@Sriniketh24 I think it would be worth looking at the work already done in #38504 and continue from there.

… length checks
Per @AlenkaF's suggestion to build on the approach from apache#38504:
- Replace the manual int64_t multiplication (which could itself silently
overflow for 64-bit offset types like large_string/large_binary) with
arrow::internal::MultiplyWithOverflow, which is correct for both 32-bit
and 64-bit OffsetType.
- Reject length > numeric_limits<OffsetType>::max() up front, independent
of value size (e.g. an empty string repeated too many times).
- Reject negative length in MakeArrayFromScalar itself.
- Add C++ test cases for the length-exceeds-offset-type and negative-length
paths, on top of the existing overflow tests and the Python-level
pa.repeat() regression test.
Credit to @llama90's work in apache#38504, which reviewer @js8544 had already
validated this approach on before it went stale.
@Sriniketh24

Copy link
Copy Markdown
Author

Hi @AlenkaF — thanks for the pointer to #38504, that was a good approach that just ran out of the original author's time (credit to @llama90 for the initial work, and @js8544 for reviewing it there).

Reworked this PR to build on that approach:

Note: I wasn't able to run the full C++ test suite in my local environment (no existing build directory / ninja), so I only syntax-checked the changed file directly against the local headers (clean, no errors). CI here will be the real validation — flagging that up front rather than claiming more confidence than I have.

@AlenkaF

Copy link
Copy Markdown
Member

Could you have a look at this comment from the linked PR: #38504 (comment) and let me know what you think of the suggestion?

Note: I wasn't able to run the full C++ test suite in my local environment (no existing build directory / ninja), so I only syntax-checked the changed file directly against the local headers (clean, no errors). CI here will be the real validation — flagging that up front rather than claiming more confidence than I have.

And please, don't use agents to communicate with us. It is OK to use the tools for development provided you understand the changes. Also, you could point your agent to the development docs so it can help with building from source and testing: https://arrow.apache.org/docs/developers/python/building.html#build-pyarrow.

Per @bkietz's review on apache#38504 (discussion_r1394400239): checking
length_ alone against OffsetType::max() is wrong, since it rejects
valid cases like an empty string repeated more than OffsetType::max()
times (total data size stays 0, so it can never actually overflow).
Only the product value_length * length_ needs to fit in OffsetType.
Compute that product in int64_t and compare against OffsetType::max()
directly, exactly as bkietz suggested.
Moved the two cases that need multi-GB allocations to succeed (as
opposed to fail-fast) into a separate LARGE_MEMORY_TEST-gated test,
matching the convention used elsewhere in this file (see table_test.cc).
@Sriniketh24

Copy link
Copy Markdown
Author

Thanks for the pointer @AlenkaF — that discussion was exactly the missing piece. @bkietz caught a real bug in the approach I'd pushed: checking length_ alone against OffsetType::max() is a false positive — an empty string repeated more than int32::max() times is perfectly valid (every offset stays 0), so that check would have incorrectly rejected it.

Applied bkietz's suggested fix directly: compute value_length * length_ in int64_t and compare the product against OffsetType::max(), rather than checking either operand individually.

Also added the boundary tests js8544 asked for (empty string at length > int32::max, and "aa" at exactly int32::max/2) — these need multi-GB allocations to actually succeed rather than fail-fast, so I gated them behind LARGE_MEMORY_TEST like the rest of the codebase does (e.g. table_test.cc) rather than adding that cost to every CI run.

Local syntax check (now with gmock available) is clean on both files.

Sign up for freeto 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.

[Python][C++] pyarrow.repeat returns an invalid array when a chunked array is required.

3 participants

@Sriniketh24@AlenkaF
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

GH-36388: [C++][Python] Return error from MakeArrayFromScalar on offset overflow - #50024

Open
Sriniketh24 wants to merge 3 commits into
apache:mainfrom
Sriniketh24:fix/repeat-offset-overflow
Open

GH-36388: [C++][Python] Return error from MakeArrayFromScalar on offset overflow#50024
Sriniketh24 wants to merge 3 commits into
apache:mainfrom
Sriniketh24:fix/repeat-offset-overflow

Conversation

@Sriniketh24

@Sriniketh24Sriniketh24 commented May 23, 2026

Copy link
Copy Markdown

Rationale

pyarrow.repeat (backed by MakeArrayFromScalar in C++) silently created an invalid array with negative offsets when the total data size (value_size * repetition_count) exceeded INT32_MAX for 32-bit offset types (StringType, BinaryType). The resulting array passed creation without error but failed validation with a cryptic "Negative offsets in binary array" or "non-monotonic offset" message.

What changed

Added an early overflow check in RepeatedArrayFactory::CreateOffsetsBuffer that computes the total data size in int64_t and returns Status::Invalid with an actionable error message when it would exceed the offset type's maximum. The error message suggests using large_* types (e.g. large_string, large_binary) for data exceeding 2 GB.

Are these changes tested?

Yes.

  • C++ test: TestMakeArrayFromScalarOffsetOverflow in array_test.cc — tests string, binary, and large_string scalars
  • Python test: test_repeat_offset_overflow in test_array.py — verifies pa.repeat raises ArrowInvalid on overflow

Are there any user-facing changes?

Yes. MakeArrayFromScalar (and pyarrow.repeat) now raises ArrowInvalid early with a clear error message instead of silently returning a corrupt array. This is a strictly better user experience.

Closes: #36388


This is AI-assisted work by Claude.

…n offset overflow
MakeArrayFromScalar silently created an invalid array with negative
offsets when the total data size (value_size * repetition_count)
exceeded the maximum value of the offset type. For 32-bit offset types
like StringType and BinaryType, this threshold is INT32_MAX (~2 GB).
The root cause was in CreateOffsetsBuffer where the running offset
accumulated via OffsetType addition without checking for overflow,
wrapping around to negative values.
Added an early overflow check in CreateOffsetsBuffer that computes the
total size in int64_t and compares against the offset type's maximum.
On overflow, a Status::Invalid error is returned with a message
suggesting the use of large_* types.
This is AI-assisted work by Claude.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses GH-36388 by preventing MakeArrayFromScalar (and therefore pyarrow.repeat) from silently constructing invalid binary/string arrays when the repeated total byte size would exceed the maximum representable value of 32-bit offsets, returning an Invalid status with a clearer error instead.

Changes:

  • Added an offset overflow check in RepeatedArrayFactory::CreateOffsetsBuffer for variable-size offset types.
  • Added a C++ regression test covering string/binary offset overflow cases.
  • Added a Python regression test verifying pa.repeat raises ArrowInvalid on overflow.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

FileDescription
python/pyarrow/tests/test_array.pyAdds Python coverage ensuring pa.repeat raises on 32-bit offset overflow.
cpp/src/arrow/array/util.ccIntroduces early offset overflow detection when creating offsets for repeated variable-size values.
cpp/src/arrow/array/array_test.ccAdds a C++ regression test for MakeArrayFromScalar offset overflow behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadcpp/src/arrow/array/util.cc Outdated
Comment on lines +860 to +864
if (value_length > 0 && length_ > 0) {
int64_t total_size = static_cast<int64_t>(value_length) * length_;
if (total_size > static_cast<int64_t>(std::numeric_limits<OffsetType>::max())) {
return Status::Invalid(
"Cannot create array: total data size (", total_size,
Comment threadcpp/src/arrow/array/util.cc Outdated
Comment on lines +856 to +860
// Check that the total data size does not overflow the offset type.
// For 32-bit offset types (e.g. StringType, BinaryType), value_length * length_
// must fit in int32_t, otherwise the offsets wrap around and produce an invalid
// array with negative offsets.
if (value_length > 0 && length_ > 0) {

@AlenkaFAlenkaF left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@Sriniketh24 I think it would be worth looking at the work already done in #38504 and continue from there.

… length checks
Per @AlenkaF's suggestion to build on the approach from apache#38504:
- Replace the manual int64_t multiplication (which could itself silently
overflow for 64-bit offset types like large_string/large_binary) with
arrow::internal::MultiplyWithOverflow, which is correct for both 32-bit
and 64-bit OffsetType.
- Reject length > numeric_limits<OffsetType>::max() up front, independent
of value size (e.g. an empty string repeated too many times).
- Reject negative length in MakeArrayFromScalar itself.
- Add C++ test cases for the length-exceeds-offset-type and negative-length
paths, on top of the existing overflow tests and the Python-level
pa.repeat() regression test.
Credit to @llama90's work in apache#38504, which reviewer @js8544 had already
validated this approach on before it went stale.
@Sriniketh24

Copy link
Copy Markdown
Author

Hi @AlenkaF — thanks for the pointer to #38504, that was a good approach that just ran out of the original author's time (credit to @llama90 for the initial work, and @js8544 for reviewing it there).

Reworked this PR to build on that approach:

Note: I wasn't able to run the full C++ test suite in my local environment (no existing build directory / ninja), so I only syntax-checked the changed file directly against the local headers (clean, no errors). CI here will be the real validation — flagging that up front rather than claiming more confidence than I have.

@AlenkaF

Copy link
Copy Markdown
Member

Could you have a look at this comment from the linked PR: #38504 (comment) and let me know what you think of the suggestion?

Note: I wasn't able to run the full C++ test suite in my local environment (no existing build directory / ninja), so I only syntax-checked the changed file directly against the local headers (clean, no errors). CI here will be the real validation — flagging that up front rather than claiming more confidence than I have.

And please, don't use agents to communicate with us. It is OK to use the tools for development provided you understand the changes. Also, you could point your agent to the development docs so it can help with building from source and testing: https://arrow.apache.org/docs/developers/python/building.html#build-pyarrow.

Per @bkietz's review on apache#38504 (discussion_r1394400239): checking
length_ alone against OffsetType::max() is wrong, since it rejects
valid cases like an empty string repeated more than OffsetType::max()
times (total data size stays 0, so it can never actually overflow).
Only the product value_length * length_ needs to fit in OffsetType.
Compute that product in int64_t and compare against OffsetType::max()
directly, exactly as bkietz suggested.
Moved the two cases that need multi-GB allocations to succeed (as
opposed to fail-fast) into a separate LARGE_MEMORY_TEST-gated test,
matching the convention used elsewhere in this file (see table_test.cc).
@Sriniketh24

Copy link
Copy Markdown
Author

Thanks for the pointer @AlenkaF — that discussion was exactly the missing piece. @bkietz caught a real bug in the approach I'd pushed: checking length_ alone against OffsetType::max() is a false positive — an empty string repeated more than int32::max() times is perfectly valid (every offset stays 0), so that check would have incorrectly rejected it.

Applied bkietz's suggested fix directly: compute value_length * length_ in int64_t and compare the product against OffsetType::max(), rather than checking either operand individually.

Also added the boundary tests js8544 asked for (empty string at length > int32::max, and "aa" at exactly int32::max/2) — these need multi-GB allocations to actually succeed rather than fail-fast, so I gated them behind LARGE_MEMORY_TEST like the rest of the codebase does (e.g. table_test.cc) rather than adding that cost to every CI run.

Local syntax check (now with gmock available) is clean on both files.

Sign up for freeto 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.

[Python][C++] pyarrow.repeat returns an invalid array when a chunked array is required.

3 participants

@Sriniketh24@AlenkaF
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

GH-36388: [C++][Python] Return error from MakeArrayFromScalar on offset overflow - #50024

Open
Sriniketh24 wants to merge 3 commits into
apache:mainfrom
Sriniketh24:fix/repeat-offset-overflow
Open

GH-36388: [C++][Python] Return error from MakeArrayFromScalar on offset overflow#50024
Sriniketh24 wants to merge 3 commits into
apache:mainfrom
Sriniketh24:fix/repeat-offset-overflow

Conversation

@Sriniketh24

@Sriniketh24Sriniketh24 commented May 23, 2026

Copy link
Copy Markdown

Rationale

pyarrow.repeat (backed by MakeArrayFromScalar in C++) silently created an invalid array with negative offsets when the total data size (value_size * repetition_count) exceeded INT32_MAX for 32-bit offset types (StringType, BinaryType). The resulting array passed creation without error but failed validation with a cryptic "Negative offsets in binary array" or "non-monotonic offset" message.

What changed

Added an early overflow check in RepeatedArrayFactory::CreateOffsetsBuffer that computes the total data size in int64_t and returns Status::Invalid with an actionable error message when it would exceed the offset type's maximum. The error message suggests using large_* types (e.g. large_string, large_binary) for data exceeding 2 GB.

Are these changes tested?

Yes.

  • C++ test: TestMakeArrayFromScalarOffsetOverflow in array_test.cc — tests string, binary, and large_string scalars
  • Python test: test_repeat_offset_overflow in test_array.py — verifies pa.repeat raises ArrowInvalid on overflow

Are there any user-facing changes?

Yes. MakeArrayFromScalar (and pyarrow.repeat) now raises ArrowInvalid early with a clear error message instead of silently returning a corrupt array. This is a strictly better user experience.

Closes: #36388


This is AI-assisted work by Claude.

…n offset overflow
MakeArrayFromScalar silently created an invalid array with negative
offsets when the total data size (value_size * repetition_count)
exceeded the maximum value of the offset type. For 32-bit offset types
like StringType and BinaryType, this threshold is INT32_MAX (~2 GB).
The root cause was in CreateOffsetsBuffer where the running offset
accumulated via OffsetType addition without checking for overflow,
wrapping around to negative values.
Added an early overflow check in CreateOffsetsBuffer that computes the
total size in int64_t and compares against the offset type's maximum.
On overflow, a Status::Invalid error is returned with a message
suggesting the use of large_* types.
This is AI-assisted work by Claude.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses GH-36388 by preventing MakeArrayFromScalar (and therefore pyarrow.repeat) from silently constructing invalid binary/string arrays when the repeated total byte size would exceed the maximum representable value of 32-bit offsets, returning an Invalid status with a clearer error instead.

Changes:

  • Added an offset overflow check in RepeatedArrayFactory::CreateOffsetsBuffer for variable-size offset types.
  • Added a C++ regression test covering string/binary offset overflow cases.
  • Added a Python regression test verifying pa.repeat raises ArrowInvalid on overflow.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

FileDescription
python/pyarrow/tests/test_array.pyAdds Python coverage ensuring pa.repeat raises on 32-bit offset overflow.
cpp/src/arrow/array/util.ccIntroduces early offset overflow detection when creating offsets for repeated variable-size values.
cpp/src/arrow/array/array_test.ccAdds a C++ regression test for MakeArrayFromScalar offset overflow behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadcpp/src/arrow/array/util.cc Outdated
Comment on lines +860 to +864
if (value_length > 0 && length_ > 0) {
int64_t total_size = static_cast<int64_t>(value_length) * length_;
if (total_size > static_cast<int64_t>(std::numeric_limits<OffsetType>::max())) {
return Status::Invalid(
"Cannot create array: total data size (", total_size,
Comment threadcpp/src/arrow/array/util.cc Outdated
Comment on lines +856 to +860
// Check that the total data size does not overflow the offset type.
// For 32-bit offset types (e.g. StringType, BinaryType), value_length * length_
// must fit in int32_t, otherwise the offsets wrap around and produce an invalid
// array with negative offsets.
if (value_length > 0 && length_ > 0) {

@AlenkaFAlenkaF left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@Sriniketh24 I think it would be worth looking at the work already done in #38504 and continue from there.

… length checks
Per @AlenkaF's suggestion to build on the approach from apache#38504:
- Replace the manual int64_t multiplication (which could itself silently
overflow for 64-bit offset types like large_string/large_binary) with
arrow::internal::MultiplyWithOverflow, which is correct for both 32-bit
and 64-bit OffsetType.
- Reject length > numeric_limits<OffsetType>::max() up front, independent
of value size (e.g. an empty string repeated too many times).
- Reject negative length in MakeArrayFromScalar itself.
- Add C++ test cases for the length-exceeds-offset-type and negative-length
paths, on top of the existing overflow tests and the Python-level
pa.repeat() regression test.
Credit to @llama90's work in apache#38504, which reviewer @js8544 had already
validated this approach on before it went stale.
@Sriniketh24

Copy link
Copy Markdown
Author

Hi @AlenkaF — thanks for the pointer to #38504, that was a good approach that just ran out of the original author's time (credit to @llama90 for the initial work, and @js8544 for reviewing it there).

Reworked this PR to build on that approach:

Note: I wasn't able to run the full C++ test suite in my local environment (no existing build directory / ninja), so I only syntax-checked the changed file directly against the local headers (clean, no errors). CI here will be the real validation — flagging that up front rather than claiming more confidence than I have.

@AlenkaF

Copy link
Copy Markdown
Member

Could you have a look at this comment from the linked PR: #38504 (comment) and let me know what you think of the suggestion?

Note: I wasn't able to run the full C++ test suite in my local environment (no existing build directory / ninja), so I only syntax-checked the changed file directly against the local headers (clean, no errors). CI here will be the real validation — flagging that up front rather than claiming more confidence than I have.

And please, don't use agents to communicate with us. It is OK to use the tools for development provided you understand the changes. Also, you could point your agent to the development docs so it can help with building from source and testing: https://arrow.apache.org/docs/developers/python/building.html#build-pyarrow.

Per @bkietz's review on apache#38504 (discussion_r1394400239): checking
length_ alone against OffsetType::max() is wrong, since it rejects
valid cases like an empty string repeated more than OffsetType::max()
times (total data size stays 0, so it can never actually overflow).
Only the product value_length * length_ needs to fit in OffsetType.
Compute that product in int64_t and compare against OffsetType::max()
directly, exactly as bkietz suggested.
Moved the two cases that need multi-GB allocations to succeed (as
opposed to fail-fast) into a separate LARGE_MEMORY_TEST-gated test,
matching the convention used elsewhere in this file (see table_test.cc).
@Sriniketh24

Copy link
Copy Markdown
Author

Thanks for the pointer @AlenkaF — that discussion was exactly the missing piece. @bkietz caught a real bug in the approach I'd pushed: checking length_ alone against OffsetType::max() is a false positive — an empty string repeated more than int32::max() times is perfectly valid (every offset stays 0), so that check would have incorrectly rejected it.

Applied bkietz's suggested fix directly: compute value_length * length_ in int64_t and compare the product against OffsetType::max(), rather than checking either operand individually.

Also added the boundary tests js8544 asked for (empty string at length > int32::max, and "aa" at exactly int32::max/2) — these need multi-GB allocations to actually succeed rather than fail-fast, so I gated them behind LARGE_MEMORY_TEST like the rest of the codebase does (e.g. table_test.cc) rather than adding that cost to every CI run.

Local syntax check (now with gmock available) is clean on both files.

Sign up for freeto 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.

[Python][C++] pyarrow.repeat returns an invalid array when a chunked array is required.

3 participants

@Sriniketh24@AlenkaF