Skip to content

[Bug] ObjectAlreadyConsumedException: Array already consumed in getThreatIdentifiers (Release build only) #136

@Jinsu0313

Description

@Jinsu0313

Description

getThreatIdentifiers method throws ObjectAlreadyConsumedException: Array already consumed on release builds when called more than once.

Environment

  • freerasp-react-native version: 4.3.2
  • React Native version: 0.78.3
  • React version: 19.0.0
  • Platform: Android (Release build with R8/ProGuard enabled)
  • Android minSdk: 24
  • Android targetSdk: 35

Stack Trace

Exception com.facebook.react.bridge.ObjectAlreadyConsumedException: Array already
consumed
at com.facebook.react.bridge.WritableNativeArray.pushNativeArray
(WritableNativeArray.kt)
at com.facebook.react.bridge.WritableNativeArray.pushArray
(WritableNativeArray.kt:38)
at com.facebook.react.bridge.Arguments.fromJavaArgs (Arguments.java:189)
at com.facebook.react.bridge.CallbackImpl.invoke (CallbackImpl.java:31)
at com.facebook.react.bridge.PromiseImpl.resolve (PromiseImpl.java:60)
at com.freeraspreactnative.FreeraspReactNativeModule.getThreatIdentifiers
(SourceFile:3)
at java.lang.reflect.Method.invoke
at com.facebook.react.bridge.JavaMethodWrapper.invoke (JavaMethodWrapper.java:372)
at com.facebook.react.bridge.JavaModuleWrapper.invoke (JavaModuleWrapper.java:146)
...

Root Cause Analysis

The issue is in ThreatEvent.kt (lines 43-65):

companion object {                                                                     
    internal val ALL_EVENTS = Arguments.fromList(                                      
      listOf(                                                                          
        AppIntegrity,                                                                  
        // ... other events                                                            
      ).map { it.value })                                                              
}                                                                                      
                                                                                       
ALL_EVENTS is created once as a static WritableArray in the companion object.          
                                                                                       
In FreeraspReactNativeModule.kt (lines 103-105):                                       
                                                                                       
@ReactMethod                                                                           
fun getThreatIdentifiers(promise: Promise) {                                           
    promise.resolve(ThreatEvent.ALL_EVENTS)  // Reuses the same instance               
}                                                                                      
                                                                                       
When promise.resolve() is called, the WritableArray becomes "consumed" and cannot be   
reused. The first call succeeds, but subsequent calls throw                            
ObjectAlreadyConsumedException.                                                        
                                                                                       
Why Release build only?                                                                
- In Debug mode, hot reload recreates modules frequently                               
- In Release mode, the module persists throughout the app lifecycle, and               
getThreatIdentifiers may be called multiple times                                      
                                                                                       
Suggested Fix                                                                          
                                                                                       
Change ALL_EVENTS from a static property to a function that creates a new array each   
time:                                                                                  
                                                                                       
ThreatEvent.kt:                                                                        
// Before (bug)                                                                        
internal val ALL_EVENTS = Arguments.fromList(...)                                      
                                                                                       
// After (fix)                                                                         
internal fun getAllEvents() = Arguments.fromList(                                      
    listOf(                                                                            
        AppIntegrity,                                                                  
        PrivilegedAccess,                                                              
        // ... other events                                                            
    ).map { it.value }                                                                 
)                                                                                      
                                                                                       
FreeraspReactNativeModule.kt:                                                          
// Before                                                                              
promise.resolve(ThreatEvent.ALL_EVENTS)                                                
                                                                                       
// After                                                                               
promise.resolve(ThreatEvent.getAllEvents())                                            
                                                                                       
The same fix should be applied to RaspExecutionStateEvent.ALL_EVENTS as well.          
                                                                                       
Steps to Reproduce                                                                     
                                                                                       
1. Build release APK with enableProguardInReleaseBuilds = true                         
2. Install and run the app                                                             
3. Trigger any scenario where getThreatIdentifiers is called more than once            
4. App crashes with ObjectAlreadyConsumedException                                     
                                                                                       
---                      

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions