@@ -866,6 +866,53 @@ public static void mapGetOrDefault(
866866 }
867867 }
868868
869+ @ MethodHook (
870+ type = HookType .BEFORE ,
871+ targetClassName = "java.lang.Enum" ,
872+ targetMethod = "valueOf" ,
873+ targetMethodDescriptor = "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;" )
874+ public static void enumValueOf (
875+ MethodHandle method , Object alwaysNull , Object [] arguments , int hookId ) {
876+ if (arguments .length < 2 ) {
877+ return ;
878+ }
879+ Object enumTypeArg = arguments [0 ];
880+ Object nameArg = arguments [1 ];
881+ if (!(enumTypeArg instanceof Class ) || !(nameArg instanceof String )) {
882+ return ;
883+ }
884+ Class <?> enumClass = (Class <?>) enumTypeArg ;
885+ if (enumClass == null || !enumClass .isEnum ()) {
886+ return ;
887+ }
888+ String candidate = (String ) nameArg ;
889+ if (candidate == null ) {
890+ return ;
891+ }
892+
893+ Enum <?>[] constants ;
894+ try {
895+ constants = (Enum <?>[]) enumClass .getEnumConstants ();
896+ } catch (Exception | LinkageError ignored ) {
897+ return ;
898+ }
899+ if (constants == null || constants .length == 0 ) {
900+ return ;
901+ }
902+
903+ // Skip guidance if the target string is already valid.
904+ for (Enum <?> enumConstant : constants ) {
905+ if (enumConstant .name ().equals (candidate )) {
906+ return ;
907+ }
908+ }
909+
910+ // Guide the fuzzer towards a single valid enum
911+ int index = Math .floorMod (candidate .hashCode (), constants .length );
912+ Enum <?> target = constants [index ];
913+ TraceDataFlowNativeCallbacks .traceStrcmp (candidate , target .name (), 1 , hookId );
914+ }
915+
869916 private static final class Bounds {
870917 private final Object lower ;
871918 private final Object upper ;
0 commit comments