Don't be an Idiot (like me...)
(This is a copy of an article originally posted here. Updates at that link.)
Oh boy.
I don't feel particularly intelligent this evening.
For the last several work days, I've been fighting a bug. A pernicious bug based around security that I couldn't find.
I'd go forwards over my code, and then backwards. Up and down. I'd check web headers, recompile and run all my tests, etc... No joy, still couldn't see the bug.
What was it?
Picture that you've got a class like this:
public class A {
protected String doSomething() {
return getName();
}
private String getName() {
return "six";
}
}
public class B extends A {
private String getName() {
return "seven";
}
}
Later on, in another object I instantiated one of these bad boys:
A foo = new B();
Log.d("Testing", foo.doSomething());
What would you expect to see in the console? Obviously:
09-24 20:34:12.346 25420-25420/com.flippinbits.kcorey.baddaddy D/Testing: six
What I'd meant is for the output to be:
09-24 20:34:12.346 25420-25420/com.flippinbits.kcorey.baddaddy D/Testing: seven
Can you see where I went wrong?
The getName method should have been "protected", at least, or maybe even "public", with a friendly and handy @Override annotation to indicate that we're overriding a method in the ancestor.
I said to myself, "Self," I says, "you done stepped on your crank."
This is an obvious bit of code, right?
But what if you had this:
A foo = new B();
Log.d("Testing", encryptSomething(foo.doSomething(), "FancySecurityMethod"));
}
String encryptSomething(String tagName, String method) {
return Base64.encodeToString((tagName + UUID.randomUUID().toString()).getBytes(), Base64.NO_WRAP);
}
Now, the output is:
09-24 20:34:12.348 25420-25420/com.flippinbits.kcorey.baddaddy D/Testing: c2l4Y2VmNWZlZjctODk0ZC00MGI0LTk1NzUtNjM3NGRjZDM3Y2Qw
How can you tell if that's any different to
c2l4OGMzMTk3NmItNWE4MC00YzVlLWE4NmYtOTU3MTJkMjY5OGFk
...or...
c2V2ZW44NjQzMGI0Zi02MmMwLTQ1NDctOTk2MC1iOWQ2MTY2NGRiMmE=
The fun thing is that there was a third party library handling encryption (that has caused us issues before), as well as a web API that is (by design) rather uncommunicative.
All it would say in this instance is "Bad signature." Exactly accurate, but not terribly helpful.
All the web request headers, as well as the other 6 arguments as well as those of the other 8 involved web calls were correct.
The biggest cause (of my stupidity, I'll admit) is that everywhere else in the code, I did this:
KeyGenerator.encryptSomething(KeyGenerator.getRealName(),"fancyMethod");
You'll notice that I refer back to a common definition of what getRealName is supposed to do. There were three different encryption methods (each of which overrode getRealName()), and lots of other variables involved...but this was the cause.
Instead of using the common name manufacturing functions, I'd reimplemented them marking them private, for some reason. Private methods aren't, of course, overridden. Why would they be?
To make matters worse, I'd done it in a place where I was almost guaranteed to not find the issue.
Damn, another few grey hairs.
Don't be an Idiot (like me)...invent your own way. This one's mine.
iOS Developer
6 年You have to be pretty smart to create a bug like that... and then explain it too! ;)?