Inspired by a PPCG answer, I wrote this code, which shuffles the autoboxing caches of Number
subclasses.
This leads to, among other things, outputting 2 + 2 = -72
after invocation of EvilStuff.doEvilStuff(Class<? extends Number>,String,int)
. (The result differs for different invocations, due to reshuffling).
I use a standard Fisher-Yates shuffle. I use reflection to access the autoboxing caches by the designated cacheID
and cacheFieldNumber
parameters, which are cache
and 0
for java.lang.Integer
. java.lang.Integer
is the only class which implements an effective autoboxing cache other than java.math.BigDecimal
, and that is not used much for normal arithmetic. Also, the Integer
stuff is better documented.
I figured I would do this since no one would otherwise think of posting evil code on Code Review, and to serve to warn myself of the dangers of using reflection in the future.
Welcome to the dark side! How would anyone else do this?
/**
* Messes up arithmetic for some cases using reflection to shuffle cache stuffs. Enjoy!
*/
public class EvilStuff{
/**
* Does a Fisher-Yates shuffling of the input.
* @param stuff The array to shuffle
* @return Nothing, array is sorted in-place
*/
public static void shuffle(Object[] stuff){
int length = stuff.length;
for (int i = 0; i < length; i++) {
// Get a random index of the stuff past i.
//truncation (flooring) is necessary to avoid array bounds violations
int random = i + (int) (Math.random() * (length - i));
// Swap the random element with the present element.
Object randomElement = stuff[random];
stuff[random] = stuff[i];
stuff[i] = randomElement;
}
}
/**
* Access the "cache" field of a {@link java.lang.Number} subclass object,
* and shuffle that cache.
*
* Currently known to work only with {@link java.lang.Integer}
* (See the special handling?)
*
* Ridiculous output can only be seen if int (in the range of a {@link java.lang.Byte}
* calculations are autoboxed to java.lang.Integer
*
* Try {@link java.lang.System.out.format(String,Object...)} for best results!
*
* @param victim The class whose cache should be shuffled. Recommend {@link java.lang.Integer}
* @return Nothing, the victim should have been dealt with in-place
*/
public static void doEvilStuff(Class<? extends Number> victim,String cacheID, int cacheFieldNumber){
Class cache = victim.getDeclaredClasses()[cacheFieldNumber];
java.lang.reflect.Field c;
try{
c = cache.getDeclaredField(cacheID);
}catch(NoSuchFieldException noCache){
throw new IllegalArgumentException(String.format("Can't mess with something (%s) without a cache (%s) at %d!"
,victim+"",cacheID,cacheFieldNumber), noCache);
}
c.setAccessible(true);
Object cached;
try{
cached=c.get(cache);
}catch(IllegalAccessException noAccessPermit){
throw new IllegalArgumentException(String.format("Can't access the cache (%s) of %s at %d!",
cacheID,victim+"",cacheFieldNumber), noAccessPermit);
}
Number[] array;
try{
array = (Number[]) cached;
shuffle(array);
}catch(NullPointerException dataLoss){
throw new IllegalArgumentException("Catastrophic data loss (for this program only)!", dataLoss);
}
}
}
A main
class for testing purposes (DISCLAIMER: The following class not up for review):
public class TestEvilStuff {
public static void main(String[] args) {
EvilStuff.doEvilStuff(Integer.class, "cache", 0);
System.out.println("Enter 2 numbers between -64 (-128/2) and 63 (127/2):");
java.util.Scanner in = new java.util.Scanner(System.in);
int n1=Integer.parseInt(in.nextLine()),
n2=Integer.parseInt(in.nextLine());
System.out.format("%d + %d = %d", new Integer(n1), new Integer(n2), n1 + n2);
}
}
Sample outputs:
Enter 2 numbers between -64 (-128/2) and 63 (127/2):
63
64
63 +たす 64 =わ -ひく94
Please find more and suggest how I can improve this. Maybe even make an EvilStuff
library?
-
3\$\begingroup\$ I, on behalf of PPCG, approve of this post. \$\endgroup\$user95591– user955912016年03月18日 17:06:03 +00:00Commented Mar 18, 2016 at 17:06
-
\$\begingroup\$ @CaptainStupid I was just checking the help center to see if this is legal here (by legal, I imply on-topic). Apparently, it is. \$\endgroup\$Tamoghna Chowdhury– Tamoghna Chowdhury2016年03月18日 17:06:50 +00:00Commented Mar 18, 2016 at 17:06
-
3\$\begingroup\$ If this code successfully makes its client code not work as intended, then it's working as intended and is therefore on-topic.. no worries =) \$\endgroup\$Mathieu Guindon– Mathieu Guindon2016年03月18日 17:13:24 +00:00Commented Mar 18, 2016 at 17:13
1 Answer 1
Regarding shuffle
:
- Declare
length
in thefor
loop. - Use
Random.random(int)
instead of(int)(Math.random() * int)
. - Rename
random
toswapIndex
or something more descriptive. - With these changes the comments are unnecessary.
- This method needn't be public.
- Also, I made things final although that's a matter of style.
My version:
private static void shuffle(final Object[] stuff){
final Random r = new Random();
for (int i = 0, length = stuff.length; i < length; i++) {
final int swapIndex = i + r.nextInt(length - i);
final Object randomElement = stuff[swapIndex];
stuff[swapIndex] = stuff[i];
stuff[i] = randomElement;
}
}
Regarding doEvilStuff
:
The proliferation of try/catch
es really clutters the code, especially because you rethrow an IllegalArgumentException
each time. Your code would be more readable if you wrapped the whole method in a try/catch
and used a multi-catch. Actually I would be controversial and advocate catching Exception
because no matter what goes wrong, you want to wrap the exception and provide diagnostic information and it's impractical (and impossible without depending on implementation details) to list every exception that could be thrown. Note that catching Exception
is bad in most circumstances.
However, with this approach of having just one catch
block your error messages can't be quite as descriptive. That's okay as long as the thrown exception includes the parameters and the original exception - any more is IMO excessive.
Another issue with your code is it puts the burden of specifying the index of the nested class on the caller. As all nested classes of Number
type X
are named XCache
, we may use this pattern in doEvilStuff
to automatically find the correct nested class.
My version:
public static void doEvilStuff(Cfinal lass<? extends Number> victim,String cacheID) {
try {
final Class cache = Class.forName(victim.getName() + "$" + victim.getSimpleName() + "Cache");
final java.lang.reflect.Field c = cache.getDeclaredField(cacheID);
c.setAccessible(true);
shuffle((Number[])c.get(cache));
} catch (final Exception e) {
throw new IllegalArgumentException("can't corrupt class " + victim, e);
}
}
-
\$\begingroup\$ Thanks for the simplifying tip for the Number class. I leave it to the caller as the pattern may differ on different JDK implementations, e.g. Android. Maybe a default override would be in order? \$\endgroup\$Tamoghna Chowdhury– Tamoghna Chowdhury2016年03月18日 17:29:34 +00:00Commented Mar 18, 2016 at 17:29
-
\$\begingroup\$ Also, I really like
String.format()
. \$\endgroup\$Tamoghna Chowdhury– Tamoghna Chowdhury2016年03月18日 17:30:26 +00:00Commented Mar 18, 2016 at 17:30 -
\$\begingroup\$ Also, the humorous errors are part of the code :P, so forgive me for not taking your advice about the multi-catch, unless you can tell me how I can properly do it while keeping the error messages. +1 for the Number thing, anyway. \$\endgroup\$Tamoghna Chowdhury– Tamoghna Chowdhury2016年03月18日 17:32:14 +00:00Commented Mar 18, 2016 at 17:32
-
\$\begingroup\$ @TamoghnaChowdhury Okay, feel free to keep those aspects of your code. I didn't mean to advocate concatenation instead of
String.format()
- it's just what I happened to use (and the difference is IMO negligible when there's just one value to insert). \$\endgroup\$Reinstate Monica– Reinstate Monica2016年03月18日 17:33:58 +00:00Commented Mar 18, 2016 at 17:33 -
\$\begingroup\$ Regarding the shuffle stuff, it was a basic copy-paste, so some stuff got carried over. An oversight on my part, anyway. I keep it public as I might use it for other cases. I don't want to import java.util.Random for something this trivial (it doesn't save much except for a cast). However, the final s are a good idea. \$\endgroup\$Tamoghna Chowdhury– Tamoghna Chowdhury2016年03月18日 17:36:19 +00:00Commented Mar 18, 2016 at 17:36