Bug 1356693 - infer: fix RESOURCE_LEAK's in services r=Grisha
☠☠ backed out by 6b9e04731fcd ☠ ☠
authorAndrzej Hunt <ahunt@mozilla.com>
Fri, 14 Apr 2017 20:58:59 -0700
changeset 569327 6d26ad68f31f431d6dfd8be5d6ad5d7962a7bcfe
parent 569326 8b672583d57c9b55e66f199545f0cd9084ebab23
child 569328 731479637edac93e715a756fe3b13e148751d780
push id56143
push userbmo:jeremychen@mozilla.com
push dateThu, 27 Apr 2017 10:17:21 +0000
reviewersGrisha
bugs1356693
milestone55.0a1
Bug 1356693 - infer: fix RESOURCE_LEAK's in services r=Grisha The primary issue is that we use a throwing InputStreamReader constructor. If it throws, then any nested streams will be lost. We can fix that by using the non-throwing InputStreamReader constructor (which uses a Charset as the second parameter, instead of a String which causes an Exception to be thrown if it can't be parsed) We also simplify some nested Stream's a little: most of the Stream constructors don't throw, so there's no harm in not keeping individual references to those that don't throw - and that results in less Stream references for us to handle. MozReview-Commit-ID: 2hyRFGVmGnU
mobile/android/services/src/main/java/org/mozilla/gecko/sync/Utils.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/MozResponse.java
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/Utils.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/Utils.java
@@ -26,16 +26,17 @@ import java.util.TreeMap;
 import java.util.concurrent.Executor;
 
 import org.json.simple.JSONArray;
 import org.mozilla.apache.commons.codec.binary.Base32;
 import org.mozilla.apache.commons.codec.binary.Base64;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.background.nativecode.NativeCrypto;
 import org.mozilla.gecko.sync.setup.Constants;
+import org.mozilla.gecko.util.IOUtils;
 import org.mozilla.gecko.util.StringUtils;
 
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.os.Bundle;
 
 public class Utils {
 
@@ -483,47 +484,30 @@ public class Utils {
    * @param filename name of file to read; must not be null.
    * @return <code>String</code> instance.
    */
   public static String readFile(final Context context, final String filename) {
     if (filename == null) {
       throw new IllegalArgumentException("Passed null filename in readFile.");
     }
 
-    FileInputStream fis = null;
-    InputStreamReader isr = null;
     BufferedReader br = null;
 
     try {
-      fis = context.openFileInput(filename);
-      isr = new InputStreamReader(fis, StringUtils.UTF_8);
-      br = new BufferedReader(isr);
+      br = new BufferedReader(new InputStreamReader(context.openFileInput(filename), StringUtils.UTF_8));
       StringBuilder sb = new StringBuilder();
       String line;
       while ((line = br.readLine()) != null) {
         sb.append(line);
       }
       return sb.toString();
     } catch (Exception e) {
       return null;
     } finally {
-      if (isr != null) {
-        try {
-          isr.close();
-        } catch (IOException e) {
-          // Ignore.
-        }
-      }
-      if (fis != null) {
-        try {
-          fis.close();
-        } catch (IOException e) {
-          // Ignore.
-        }
-      }
+      IOUtils.safeStreamClose(br);
     }
   }
 
   /**
    * Format a duration as a string, like "0.56 seconds".
    *
    * @param startMillis start time in milliseconds.
    * @param endMillis end time in milliseconds.
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/MozResponse.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/net/MozResponse.java
@@ -13,16 +13,17 @@ import java.util.Scanner;
 
 import org.json.simple.JSONArray;
 import org.json.simple.parser.JSONParser;
 import org.json.simple.parser.ParseException;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.sync.NonArrayJSONException;
 import org.mozilla.gecko.sync.NonObjectJSONException;
+import org.mozilla.gecko.util.IOUtils;
 import org.mozilla.gecko.util.StringUtils;
 
 import ch.boye.httpclientandroidlib.Header;
 import ch.boye.httpclientandroidlib.HttpEntity;
 import ch.boye.httpclientandroidlib.HttpResponse;
 import ch.boye.httpclientandroidlib.HttpStatus;
 import ch.boye.httpclientandroidlib.impl.cookie.DateParseException;
 import ch.boye.httpclientandroidlib.impl.cookie.DateUtils;
@@ -101,22 +102,22 @@ public class MozResponse {
       return new ExtendedJSONObject(body);
     }
 
     HttpEntity entity = this.response.getEntity();
     if (entity == null) {
       throw new IOException("no entity");
     }
 
-    InputStream content = entity.getContent();
+    Reader in = null;
     try {
-      Reader in = new BufferedReader(new InputStreamReader(content, "UTF-8"));
+      in = new BufferedReader(new InputStreamReader(entity.getContent(), StringUtils.UTF_8));
       return new ExtendedJSONObject(in);
     } finally {
-      content.close();
+      IOUtils.safeStreamClose(in);
     }
   }
 
   public JSONArray jsonArrayBody() throws NonArrayJSONException, IOException {
     final JSONParser parser = new JSONParser();
     try {
       if (body != null) {
         // Do it from the cached String.