Skip to content
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

Strange StackOverflowError in crash report #1804

Closed
epetrenko opened this issue Feb 13, 2020 · 2 comments
Closed

Strange StackOverflowError in crash report #1804

epetrenko opened this issue Feb 13, 2020 · 2 comments

Comments

@epetrenko
Copy link

Hi there.

First, prehistory. I've published an app which I was working on to Google Play as alpha version and got strange crash reports in Crashlytics with StackOverflowError. I'm not even sure that the problem is related to coroutines (it seems to be more related to ProGuard or R8 tools), but stacktraces include links to coroutines, so that's why I'm placing an issue here.

I created a simple repository as example to show the issue. It's simplified a lot, production app has much more complicated architecture and uses coroutines as base for domain layer.

Example has a simple view model, which has live data based on state:

private val _state = MutableLiveData(MainViewState())
val state: LiveData<MainViewState>
    get() = _state

State is a data class:

data class MainViewState(val list: List<Int> = emptyList())

Activity observes this live data state:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    viewModel.state.observe(this, Observer(::renderViewState))
}

In the production app view model collects flow returned by Room library in init block. In the example repo I just created a simple flow:

init {
    viewModelScope.launch {
        flow {
            val list = arrayListOf<Int>()
            for (i in 0..100) {
                list.add(Random(100).nextInt())
            }
            emit(list)
        }.flowOn(Dispatchers.Default)
            .distinctUntilChanged()
            .collect { list ->
                Log.e("Collect list", list.toString())
            }
    }
}

flowOn(Dispatchers.Default) and distinctUntilChanged() methods are placed here just to match the behavior of the actual app. Also I emulated release mode by setting the following in build.gradle:

debug {
    debuggable false
    minifyEnabled true
    shrinkResources true
    proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}

And android.enableR8.fullMode=true in gradle.properties.

Actual issue is in that app crashes with these parameters, but everything works fine with another variations. I've got the following results. Crash doesn't appear if:

  1. Set debuggable to true
  2. Using proguard-android.txt instead of proguard-android-optimize.txt
  3. Removing android.enableR8.fullMode=true. Works for both proguard-android.txt and proguard-android-optimize.txt
  4. Removing .flowOn(Dispatchers.Default) from chain
  5. Using the same dispatchers for .flowOn() and viewModelScope.launch()

Each item in the above list describes changing of single parameter without affecting the rest. Maybe I missed something or just misunderstood basic concepts, but it's interesting why stacktrace points to StackOverflowError exception.

Deobfuscated stacktrace for example app is attached: stacktrace.txt.

@elizarov
Copy link
Contributor

It definitely looks like a problem with R8. I would really recommend to submit it to R8 bug tracker.

@epetrenko
Copy link
Author

@elizarov I've opened an issue on R8 bugtracker. This is the link for the case if someone wants to track the status of this problem.

Also, R8 developers adviced to add the following ProGuard rule as temporary workaround for this concrete case:

-keep class kotlinx.coroutines.flow.internal.ChannelFlowOperator { }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants