質問は@mhallerによって良い答えを受け取りました。いわゆるパズルはとても簡単だったと思います。Stringの利用可能なc-torを見るだけで、どの部分を見つけることができるはずです。
ウォークスルー
関心のあるC-torは以下のとおりです。侵入/クラック/セキュリティの脆弱性を探す場合は、常に非最終的な任意のクラスを探してください。ここでのケースはjava.nio.charset.Charset
//String
public String(byte bytes[], int offset, int length, Charset charset) {
if (charset == null)
throw new NullPointerException("charset");
checkBounds(bytes, offset, length);
char[] v = StringCoding.decode(charset, bytes, offset, length);
this.offset = 0;
this.count = v.length;
this.value = v;
}
byte[]
c-torは、ルックアップchartsetName-> charsetを回避するために、チャートセット名ではなく文字セットを渡すことにより、文字列
に変換するためのおそらく高速な方法を提供します。また、任意のCharsetオブジェクトを渡してStringを作成することもできます。文字セットのメインルーティングは、のコンテンツを
java.nio.ByteBuffer
に変換し
CharBuffer
ます。CharBufferはchar[]への参照を保持する場合があり、を介して利用できます
array()
。また、CharBufferは完全に変更可能です。
//StringCoding
static char[] decode(Charset cs, byte[] ba, int off, int len) {
StringDecoder sd = new StringDecoder(cs, cs.name());
byte[] b = Arrays.copyOf(ba, ba.length);
return sd.decode(b, off, len);
}
//StringDecoder
char[] decode(byte[] ba, int off, int len) {
int en = scale(len, cd.maxCharsPerByte());
char[] ca = new char[en];
if (len == 0)
return ca;
cd.reset();
ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
CharBuffer cb = CharBuffer.wrap(ca);
try {
CoderResult cr = cd.decode(bb, cb, true);
if (!cr.isUnderflow())
cr.throwException();
cr = cd.flush(cb);
if (!cr.isUnderflow())
cr.throwException();
} catch (CharacterCodingException x) {
// Substitution is always enabled,
// so this shouldn't happen
throw new Error(x);
}
return safeTrim(ca, cb.position(), cs);
}
Java開発者の変更を防ぐためにchar[]
、他の文字列構造(たとえばpublic String(char value[])
)と同じように配列をコピーします。ただし、例外があります。SecurityManagerがインストールされていない場合、char[]はコピーされません。
//Trim the given char array to the given length
//
private static char[] safeTrim(char[] ca, int len, Charset cs) {
if (len == ca.length
&& (System.getSecurityManager() == null
|| cs.getClass().getClassLoader0() == null))
return ca;
else
return Arrays.copyOf(ca, len);
}
したがって、SecurityManagerがない場合は、文字列によって参照されている変更可能なCharBuffer /char[]を持つことが絶対に可能です。
もコピーされていることを除いて、今ではすべてが正常に見えますbyte[]
(上の太字)。これは、Java開発者が怠惰で大いに間違っていた場所です。
コピーは、不正な文字セット(上記の例)がソースバイト[]を変更できないようにするために必要です。ただし、文字列がほとんど含まれていない約512KBのbyte[]
バッファがある場合を想像してみてください。単一の小さな少数のグラフを作成しようとすると、new String(buf, position, position+32,charset)
512KBの大量のbyte[]コピーが生成されます。バッファが1KB程度の場合、その影響に実際に気付くことはありません。ただし、バッファが大きいと、パフォーマンスへの影響は非常に大きくなります。簡単な修正は、関連する部分をコピーすることです。
...または、java.nio
読み取り専用バッファを導入することで考えた設計者。単に呼び出すだけでByteBuffer.asReadOnlyBuffer()
十分でした(Charset.getClassLoader()!= nullの場合)*作業をしている人でさえ、java.lang
完全に間違っている場合があります。
* Class.getClassLoader()は、ブートストラップクラス、つまりJVM自体に付属しているクラスに対してnullを返します。