From 759b48e336064f46be45b1ce1d2111a6f30b189b Mon Sep 17 00:00:00 2001 From: Inseok Lee Date: Sun, 2 Aug 2026 17:15:31 +0900 Subject: [PATCH] Fix custom class loader registry lookups --- .../src/classes/java/lang/class_loader.rs | 13 +++++----- jvm/src/runtime/java_lang_class_loader.rs | 3 ++- test_data/ClassMetadata$ByteLoader.class | Bin 1306 -> 1538 bytes test_data/ClassMetadata$First.class | Bin 190 -> 171 bytes test_data/ClassMetadata$Payload.class | Bin 287 -> 268 bytes test_data/ClassMetadata$Sample.class | Bin 373 -> 354 bytes test_data/ClassMetadata$Second.class | Bin 192 -> 173 bytes test_data/ClassMetadata.class | Bin 2774 -> 3205 bytes test_data/ClassMetadata.txt | 4 +++ test_data/loader/Base.class | Bin 0 -> 189 bytes test_data/loader/Payload.class | Bin 0 -> 190 bytes test_data/src/ClassMetadata.java | 24 ++++++++++++++++-- test_data/src/loader/Base.java | 4 +++ test_data/src/loader/Payload.java | 4 +++ 14 files changed, 43 insertions(+), 9 deletions(-) create mode 100644 test_data/loader/Base.class create mode 100644 test_data/loader/Payload.class create mode 100644 test_data/src/loader/Base.java create mode 100644 test_data/src/loader/Payload.java diff --git a/java_runtime/src/classes/java/lang/class_loader.rs b/java_runtime/src/classes/java/lang/class_loader.rs index d9e8c999..1ac583ca 100644 --- a/java_runtime/src/classes/java/lang/class_loader.rs +++ b/java_runtime/src/classes/java/lang/class_loader.rs @@ -186,9 +186,10 @@ impl ClassLoader { } let name_str = JavaLangString::to_rust_string(jvm, &name).await?; + let internal_name = name_str.replace('.', "/"); - if let Some(element_type_name) = name_str.strip_prefix('[') { - let ultimate_element_type = element_type_name.trim_start_matches('['); + if let Some(element_type_name) = internal_name.strip_prefix('[') { + let ultimate_element_type = name_str.trim_start_matches('['); let defining_loader = if let Some(element_class_name) = ultimate_element_type.strip_prefix('L').and_then(|name| name.strip_suffix(';')) { let element_class_name = JavaLangString::from_rust_string(jvm, element_class_name).await?; let element_class: ClassInstanceRef = jvm @@ -210,7 +211,7 @@ impl ClassLoader { jvm.invoke_virtual(&parent, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;", (name.clone(),)) .await? } else { - jvm.load_bootstrap_class(&name_str).await?.into() + jvm.load_bootstrap_class(&internal_name).await?.into() }; if !class.is_null() { @@ -243,12 +244,12 @@ impl ClassLoader { ) -> Result> { tracing::debug!("java.lang.ClassLoader::findLoadedClass({this:?}, {name:?})"); - let rust_name = JavaLangString::to_rust_string(jvm, &name).await?; - if !jvm.has_class(&rust_name) { + let internal_name = JavaLangString::to_rust_string(jvm, &name).await?.replace('.', "/"); + if !jvm.has_class(&internal_name) { return Ok(None.into()); } - let class = jvm.resolve_class(&rust_name).await?; + let class = jvm.resolve_class(&internal_name).await?; Ok(class.java_class().into()) } diff --git a/jvm/src/runtime/java_lang_class_loader.rs b/jvm/src/runtime/java_lang_class_loader.rs index c10907fb..f9a53202 100644 --- a/jvm/src/runtime/java_lang_class_loader.rs +++ b/jvm/src/runtime/java_lang_class_loader.rs @@ -17,7 +17,8 @@ impl JavaLangClassLoader { #[allow(clippy::borrowed_box)] pub async fn load_class(jvm: &Jvm, this: &Box, class_name: &str) -> Result>> { - let java_class_name = JavaLangString::from_rust_string(jvm, class_name).await?; + let binary_name = class_name.replace('/', "."); + let java_class_name = JavaLangString::from_rust_string(jvm, &binary_name).await?; let java_class: Option> = jvm .invoke_virtual(this, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;", (java_class_name,)) diff --git a/test_data/ClassMetadata$ByteLoader.class b/test_data/ClassMetadata$ByteLoader.class index 3677d58dad0836556341b39869918fac71064b03..271de3135b1296201bc82f1c3b95c52b3eb4fe37 100644 GIT binary patch literal 1538 zcmZ`(U2_vv7=BK&$tK%POSddGsq#@NB-wlbLev%%TB$~x6etvdafWTO)`gJN?54_{ ze?!JAZ+cs2FwUq0m(2JN{3}iee9ms5O@WJZ_MG?QdEfUr@4Npz|MLlev-ny=1W^@= zju_$s<~@7UF1PIVdU>H`d)`vVZaQ6o_<6VO`kx47vP*9?naiyvkRU+dR&#v2Y5Vr^ zEB3<{Av96Rp# zp<@CE1vJmMyS{hR^}pNa8zR$JmUu|VJD3zmN{ApuftkILURv+3Zcal6Q!3uo@ty>j z9IkKvq3^upXzW|J-3%^a1nGH1$I&3J)CI0dN~d+akK@cHkal`)UqDn7I3X}Kj6dM7 z)R2#nKvrOMK*B(iKwjWrC@b%?E(nYdH1oFSgdi$P0;!=W8cyM~iZePsz*&K@-PZ}s z1SZxU|C-}x!T_7`JpK}tl&cxAL;lQvxEx*4BLW5e0--A-G@mjXxkaZ~U3i+sQ4D=Q6EEXiT2y`>#jS*%o0QF%;WPk(i!I1K%Ei&Aq|VbcwNf9?TYo_O#*@G@cR53VLCXnBI7+-r z`v$)fpo?%3u4sSszY|}mxpc+tkK15uJn89I8 z;R+=wL??GJuHw{1E?lKZVc05nPE#0Kq?wFL%}@DTk8w=7`#X+>N&JkYF;m-uX&EP( zlf345jT=_YC>HuC*Nc6e`#UkKL@O~fmR6qpikV_s365s0*~eTZZpME>dPCbjFF!~6U>Z{i$&;1ozoEU4+x9Yj=U&m}Vz71zWL kj)?z|e1TD^$WRBNGL2orBDhZH2t%y$OEp<8;wBRR1Dmy3!vFvP delta 673 zcmYL{&rTCj6vlsdX3DhFX`o|A!D=Zjly=&Rq7GC*5&T0JCAuL|H#W8=CPWh3r3r~| zKxSizD>vQNg*8!wOB0@fjZa}>2zaI;VUm09xo6Hf-*>)yKiK=0b$Igq09c{EXZ0)# zjWL@f&fZ@?p29V`XmbfCSX6UfiV2&`IEvWoH*Z_(+s#hL1usP*8hUW!FG+nw&l zPNy3j>65!DnJxTuSrJB1+!Ze;(J(&ZmA|3Bh^M$GHdF$}Br_=y5k$^m{&U&G4*9ZU z4v6g&3kyg4UU|TUM&&p0&>QbzRQi&p4VyU_>>}J_xQsF`c7j#;oj@NwCTWsgmBoDt z83I=mD>|P+9uDckQzz|Q9WdFb44C;D-PC=ff$?3=9k=41yE6+7);_^YT)QoO2S3i&Kl)8Tc6)c)=Xs)RM%M#FE5` edz>Vh7`TBNm>75%c!4w*10w@F10RC`0|x-8^AZ{W delta 99 zcmeBSn$N^_>ff$?3=9mm3_=sR+O;|SQj1GG@{3E@8Tc6)c%5?+i;I0zOA=EOOA;9w ucs%p+Qj5TXsl^jFIw>+Ua0B%+G4L?(f@wYm0U*uAz{tSPz{eoSzySbiP!*2= diff --git a/test_data/ClassMetadata$Sample.class b/test_data/ClassMetadata$Sample.class index 6e4a02ab19bec4288e662a5e65991355acf170ad..185fae40e71a76717ffd20c0cf6a89db99c3a368 100644 GIT binary patch delta 96 zcmey$^oWV;)W2Q(7#J8#7{n)X?Ns3L%*#tHa?VLCE>10GXAov&;01GhQ%e$45=#;% sz6;Z2V&DgAU}6wp5Cqav49pDd3_=Vd3>*xcKw6ZIgMk}Ji?MM405f6}{Qv*} delta 98 zcmaFF^p%P0)W2Q(7#J9A86+lh?d0U}OD!(($S*FLctMnx$1^W4wa7UqvA8(3c;e$Q uLuLkkpi(9V0R}-ZEyN%Kq@@^`8Q2+w7(^L37&w8n7#jxzH;@)*;{X6>5fhyN diff --git a/test_data/ClassMetadata$Second.class b/test_data/ClassMetadata$Second.class index a92d9143b24c49b9a9d89fedbc34d7c1f50e17c8..122785e11f87bf253d66ffcec69f9e300d332295 100644 GIT binary patch delta 98 zcmX@WxR#OY)W2Q(7#J8#7`P{Lh4}M$=H;apIp-u67pE4pGjK98@PawMsU?Xii6x1Q p3~a%v$@zIHYzz#H49q}{Ai%`H3MSbY*nu<`P==9#gMo{U0{{`~67c{4 delta 99 zcmZ3>cz}`X)W2Q(7#J9A8F(ggg=lm5r52ZXEqJRj7zRGAONg$?E@n@A2{GVjkRgRPKEE8huyS+xhC+2Z z_l+(!?tC_C)THy%IHabXTC>GTm`#R7yR&8nn};Q5E#fS;tl>3kQ-I>Cte!L}nv5`t zMqI5R27b_MFTR`gIvg-7d$#Ckv2(yHpx0%5IZ*zbihv#PZeW>DFpVt&F5?T7?_%sN zs+}*Ms-*dne$V=jyIYY?SG2(q!DpnhvjjNDQRzIyd1<|s1uk-%Htx~RV>)=lB|dPO zuXOQ)Zsq5S3euwv%V1B^t2$+v5eC#WgX+4B?k>aX0VC>Bl2P@PG4+aw+GbpRWI}yo zQvG5|R}$6r%;*!u^eJX_D{uB@4rO)ya?oue~sk^29=O3{p+FI`eN&%6gMw+$E9`RYo+$*jLc$ikO-GT$O4 z_tak~U+9we6_6iVY2N9M!`YAJPnMJ+9W#`RDLtg`pCN;}rrk!;X_%4|Y|4KjDmQY* kJA1@*i}hai1o}#)>Fh_S$=&wf0$uyB~C}L?iFNzgq@U zl$Rn81O7^2WLsW{&U&}Ko{D$#de5nfSFMiDc{AmCL(xyUyX2x@a{D%K8Y@?Coh#oc zmFKI5LI0_nED9#$-Ki*>ofsUQj7A|yo5pdiwkwKaF!2Ui(nQE;w8u6NlVw6BN)0|H zKuGm_UL}HE&VnU7Yve_p4!tTmKqm*;%OTPv$#a-lj&hGa9&wBp9OtdR?E@$HqKs7r zq@9xz=d|qRj3gP9A09!ceYS) zx+pTKjy|%#Mij@;ZO9>pSj{?Z)QU05wl@8NaEIjl`#)oM&eAu~{@842>k~9?ZD@19 zUC|t#`rB~pJWzLPC^XIgYWbhS9j?wU*kr*bbyrsCHihf8t=*P){ohfIBZSspVf?$1 zn6VzLpJ$OB|B}x&_=dD0Qvd2t;Jp4OS9k7$?%Aca<(lHMV!N(unrZgYPn;{-NoXgo b3w^aMq+Nrjd)cp8(mJhpP3vjJ8A3k*9CU)O diff --git a/test_data/ClassMetadata.txt b/test_data/ClassMetadata.txt index 058d99f0..b5e3255a 100644 --- a/test_data/ClassMetadata.txt +++ b/test_data/ClassMetadata.txt @@ -23,3 +23,7 @@ true true true true +true +true +true +true diff --git a/test_data/loader/Base.class b/test_data/loader/Base.class new file mode 100644 index 0000000000000000000000000000000000000000..0eb08e7e4c79b0f6456db1f574d40c7b32e41601 GIT binary patch literal 189 zcmW+vy9&ZU5S-1^JVbxM!cHwrV<{F2R$>ap{*oMWAtrDp{+E?t;RpCp;$C)PhS?c* zzQ6YezzV|<7Hl6*3>O|@T#AQCDp6mPG%ID^61=slRl6bBv-!oxfDl!UD5Ord;w}l! zt|^#C2UW{scgv(ci>%^HcxpPG%e^upFyW>7jwyUDHAB2y%NVel^crv%FVM5MLq=l* KHebE24;2!79Ivx1~x_p?wtI@l++@9r^Mn^Mg}&U%)HDJJ4Oa( z4b3oi1`b9BKB#;^VkL;h$iU*9p8{0L?~|FA>Q|bZlv)&$n3Mw);R?<#ElN&x%LH+F zpz8Iq63Y@96dBlowt@g75CZK5lAJ)EESS&0z^b*KfpH^PnhQvRq!}2Pfh0GOW@6w0 E0FZ7XfdBvi literal 0 HcmV?d00001 diff --git a/test_data/src/ClassMetadata.java b/test_data/src/ClassMetadata.java index 16719b37..c1ecba4a 100644 --- a/test_data/src/ClassMetadata.java +++ b/test_data/src/ClassMetadata.java @@ -12,12 +12,14 @@ static class Payload { } static class ByteLoader extends ClassLoader { + int findCount; + ByteLoader(ClassLoader parent) { super(parent); } public Class loadClass(String name) throws ClassNotFoundException { - if (!name.equals("ClassMetadata$Payload")) { + if (!name.equals("ClassMetadata$Payload") && !name.startsWith("loader.")) { return super.loadClass(name); } @@ -27,7 +29,16 @@ public Class loadClass(String name) throws ClassNotFoundException { protected Class findClass(String name) throws ClassNotFoundException { try { - java.io.InputStream input = ClassMetadata.class.getResourceAsStream("ClassMetadata$Payload.class"); + findCount++; + String resourceName; + if (name.equals("ClassMetadata$Payload")) { + resourceName = "ClassMetadata$Payload.class"; + } else if (name.equals("loader.Payload")) { + resourceName = "loader/Payload.class"; + } else { + resourceName = "loader/Base.class"; + } + java.io.InputStream input = ClassMetadata.class.getResourceAsStream(resourceName); byte[] bytes = new byte[input.available()]; int offset = 0; while (offset < bytes.length) { @@ -84,5 +95,14 @@ public static void main(String[] args) throws Exception { System.out.println(payloadMatrix.getClassLoader() == customLoader); System.out.println(payloadArray.getComponentType() == payload); System.out.println(payloadMatrix.getComponentType() == payloadArray); + + Class packagedPayload = customLoader.loadClass("loader.Payload"); + Class packagedPayloadAgain = customLoader.loadClass("loader.Payload"); + Class packagedPayloadArray = customLoader.loadClass("[Lloader.Payload;"); + Class packagedPayloadArrayAgain = customLoader.loadClass("[Lloader.Payload;"); + System.out.println(packagedPayload == packagedPayloadAgain); + System.out.println(packagedPayloadArray == packagedPayloadArrayAgain); + System.out.println(packagedPayload.getSuperclass().getClassLoader() == customLoader); + System.out.println(customLoader.findCount == 3); } } diff --git a/test_data/src/loader/Base.java b/test_data/src/loader/Base.java new file mode 100644 index 00000000..54908d18 --- /dev/null +++ b/test_data/src/loader/Base.java @@ -0,0 +1,4 @@ +package loader; + +public class Base { +} diff --git a/test_data/src/loader/Payload.java b/test_data/src/loader/Payload.java new file mode 100644 index 00000000..e7bcddbe --- /dev/null +++ b/test_data/src/loader/Payload.java @@ -0,0 +1,4 @@ +package loader; + +public class Payload extends Base { +}