[ 
https://issues.apache.org/jira/browse/SPARK-58713?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

ASF GitHub Bot updated SPARK-58713:
-----------------------------------
    Labels: pull-request-available  (was: )

> overlay() returns wrong results for out-of-range position arguments
> -------------------------------------------------------------------
>
>                 Key: SPARK-58713
>                 URL: https://issues.apache.org/jira/browse/SPARK-58713
>             Project: Spark
>          Issue Type: Bug
>          Components: SQL
>    Affects Versions: 4.2.0
>            Reporter: sepuri sai krishna
>            Priority: Major
>              Labels: pull-request-available
>
> {{Overlay.calculate}} computes its two slice boundaries in {{int}} 
> arithmetic, so a position argument near the ends of the {{int}} range wraps 
> and the function silently returns a wrong result. Both the STRING and the 
> BINARY overload are affected, on the interpreted and the codegen path, with 
> default configuration.
> {code:scala}
> def calculate(input: UTF8String, replace: UTF8String, pos: Int, len: Int): 
> UTF8String = {
>   val builder = new UTF8StringBuilder
>   builder.append(input.substringSQL(1, pos - 1))          // (1) `pos - 1` 
> overflows
>   builder.append(replace)
>   val length = if (len >= 0) len else replace.numChars
>   builder.append(input.substringSQL(pos + length, Int.MaxValue))  // (2) `pos 
> + length` overflows
>   builder.build()
> }
> {code}
> The BINARY overload has the same two expressions, via 
> {{ByteArray.subStringSQL}}.
> For {{pos == Int.MinValue}}, {{pos - 1}} wraps to {{Int.MaxValue}}, so the 
> leading slice becomes the whole input instead of the empty string. For 
> {{pos}} near {{Int.MaxValue}}, {{pos + length}} wraps to a large negative 
> value, which {{substringSQL}} interprets as an offset from the end of the 
> input, so the trailing slice becomes the whole input instead of the empty 
> string. In both cases the input is duplicated around the replacement.
> h3. Reproduction
> {code:sql}
> SELECT overlay('Spark SQL' PLACING '_' FROM 2147483647 FOR 5);
> -- actual:   'Spark SQL_Spark SQL'
> -- expected: 'Spark SQL_'
> SELECT overlay('Spark SQL' PLACING '_' FROM -2147483648 FOR 1);
> -- actual:   'Spark SQL_Spark SQL'
> -- expected: '_Spark SQL'
> {code}
> Measured on current master, input {{'Spark SQL'}} and replacement {{'_'}}:
> || pos || len || actual (STRING) || actual (BINARY) || expected ||
> | {{Int.MaxValue}} | 5 | {{'Spark SQL_Spark SQL'}} | {{'Spark SQL_Spark 
> SQL'}} | {{'Spark SQL_'}} |
> | {{Int.MaxValue}} | -1 | {{'Spark SQL_Spark SQ'}} | {{'Spark SQL_Spark 
> SQL'}} | {{'Spark SQL_'}} |
> | {{Int.MaxValue - 2}} | 10 | {{'Spark SQL_Spark SQL'}} | {{'Spark SQL_Spark 
> SQL'}} | {{'Spark SQL_'}} |
> | {{Int.MinValue}} | 1 | {{'Spark SQL_Spark SQL'}} | {{'Spark SQL_Spark 
> SQL'}} | {{'_Spark SQL'}} |
> | {{Int.MinValue}} | -1 | {{'Spark SQL_Spark SQL'}} | {{'Spark SQL_Spark 
> SQL'}} | {{'_Spark SQL'}} |
> All in-range positions are unaffected; {{pos}} values such as 2, 6, 7, 100 
> and -1 produce identical results before and after the fix.
> Note the STRING and BINARY columns already disagree for {{pos = Int.MaxValue, 
> len = -1}}, which is a symptom of the separate clamping problem fixed under 
> SPARK-58708. That fix brings BINARY into line with STRING for that row, but 
> both remain wrong until the arithmetic here is corrected -- the overflow 
> happens in {{Overlay.calculate}} before {{substringSQL}} is ever reached, so 
> SPARK-58708 does not and cannot fix it.
> h3. Proposed fix
> Compute both boundaries in {{long}} and clamp into the {{int}} range before 
> calling {{substringSQL}}:
> {code:scala}
> private def clamp(v: Long): Int =
>   math.max(Int.MinValue, math.min(Int.MaxValue, v)).toInt
> {code}
> applied to {{pos - 1}} and {{pos + length}} in both overloads. Clamping 
> rather than throwing keeps the behaviour consistent with {{substring()}}, 
> which saturates rather than erroring for out-of-range positions. With this 
> change all five rows above produce the expected column, and the in-range 
> cases are unchanged.
> h3. Impact
> Wrong results, silently. No error is raised and no configuration is involved. 
> The affected argument range is narrow, so the practical exposure is low, but 
> the failure mode is a duplicated input rather than an obviously bogus value, 
> which makes it hard to notice.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to