-2

My Android code is behaving funny. The input stream should and does throw an IOException, which correctly causes control to go to // read an error stream. The error stream is read correctly and the debugger steps to return error_message with the error_message variable containing expected characters read from error stream. It then correctly steps to the // no op in the finally block, which I added just for kicks.

And then, it steps to return "all hope lost";!! Which then, instead of returning to the caller, steps into some Android system code that throws a SecurityException with a message about lack of content permissions.

Removing the finally block has no impact -- the bug still happens. The streams being read are from an HTTP URL Connection. No problems if server returns 200 but if server returns 400 it goes through the weird path described above and tries to throw the weird SecurityException.

try {
  // read an input stream into message
  return message;
} catch (IOException outer) {
  try {
    // read an error stream into error_message
    return error_message;
  } catch (IOException inner) {
    return "all hope lost";
  }
} finally {
  // no op, just to step debugger
}

Update: Posting exact code and debug trace.

try {
  /*x*/ BufferedReader buffered_reader = 
        new BufferedReader(
        new InputStreamReader(
        new BufferedInputStream(http_url_connection.getInputStream())));
  StringBuilder string_builder = new StringBuilder();
  String line;
  for (line = buffered_reader.readLine(); 
       line != null; 
       line = buffered_reader.readLine()) {
    string_builder.append(line);
  }
  return string_builder.toString();
} catch (IOException io_exception) {
  this.io_exception = io_exception;
  BufferedReader buffered_reader = 
       new BufferedReader(
       new InputStreamReader(
       new BufferedInputStream(http_url_connection.getErrorStream())));
  StringBuilder string_builder = new StringBuilder();
  try {
    for (String line = buffered_reader.readLine(); 
         line != null; 
         line = buffered_reader.readLine()) {
      string_builder.append(line);
    }
    /*y*/ String error_message = "server error: " + string_builder.toString();
    return error_message;
  } catch (IOException exception) {
    String level_2_error_message = "level 2 error: " + exception.getMessage();
    return level_2_error_message;
  } finally {
    return "foo";
  }
}

Line /*x*/ causes the jump to the first catch as expected. All lines up to /*y*/ are then executed as expected. Then the weird thing is that line /*y*/ does not complete and control immediately goes to either the next catch block if there is no finally or to the finally. If there is a finally then it does not to got the last catch block.

The contents of the string buffer on /*y*/ line look perfectly fine -- a 20 character string from the server.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
necromancer
  • 23,916
  • 22
  • 68
  • 115
  • You do realize instead of this try-catch madness you could just do something like `Log.e(this.getClass().getSimpleName(), "Error in method insertMethodNameHere()", exception);` and that way you actually know what went wrong, right? – EpicPandaForce Aug 15 '14 at 13:44
  • @Zhuinden it is not for debugging. the exceptions are from a network connection and could happen while the user is using the app in the field. so i don't see how `Log.e(...)` would help. – necromancer Aug 15 '14 at 13:47
  • and if in the final block you place a return statement the behaviour is still the same? – eldjon Aug 15 '14 at 13:49
  • @eldjon yes, it is still the same. but i have an update to the question. posting exact code and trace. – necromancer Aug 15 '14 at 13:54
  • if you don't know the actual error, it's hard to find the cause. – EpicPandaForce Aug 15 '14 at 14:04
  • @Zhuinden yes, I might have to reduce this to a self-contained example. – necromancer Aug 15 '14 at 14:05
  • try to close each stream at finally block. it might have to do with stream not closed. – eldjon Aug 15 '14 at 14:07
  • @eldjon thanks for the great suggestion. i'll try it out later today and post the results here. – necromancer Aug 15 '14 at 14:14

1 Answers1

1

You say that an exception is being thrown by line /* y */

By my reading of that line of code, the following are plausible explanations:

  • The exception is a NullPointerException because string_builder is null. But it can't be.

  • The exception is an OutOfMemoryError because you don't have enough free space for the toString() call to create the new String object.

  • It is possible that StringBuilder is not java.lang.StringBuilder but some class you wrote yourself. In that case, any exception is possible.

However, I can't see how you would end up in the second IOException handler.


Apart from that, the only other likely explanation is that that source code does not match the code that you are actually executing; e.g. you forgot to recompile something, or you forgot to redeploy after your last compilation.


For what it is worth, your return in your finally is almost certainly a mistake.

  • It means that you will return "foo" instead of either of the error messages.

  • If (for example) string_builder.toString() did throw an NPE or OOME, then the return would squash it.

A finally with a return can have non-intuitive behaviour. It is certainly NOT something you should do "for debugging"!!!

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • +1 thanks for the great suggestions. The stringbuilder was perfectly fine as far as NPE & OOME. I stepped through it. Yes, the `return "foo"` is wrong. I tried it both with and without. will update after some more sleuthing. – necromancer Aug 15 '14 at 23:34