-
Notifications
You must be signed in to change notification settings - Fork 28.6k
[SPARK-18458][CORE] Fix signed integer overflow problem at an expression in RadixSort.java #15907
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@hvanhovell I found similar portions in |
cc @ericl |
@kiszk yeah lets also address those |
@hvanhovell as far as I know, I addressed them in |
Test build #68728 has finished for PR 15907 at commit
|
Test build #68732 has finished for PR 15907 at commit
|
Can you please have a more descriptive title? Presumably the pull request is not to add coredump. |
@rxin Sure, I did. |
LGTM. I wonder if it's also worth changing all the int parameters to longs to be extra safe here with conversions, even if we know the values are bounded. |
Yea it might be a good idea to just use longs. |
Ideally, it is a good idea. Do you want to do that change using this PR? Another question is which scope do we apply such a change?
Obviously, 3. requires a lot of changes to many files. What do you think? |
I'm thinking 2. What do you think? |
It would be good. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about keeping the very small numbers (0..7, 0..255) as ints, and everything else as a long.
if (numRecords > 0) { | ||
long[][] counts = getCounts(array, numRecords, startByteIndex, endByteIndex); | ||
for (int i = startByteIndex; i <= endByteIndex; i++) { | ||
if (counts[i] != null) { | ||
for (long i = startByteIndex; i <= endByteIndex; i++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably not be a long, since it ranges from 0..7
@@ -40,28 +40,28 @@ | |||
* of always copying the data back to position zero for efficiency. | |||
*/ | |||
public static int sort( | |||
LongArray array, int numRecords, int startByteIndex, int endByteIndex, | |||
LongArray array, long numRecords, long startByteIndex, long endByteIndex, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should keep the byte indices as ints, since they are in 0..7 and we assert these below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I imagined that all of variables should be changed to long anyway.
Test build #68793 has finished for PR 15907 at commit
|
Test build #68798 has finished for PR 15907 at commit
|
Looks good |
@@ -80,7 +80,7 @@ class SortBenchmark extends BenchmarkBase { | |||
} | |||
val buf = new LongArray(MemoryBlock.fromLongArray(array)) | |||
timer.startTiming() | |||
RadixSort.sort(buf, size, 0, 7, false, false) | |||
RadixSort.sort(buf, size.toLong, 0, 7, false, false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need these toLongs? Doesn't scala do the cast implicitly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I wrote before, I wanted to emphasis the difference of types between caller and callee.
It is OK to rely on implicit cast, done.
var i = 0 | ||
val out = new Array[Long](length) | ||
val out = new Array[Long](length.toInt) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd add a checkedCast function similar to Guava's: https://google.github.io/guava/releases/19.0/api/docs/com/google/common/primitives/Ints.html#checkedCast(long)
and use those for all the toInt downcasts. Otherwise it'd be annoying to get mysterious negative integer exceptions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great! done in these files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you forget to push?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I put this comment before pushed. Now, you can see it
@@ -176,7 +176,7 @@ public ShuffleSorterIterator getSortedIterator() { | |||
int offset = 0; | |||
if (useRadixSort) { | |||
offset = RadixSort.sort( | |||
array, pos, | |||
array, (long)pos, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
again doesn't java do the upcast implicitly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is OK to rely on implicit cast, done.
Test build #68819 has finished for PR 15907 at commit
|
Test build #68820 has finished for PR 15907 at commit
|
Test build #68821 has finished for PR 15907 at commit
|
@@ -30,7 +32,7 @@ import org.apache.spark.util.collection.Sorter | |||
import org.apache.spark.util.random.XORShiftRandom | |||
|
|||
class RadixSortSuite extends SparkFunSuite with Logging { | |||
private val N = 10000 // scale this down for more readable results | |||
private val N = 10000.toLong // scale this down for more readable results |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Write 10000L
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I will do that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
inIndex = outIndex; | ||
outIndex = tmp; | ||
} | ||
} | ||
} | ||
return inIndex; | ||
return Ints.checkedCast(inIndex); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than pull in a library method, how about require
which lets you provide an actual error message?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @rxin
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might make sense to add a very simple if check in the beginning of this function. I will do it when I merge this.
Test build #68855 has finished for PR 15907 at commit
|
Merging in master/branch-2.1 |
…ion in RadixSort.java ## What changes were proposed in this pull request? This PR avoids that a result of an expression is negative due to signed integer overflow (e.g. 0x10?????? * 8 < 0). This PR casts each operand to `long` before executing a calculation. Since the result is interpreted as long, the result of the expression is positive. ## How was this patch tested? Manually executed query82 of TPC-DS with 100TB Author: Kazuaki Ishizaki <ishizaki@jp.ibm.com> Closes #15907 from kiszk/SPARK-18458. (cherry picked from commit d93b655) Signed-off-by: Reynold Xin <rxin@databricks.com>
…ion in RadixSort.java ## What changes were proposed in this pull request? This PR avoids that a result of an expression is negative due to signed integer overflow (e.g. 0x10?????? * 8 < 0). This PR casts each operand to `long` before executing a calculation. Since the result is interpreted as long, the result of the expression is positive. ## How was this patch tested? Manually executed query82 of TPC-DS with 100TB Author: Kazuaki Ishizaki <ishizaki@jp.ibm.com> Closes apache#15907 from kiszk/SPARK-18458.
What changes were proposed in this pull request?
This PR avoids that a result of an expression is negative due to signed integer overflow (e.g. 0x10?????? * 8 < 0). This PR casts each operand to
long
before executing a calculation. Since the result is interpreted as long, the result of the expression is positive.How was this patch tested?
Manually executed query82 of TPC-DS with 100TB