realm / realm-java

Realm is a mobile database: a replacement for SQLite & ORMs
http://realm.io
Apache License 2.0
11.45k stars 1.75k forks source link

RealmList<RealmAny> on Android ARM devices works incorrectly #7626

Closed vcimka closed 2 years ago

vcimka commented 2 years ago

Expected results

List of RealmAny objects

Actual Results

List of "null" objects

Steps & Code to Reproduce

package com.example.testapp

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import io.realm.*
import io.realm.annotations.PrimaryKey
import java.io.File
import kotlin.random.Random

open class FirstInnerTestEntity(
    @PrimaryKey
    var id: Long = 0
) : RealmObject()

open class SecondInnerTestEntity(
    @PrimaryKey
    var id: Long = 0
) : RealmObject()

open class TestEntity(
    @PrimaryKey
    var id: Long = 0,
    var items: RealmList<FirstInnerTestEntity>? = null
) : RealmObject()

open class WithRealmAnyTestEntity(
    @PrimaryKey
    var id: Long = 0,
    var items: RealmList<RealmAny>? = null
) : RealmObject()

class MainActivity : AppCompatActivity() {

    private lateinit var realm: Realm

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        initDb()

        saveEntities()

        getEntities(FirstInnerTestEntity::class.java)
        getEntities(SecondInnerTestEntity::class.java)
        getEntities(TestEntity::class.java)
        getEntities(WithRealmAnyTestEntity::class.java)

        setContentView(R.layout.activity_main)
    }

    private fun initDb() {
        Realm.init(applicationContext)

        val directory =
            File(applicationContext.filesDir.absolutePath + File.separator + "app_db")

        val config = RealmConfiguration.Builder()
            .directory(directory)
            .deleteRealmIfMigrationNeeded()
            .allowWritesOnUiThread(true)
            .build()

        Realm.setDefaultConfiguration(config)

        realm = Realm.getDefaultInstance()
    }

    private fun <C: RealmModel> getEntities(clazz: Class<C>): List<C> {
        val results = realm.where(clazz).findAll()
        return realm.copyFromRealm(results)
    }

    private fun saveEntities() {
        val entities = (0..100).realmMap {
            TestEntity(
                id = it.toLong(),
                items = (0..10).realmMap {
                    FirstInnerTestEntity(
                        Random.nextLong()
                    )
                }
            )
        }
        val entities2 = (0..100).realmMap {
            WithRealmAnyTestEntity(
                id = it.toLong(),
                items = (0..10).realmMap {
                    RealmAny.valueOf(
                        when (Random.nextBoolean()) {
                            true -> FirstInnerTestEntity(
                                Random.nextLong()
                            )
                            false -> SecondInnerTestEntity(
                                Random.nextLong()
                            )
                        }
                    )
                }
            )
        }

        realm.executeTransaction {
            realm.insertOrUpdate(entities)
            realm.insertOrUpdate(entities2)
        }
    }

    inline fun <T, R> Iterable<T>.realmMap(transform: (T) -> R): RealmList<R> {
        return mapTo(RealmList(), transform)
    }
}

on realm-java 10.8.1 (realm-core 11.6.0) this sample crashing with next stacktrace:

<unknown> 0x0000000091680608
Java_io_realm_internal_core_NativeRealmAny_nativeGetType 0x00000000916c4aac
int io.realm.internal.core.NativeRealmAny.nativeGetType(long) 0x0000000091a57c08
art_quick_invoke_stub_internal 0x00000000ac583376
art_quick_invoke_static_stub 0x00000000ac5885ee
art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*) 0x00000000ac2300e2

       *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'motorola/pettyl/pettyl:8.1.0/OPG28.54-53-8/55beb:user/release-keys'
Revision: 'p300'
ABI: 'arm'
pid: 19549, tid: 19549, name: example.testapp  >>> com.example.testapp <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x8b
Cause: null pointer dereference
    r0 00000000  r1 0000007b  r2 0000007b  r3 00000000
    r4 bed1c6b8  r5 00000000  r6 00000000  r7 bed1c698
    r8 00000000  r9 0000007b  sl 00000000  fp bed1c76c
    ip 975c2a99  sp bed1c680  lr 9757e609  pc 9757e608  cpsr 40070030
backtrace:
    #00 pc 001fe608  /data/app/com.example.testapp-4jVqw7f-kkz-6UcIiIozOQ==/lib/arm/librealm-jni.so
    realm/realm-core#1 pc 00242aa9  /data/app/com.example.testapp-4jVqw7f-kkz-6UcIiIozOQ==/lib/arm/librealm-jni.so (Java_io_realm_internal_core_NativeRealmAny_nativeGetType+16)
    realm/realm-core#2 pc 00021f5f  /data/app/com.example.testapp-4jVqw7f-kkz-6UcIiIozOQ==/oat/arm/base.odex (offset 0x20000)

on realm-java realm-java 10.9.0 (realm-core 11.7.0) getEntities(WithRealmAnyTestEntity::class.java) returns list of "null" 145781083-90383218-94dc-4acb-b568-4aaa493eb622

Can be reproduced on ARM devices: SM-A105FN (API 29) Nokia 1 (API 27) Motorolla G5S (API 27) Redmi 6A (API 27) moto e5 play (API 27) SM-G532G (API 23) Nexus 5 (API 23) LG-AS110 (API 23) Nexus 7 (API 21)

Core version

realm-java 10.9.0 (realm-core 11.7.0)

clementetb commented 2 years ago

Thanks for sharing the code example, it has allowed us reproducing the issue.

While we are investigating the root cause for the issue we have noticed that it only affects ARM 32 bits, ARM 64 bits does not show the issue.

Half of the devices you listed are arm64-v8a, how come that they present the issue, do you have you set any ABI filter on your app?

vcimka commented 2 years ago

@clementetb hello devices from list was tested on realm-java 10.8.1 (realm-core 11.6.0) you can run my sample yourself on these devices using Firebase TestLab and see for yourself our app doesnt have any ABI filter

clementetb commented 2 years ago

After running the example app on Testlab I confirm the devices in your list, although they might a 64bit SOC, run in 32bit mode in Testlab.

clementetb commented 2 years ago

Unrolled stacktrace of the crash:

Build fingerprint: 'Xiaomi/raphael_eea/raphael:11/RKQ1.200826.002/V12.5.1.0.RFKEUXM:user/release-keys'
#00 0x00065658 /apex/com.android.runtime/lib/bionic/libc.so (abort+172) (BuildId: 3516bc395829323390a814b64aaaf5a1)
#01 0x004a3b3f /data/app/~~NZ9y0jVigYZM8kyy_SW0xw==/com.example.myapplication-kbFFktxW_MsMApylsofNOg==/lib/arm/librealm-jni.so (BuildId: 130bf72fdcd56946da08a6d82edf6a706c0f4f1c)
                                                                                                                                please_report_this_issue_in_github_realm_realm_core
                                                                                                                                /tmp/realm-java/realm/realm-library/src/main/cpp/realm-core/src/realm/util/terminate.cpp:50:5
#02 0x004a3bd1 /data/app/~~NZ9y0jVigYZM8kyy_SW0xw==/com.example.myapplication-kbFFktxW_MsMApylsofNOg==/lib/arm/librealm-jni.so (BuildId: 130bf72fdcd56946da08a6d82edf6a706c0f4f1c)
                                                                                                                                realm::util::terminate_internal(std::__ndk1::basic_stringstream<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> >&) (.llvm.12074595099032379996)
                                                                                                                                /tmp/realm-java/realm/realm-library/src/main/cpp/realm-core/src/realm/util/terminate.cpp:123:5
#03 0x004a3cc7 /data/app/~~NZ9y0jVigYZM8kyy_SW0xw==/com.example.myapplication-kbFFktxW_MsMApylsofNOg==/lib/arm/librealm-jni.so (BuildId: 130bf72fdcd56946da08a6d82edf6a706c0f4f1c)
                                                                                                                                realm::util::terminate(char const*, char const*, long, std::initializer_list<realm::util::Printable>&&)
                                                                                                                                /tmp/realm-java/realm/realm-library/src/main/cpp/realm-core/src/realm/util/terminate.cpp:140:5
#04 0x0027c44b /data/app/~~NZ9y0jVigYZM8kyy_SW0xw==/com.example.myapplication-kbFFktxW_MsMApylsofNOg==/lib/arm/librealm-jni.so (BuildId: 130bf72fdcd56946da08a6d82edf6a706c0f4f1c)
                                                                                                                                realm::JavaValue::clear()
                                                                                                                                /tmp/realm-java/realm/realm-library/src/main/cpp/java_object_accessor.hpp:287:22
#05 0x002a39d3 /data/app/~~NZ9y0jVigYZM8kyy_SW0xw==/com.example.myapplication-kbFFktxW_MsMApylsofNOg==/lib/arm/librealm-jni.so (Java_io_realm_internal_core_NativeRealmAny_nativeGetType+46) (BuildId: 130bf72fdcd56946da08a6d82edf6a706c0f4f1c)
                                                                                                                                realm::JavaValue::~JavaValue()
                                                                                                                                /tmp/realm-java/realm/realm-library/src/main/cpp/java_object_accessor.hpp:137:9
                                                                                                                                Java_io_realm_internal_core_NativeRealmAny_nativeGetType
                                                                                                                                /tmp/realm-java/realm/realm-library/src/main/cpp/io_realm_internal_core_NativeRealmAny.cpp:262:5
#06 0x000d86dd /apex/com.android.art/lib/libart.so (art_quick_generic_jni_trampoline+44) (BuildId: b218a062b8132f065f9de1aaecd032de)
#07 0x000d3bd5 /apex/com.android.art/lib/libart.so (art_quick_invoke_stub_internal+68) (BuildId: b218a062b8132f065f9de1aaecd032de)
#08 0x004c3499 /apex/com.android.art/lib/libart.so (art_quick_invoke_static_stub+288) (BuildId: b218a062b8132f065f9de1aaecd032de)
rorbech commented 2 years ago

I managed to compile a very small test case reproducing this only on ARM 32-bit in https://github.com/realm/realm-java/tree/ct/investigation-realmany. I have not yet been able to locate the actual root cause as the realm any immediately looks fine but is maybe ruined by a type cast. The debug session itself crashes without a proper indication of what goes wrong when trying to inspect the details, so will have to dig a bit more into the internals of the low level realm any implementation.

rorbech commented 2 years ago

This is fixed in 10.10.0.