-
-
Notifications
You must be signed in to change notification settings - Fork 735
Fix StackOverflowError when merging ParseObject from JSON #925
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
Fix StackOverflowError when merging ParseObject from JSON #925
Conversation
This test shows the parse-community#896 bug.
`synchronizedSet(s)` ends up making a new wrapper for the supplied set, which means on subsequent calls, it becomes a SynchronizedSet, wrapped in a SynchronizedSet, wrapped ... etc. When using the LocalDataStore, the ParseObject.State is reused for every matching ClassName+ObjectId pair, so every time a ParseObject is parsed from JSON data, the existing object is "refreshed" by making a copy of its State, and then merging with the new data. Every call to State.newBuilder() is therefore adding a new layer of SynchronizedSet to the availableKeys Set. Eventually that nested hierarchy of sets becomes so large that it causes a StackOverflowError for any operation on the collection. By making a copy of the set before wrapping it in synchronizedSet(), that nested hierarchy becomes severed, and we end up with just one level of wrappers.
Codecov Report
@@ Coverage Diff @@
## master #925 +/- ##
============================================
- Coverage 64.65% 64.64% -0.02%
Complexity 1898 1898
============================================
Files 122 122
Lines 9709 9709
Branches 1361 1361
============================================
- Hits 6277 6276 -1
Misses 2927 2927
- Partials 505 506 +1
Continue to review full report at Codecov.
|
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.
Looks good to me, other than some minor changes
26eec70
to
0c3dfd2
Compare
Hi, now that this is merged, when could we expect a new version of the library to be released? |
I'll wait for EOD for a review of #926 and then I'll merge and create 1.19.0 |
Awesome thanks… well, I guess this is as far as I go and now I need to migrate the project to AndroidX 😅 wish me luck |
|
Yeah, just tried it out again and have some problems with the native C++ code 😅 |
It might be a good idea to release this change as 1.18.6, and then 1.19 separately with the AndroidX update. Since that change breaks compatibility, but this one didn't. We can still do a retro tag and release of f2e6475. What do you think? |
It would be really amazing if you could do that 👍 |
Sure, it has been released as 1.18.6 |
Thanks! |
Hi, buildscript {
ext.kotlin_version = '1.2.71'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.3'
classpath 'org.kt3k.gradle.plugin:coveralls-gradle-plugin:2.8.2'
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
plugins {
id 'com.github.ben-manes.versions' version '0.20.0'
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
ext {
compileSdkVersion = 27
supportLibVersion = '27.1.1'
firebaseJobdispatcherVersion = '0.8.5'
minSdkVersion = 14
targetSdkVersion = 27
} Any reason to not do so? If it is fine, I can open a PR to update those :) |
1.18.6 is sort of a special case for those who cannot move to AndroidX yet, but want the fixes of this PR. 1.19.0 is the preferred upgrade path for anyone who is targeting API 28 and all future versions will build on this. |
@Jawnnypoo did any of those releases make it to Maven Central? Or did I miss something wrt where artifacts are deployed these days? https://mvnrepository.com/artifact/com.parse/parse-android shows the latest version is 1.17.3 EDIT: disregard :) I see the notes about jitpack |
Yeah I kind of wished we had it back to maven central. It's created a lot of confusion.. |
Feel free to move it back if you would like, I think jitpack makes the releases much easier (less configuration) and just requires creating a tag, which is simple and allowed me to create 1.18.6 very easily by just creating a tag of a commit that hadn't even been released previously. Easier access to SNAPSHOTS and versioning by a particular commit (pre release) as well. |
This fixes #896. See comments there, and at #795.
When LocalDataStore is enabled, the same
ParseObject(.State)
is shared for the same class+id pair. That allows us to update objects in-place whenever a ParseObject is parsed from JSON. But every time the state is copied, viaState.newBuilder()
, theavailableKeys
Set is wrapped (and re-wrapped, etc...) in synchronizedSet().Eventually, if the object has been refreshed enough times, that results in such a deeply nested hierarchy of wrapped sets, that any collection operation on it results in a StackOverflowError.
This change adds a test to prove the bug, and fixes it by severing making a copy of the set before wrapping it in synchronizedSet().