react-native-image-resizer icon indicating copy to clipboard operation
react-native-image-resizer copied to clipboard

Fix InputStream resource leak in `ImageResizer.getOrientationMatrix()`

Open ian-wd opened this issue 4 months ago • 0 comments

Fix: Resource leak in ImageResizer.getOrientationMatrix()

Problem

The InputStream opened in getOrientationMatrix() was not being properly closed, causing a resource leak. We discovered this when we turned on StrictMode on our Android app to trace memory related problems:

StrictMode policy violation: android.os.strictmode.LeakedClosableViolation: A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks. (Ask Gemini)
  	at android.os.StrictMode$AndroidCloseGuardReporter.report(StrictMode.java:2011)
  	at dalvik.system.CloseGuard.warnIfOpen(CloseGuard.java:336)
  	at java.io.FileInputStream.finalize(FileInputStream.java:662)
  	at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:370)
  	at java.lang.Daemons$FinalizerDaemon.processReference(Daemons.java:350)
  	at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:322)
  	at java.lang.Daemons$Daemon.run(Daemons.java:131)
  	at java.lang.Thread.run(Thread.java:1012)
  Caused by: java.lang.Throwable: Explicit termination method 'close' not called
  	at dalvik.system.CloseGuard.openWithCallSite(CloseGuard.java:288)
  	at dalvik.system.CloseGuard.open(CloseGuard.java:257)
  	at java.io.FileInputStream.<init>(FileInputStream.java:195)
  	at java.io.FileInputStream.<init>(FileInputStream.java:133)
  	at android.content.ContentResolver.openInputStream(ContentResolver.java:1526)
  	at com.reactnativeimageresizer.ImageResizer.getOrientation(ImageResizer.java:323)
  	at com.reactnativeimageresizer.ImageResizer.createResizedImage(ImageResizer.java:552)
  	at com.reactnativeimageresizer.ImageResizerModule.createResizedImageWithExceptions(ImageResizerModule.java:68)
  	at com.reactnativeimageresizer.ImageResizerModule.-$$Nest$mcreateResizedImageWithExceptions(Unknown Source:0)
  	at com.reactnativeimageresizer.ImageResizerModule$1.doInBackgroundGuarded(ImageResizerModule.java:49)
  	at com.reactnativeimageresizer.ImageResizerModule$1.doInBackgroundGuarded(ImageResizerModule.java:45)
  	at com.facebook.react.bridge.GuardedAsyncTask.doInBackground(GuardedAsyncTask.java:34)
  	at com.facebook.react.bridge.GuardedAsyncTask.doInBackground(GuardedAsyncTask.java:19)
  	at android.os.AsyncTask$3.call(AsyncTask.java:394)
  	at java.util.concurrent.FutureTask.run(FutureTask.java:264)
  	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
  	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
  	at java.lang.Thread.run(Thread.java:1012) 

Solution

Wrapped the InputStream in a try-with-resources statement to ensure automatic resource cleanup.

Changes

  • Updated android/src/main/java/com/reactnativeimageresizer/ImageResizer.java line 322-324
  • Changed from manual InputStream management to try-with-resources pattern

Impact

  • Prevents resource leaks when reading image orientation metadata
  • Follows Java best practices for resource management
  • No functional changes to the API

Testing

  • Existing functionality remains unchanged
  • Resource cleanup is now guaranteed even if exceptions occur

ian-wd avatar Jun 10 '25 06:06 ian-wd