/* * Copyright 2009-2012 Michael Dalton * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jtaint; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Random; import java.util.Vector; //[ifJava5+] import java.util.concurrent.CopyOnWriteArrayList; //[fiJava5+] import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.CharArrayWriter; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.PrintStream; import java.io.UnsupportedEncodingException; import java.nio.CharBuffer; import java.nio.charset.Charset; public final class StringTest extends Thread { private static int maxlen = 65536 * 2; private static int nrtest = 1024 * 32; private static int threads; private static volatile boolean fail; private SafeRandom sr; private Charset[] charsets; private Locale[] locales; private static class StringMethod { public static final int S_NEW = 0; public static final int S_CHARAT = 1; public static final int S_CODEPOINT = 2; public static final int S_COMPARETO = 3; public static final int S_CONCAT = 4; public static final int S_CONTAINS = 5; public static final int S_CONTENTEQUALS = 6; public static final int S_COPYVALUEOF = 7; public static final int S_ENDSWITH = 8; public static final int S_EQUALS = 9; public static final int S_GETBYTES = 10; public static final int S_GETCHARS = 11; public static final int S_HASHCODE = 12; public static final int S_INDEXOF = 13; public static final int S_ISEMPTY = 14; public static final int S_LASTINDEXOF = 15; public static final int S_LENGTH = 16; public static final int S_OFFSETBYCODEPOINTS = 17; public static final int S_STARTSWITH = 18; public static final int S_SUBSEQUENCE = 19; public static final int S_SUBSTRING = 20; public static final int S_TOCHARARRAY = 21; public static final int S_TOLOWERCASE = 22; public static final int S_TOSTRING = 23; public static final int S_TOUPPERCASE = 24; public static final int S_TRIM = 25; public static final int S_VALUEOF = 26; public static final int S_ISTAINTED = 27; public static final int S_SERIALIZE = 28; public static final int S_END = 29; public static final String[] methodNames = { "new", "charAt", "codePoint", "compareTo", "concat", "contains", "contentEquals", "copyValueOf", "endsWith", "equals", "getBytes", "getChars", "hashCode", "indexOf", "isEmpty", "lastIndexOf", "length", "offsetByCodePoints", "startsWith", "subSequence", "substring", "toCharArray", "toLowerCase", "toString", "toUpperCase", "trim", "valueOf", "isTainted", "serialize" }; } private static class StringElem { String s; SafeString sfs; int id; List opList; public StringElem(String s, SafeString sfs, int id) { this.s = s; this.sfs = sfs; /* Unlike StringBuffer/Builder, String is an immutable class * and thus StringElems may be accessed concurrently by multiple * threads. Consequently, opList must be a synchronized list to * prevent race conditions in the addOp method. */ this.opList = new Vector(); this.id = id; } public String getString() { return s; } public SafeString getSafeString() { return sfs; } public void addOp(int op) { opList.add(StringMethod.methodNames[op]); } public void addOp(String op) { opList.add(op); } public void verify(String s) throws IllegalArgumentException { if (!sfs.verify(s)) throw new IllegalArgumentException(this.toString()); } public void verify(StringElem otherse) throws IllegalArgumentException { SafeString othersfs = otherse.getSafeString(); if (!sfs.verify(s) || !sfs.verify(otherse.getString()) || !othersfs.verify(otherse.getString()) || !othersfs.verify(s)) throw new IllegalArgumentException(this.toString()); } public void verify() throws IllegalArgumentException { verify(s); } public String toString() { String str = "id " + id + " string " + s + " taint " + s.@internal@taint() + "safestring " + sfs + " safetaint " + sfs.taint() + " operations: "; for (int i = 0; i < opList.size(); i++) str += (String) opList.get(i); return str; } } private static class StringBufferMethod { public static final int SB_NEW = 0; public static final int SB_APPEND = 1; public static final int SB_CAPACITY = 2; public static final int SB_CHARAT = 3; public static final int SB_CODEPOINT = 4; public static final int SB_DELETE = 5; public static final int SB_ENSURECAPACITY = 6; public static final int SB_GETCHARS = 7; public static final int SB_INDEXOF = 8; public static final int SB_INSERT = 9; public static final int SB_LASTINDEXOF = 10; public static final int SB_LENGTH = 11; public static final int SB_OFFSETBYCODEPOINTS = 12; public static final int SB_REPLACE = 13; public static final int SB_REVERSE = 14; public static final int SB_SETCHARAT = 15; public static final int SB_SETLENGTH = 16; public static final int SB_SUBSEQUENCE = 17; public static final int SB_SUBSTRING = 18; public static final int SB_TOSTRING = 19; public static final int SB_TRIMTOSIZE = 20; public static final int SB_SERIALIZE = 21; public static final int SB_END = 22; public static final String[] methodNames = { "new", "append", "capacity", "charAt", "codePoint", "delete", "ensureCapacity", "getChars", "indexOf", "insert", "lastIndexOf", "length", "offsetByCodePoints", "replace", "reverse", "setCharAt", "setLength", "subSequence", "substring", "toString", "trimToSize", "serialize" }; } private static class StringBufferElem { StringBuffer sb; SafeStringBuffer sfsb; int id; List opList; public StringBufferElem(StringBuffer sb, SafeStringBuffer sfsb, int id) { this.sb = sb; this.sfsb = sfsb; this.opList = new ArrayList(); this.id = id; } public StringBuffer getStringBuffer() { return sb; } public SafeStringBuffer getSafeStringBuffer() { return sfsb; } public void addOp(int op) { opList.add(StringBufferMethod.methodNames[op]); } public void verify(StringBuffer sb) throws IllegalArgumentException { if (!sfsb.verify(sb)) throw new IllegalArgumentException(this.toString()); } public void verify(String s) { if (!sfsb.verify(new StringBuffer(s))) throw new IllegalArgumentException(this.toString()); } public void verify(SafeString sfs) { if (!sfsb.verify(new StringBuffer(sfs.toString()))) throw new IllegalArgumentException(this.toString()); } public void verify(StringBufferElem othersbe) throws IllegalArgumentException { SafeStringBuffer othersfsb = othersbe.getSafeStringBuffer(); if (!sfsb.verify(sb) || !sfsb.verify(othersbe.getStringBuffer()) || !othersfsb.verify(othersbe.getStringBuffer()) || !othersfsb.verify(sb)) throw new IllegalArgumentException(this.toString()); } public void verify() throws IllegalArgumentException { verify(sb); } public String toString() { String str = "id " + id + " string " + sb + " taint " + sb.toString().@internal@taint() + "safestring " + sfsb + " taint " + sfsb.taint() + " operations: "; for (int i = 0; i < opList.size(); i++) str += (String) opList.get(i); return str; } } //[ifJava5+] private static class StringBuilderMethod { public static final int SB_NEW = 0; public static final int SB_APPEND = 1; public static final int SB_CAPACITY = 2; public static final int SB_CHARAT = 3; public static final int SB_CODEPOINT = 4; public static final int SB_DELETE = 5; public static final int SB_ENSURECAPACITY = 6; public static final int SB_GETCHARS = 7; public static final int SB_INDEXOF = 8; public static final int SB_INSERT = 9; public static final int SB_LASTINDEXOF = 10; public static final int SB_LENGTH = 11; public static final int SB_OFFSETBYCODEPOINTS = 12; public static final int SB_REPLACE = 13; public static final int SB_REVERSE = 14; public static final int SB_SETCHARAT = 15; public static final int SB_SETLENGTH = 16; public static final int SB_SUBSEQUENCE = 17; public static final int SB_SUBSTRING = 18; public static final int SB_TOSTRING = 19; public static final int SB_TRIMTOSIZE = 20; public static final int SB_SERIALIZE = 21; public static final int SB_END = 22; public static final String[] methodNames = { "new", "append", "capacity", "charAt", "codePoint", "delete", "ensureCapacity", "getChars", "indexOf", "insert", "lastIndexOf", "length", "offsetByCodePoints", "replace", "reverse", "setCharAt", "setLength", "subSequence", "substring", "toString", "trimToSize", "serialize", }; } private static class StringBuilderElem { StringBuilder sb; SafeStringBuilder sfsb; int id; List opList; public StringBuilderElem(StringBuilder sb, SafeStringBuilder sfsb, int id) { this.sb = sb; this.sfsb = sfsb; this.opList = new ArrayList(); this.id = id; } public StringBuilder getStringBuilder() { return sb; } public SafeStringBuilder getSafeStringBuilder() { return sfsb; } public void addOp(int op) { opList.add(StringBuilderMethod.methodNames[op]); } public void verify(StringBuilder sb) throws IllegalArgumentException { if (!sfsb.verify(sb)) throw new IllegalArgumentException(this.toString()); } public void verify(StringBuilderElem othersbe) throws IllegalArgumentException { SafeStringBuilder othersfsb = othersbe.getSafeStringBuilder(); if (!sfsb.verify(sb) || !sfsb.verify(othersbe.getStringBuilder()) || !othersfsb.verify(othersbe.getStringBuilder()) || !othersfsb.verify(sb)) throw new IllegalArgumentException(this.toString()); } public void verify(String s) { if (!sfsb.verify(new StringBuilder(s))) throw new IllegalArgumentException(this.toString()); } public void verify(SafeString sfs) { if (!sfsb.verify(new StringBuilder(sfs.toString()))) throw new IllegalArgumentException(this.toString()); } public void verify() throws IllegalArgumentException { verify(sb); } public String toString() { String str = "id " + id + " string " + sb + " taint " + sb.toString().@internal@taint() + "safestring " + sfsb + " taint " + sfsb.taint() + " operations: "; for (int i = 0; i < opList.size(); i++) str += (String) opList.get(i); return str; } } //[fiJava5+] private static class CharSequenceElem { CharSequence cs; SafeCharSequence sfcs; Object origElem; public CharSequenceElem(CharSequence cs, SafeCharSequence sfcs, Object origElem) { this.cs = cs; this.sfcs = sfcs; this.origElem = origElem; } public CharSequence getCharSequence() { return cs; } public SafeCharSequence getSafeCharSequence() { return sfcs; } public Object getOrigElem() { return origElem; } public void release() { if (origElem == null) return; else if (origElem instanceof StringElem) { origElem = cs = sfcs = null; return; } else if (origElem instanceof StringBufferElem) { stringBufferList.add((StringBufferElem)origElem); origElem = cs = sfcs = null; return; //[ifJava5+] } else if (origElem instanceof StringBuilderElem) { origElem = cs = sfcs = null; stringBuilderList.add((StringBuilderElem)origElem); return; //[fiJava5+] } else throw new RuntimeException("unknown charsequence"); } } public StringTest(SafeRandom sr) { this.sr = sr; locales = Locale.getAvailableLocales(); Collection c = Charset.availableCharsets().values(); charsets = (Charset[]) c.toArray(new Charset[0]); } //[ifJava5+] // List of all Strings, concurrently accessed static List stringList = new CopyOnWriteArrayList(); //[fiJava5+] //[ifJava4] static List stringList = new Vector(); //[fiJava4] /* List of all StringBuffers, synchronized */ static List stringBufferList = new Vector(); /* List of all StringBuilders, synchronized */ //[ifJava5+] static List stringBuilderList= new Vector(); private int randomCodePoint() { return Character.MIN_CODE_POINT + sr.nextInt(Character.MAX_CODE_POINT - Character.MIN_CODE_POINT); } private int[] randomCodePointArray() { int len = sr.nextInt(maxlen); int[] cp = new int[len]; for (int i = 0; i < len; i++) cp[i] = randomCodePoint(); return cp; } private char randomChar() { return Character.toChars(randomCodePoint())[0]; } private char[] randomCharArray() { CharArrayWriter cw = new CharArrayWriter(); int[] cp = randomCodePointArray(); for (int i = 0 ; i < cp.length; i++) { char[] c = Character.toChars(cp[i]); cw.write(c, 0, c.length); } return cw.toCharArray(); } //[fiJava5+] //[ifJava4] private char randomChar() { return (char) sr.nextInt(0xffff + 1); } private char[] randomCharArray() { int len = sr.nextInt(maxlen); char[] c = new char[len]; for (int i = 0; i < len; i++) c[i] = randomChar(); return c; } //[fiJava4] private byte[] randomByteArray() { return new String(randomCharArray()).getBytes(); } private byte[] randomAsciiByteArray() { int len = sr.nextInt(maxlen); byte[] b = new byte[len]; for (int i = 0; i < len; i++) b[i] = (byte) sr.nextInt(128); return b; } private StringElem getRandomStringElem() { /* we only add elements to stringList -- do not synchronize here. */ if (stringList.size() == 0) return null; return (StringElem) stringList.get(sr.nextInt(stringList.size())); } private StringBufferElem removeRandomStringBufferElem() { synchronized (stringBufferList) { if (stringBufferList.size() == 0) return null; return (StringBufferElem) stringBufferList.remove( sr.nextInt(stringBufferList.size())); } } //[ifJava5+] private StringBuilderElem removeRandomStringBuilderElem() { synchronized(stringBuilderList) { if (stringBuilderList.size() == 0) return null; return (StringBuilderElem) stringBuilderList.remove( sr.nextInt(stringBuilderList.size())); } } //[fiJava5+] private CharSequenceElem randomCharSequenceElem() { CharSequenceElem cse = null; while (cse == null) { switch(sr.nextInt(4)) { case 0: { StringElem se = getRandomStringElem(); if (se != null) { CharSequence c; SafeCharSequence sfc; c = (CharSequence) se.getString(); sfc = (SafeCharSequence) se.getSafeString(); cse = new CharSequenceElem(c, sfc, se); } break; } case 1: { StringBufferElem sbe = removeRandomStringBufferElem(); if (sbe != null) { CharSequence c; SafeCharSequence sfc; c = (CharSequence) sbe.getStringBuffer(); sfc = (SafeCharSequence) sbe.getSafeStringBuffer(); cse = new CharSequenceElem(c, sfc, sbe); } break; } case 2: //[ifJava5+] { StringBuilderElem sbe = removeRandomStringBuilderElem(); if (sbe != null) { CharSequence c; SafeCharSequence sfc; c = (CharSequence) sbe.getStringBuilder(); sfc = (SafeCharSequence) sbe.getSafeStringBuilder(); cse = new CharSequenceElem(c, sfc, sbe); } break; } //[fiJava5+] //...else fall through case 3: { char[] c = randomCharArray(); CharBuffer cb = CharBuffer.wrap(c); SafeCharBuffer sfcb = SafeCharBuffer.wrap((char[])c.clone()); cse = new CharSequenceElem(cb, sfcb, null); break; } default: throw new RuntimeException("switch"); } } return cse; } private Charset randomCharset() { /* XXX Not all charsets can handle arbitrary byte sequences * For now, we stick with UTF-8 * return charsets[sr.nextInt(charsets.length)]; */ return Charset.forName("UTF-8"); } private Locale randomLocale() { return locales[sr.nextInt(locales.length)]; } private void testStringNew() throws UnsupportedEncodingException { String s = null; OrigString os = null; SafeString sfs; BitSet b = new BitSet(); Charset c = randomCharset(); switch(sr.nextInt(8)) { case 0: /* String() */ s = new String(); sfs = new SafeString(); break; case 1: /* String (byte[] bytes, ... */ { byte[] bytes = randomByteArray(); int offset = sr.nextInt(bytes.length); int length = bytes.length - offset; int type = sr.nextInt(6); switch(type) { case 0: s = new String(bytes); os = new OrigString(bytes); break; case 1: //[ifJava6] s = new String(bytes, c); os = new OrigString(bytes, c); break; //[fiJava6] // ...else fall through case 2: s = new String(bytes, offset, length); os = new OrigString(bytes, offset, length); break; case 3: //[ifJava6] s = new String(bytes, offset, length, c); os = new OrigString(bytes, offset, length, c); break; //[fiJava6] // ...else fall through case 4: s = new String(bytes, offset, length, c.name()); os = new OrigString(bytes, offset, length, OrigStringUtil.toOrig(c.name())); break; case 5: s = new String(bytes, c.name()); os = new OrigString(bytes, OrigStringUtil.toOrig(c.name())); break; default: throw new RuntimeException("switch"); } for (int i = 0; i < s.length(); i++) b.set(i, sr.nextBoolean()); s = new String(s, new Taint(b, s.length())); sfs = new SafeString(os, new SafeTaint(b, s.length())); break; } case 2: /* String(byte[] ascii, ....) */ { byte[] bytes = randomAsciiByteArray(); /* XXX: offset might potentially break up a surrogate pair */ int offset = sr.nextInt(bytes.length); int length = bytes.length - offset; boolean useOffset = sr.nextBoolean(); if (useOffset) { s = new String(bytes, 0, offset, length); os = new OrigString(bytes, 0, offset, length); } else { s = new String(bytes, 0); os = new OrigString(bytes, 0); } for (int i = 0; i < s.length(); i++) b.set(i, sr.nextBoolean()); s = new String(s, new Taint(b, s.length())); sfs = new SafeString(os, new SafeTaint(b, s.length())); break; } case 3: /* String(char[] ....) */ { char[] chars = randomCharArray(); /* XXX: offset might potentially break up a surrogate pair */ int offset = sr.nextInt(chars.length); int length = chars.length - offset; boolean useOffset = sr.nextBoolean(); if (useOffset) { s = new String(chars, offset, length); os = new OrigString(chars ,offset, length); } else { s = new String(chars); os = new OrigString(chars); } for (int i = 0; i < s.length(); i++) b.set(i, sr.nextBoolean()); s = new String(s, new Taint(b, s.length())); sfs = new SafeString(os, new SafeTaint(b, s.length())); break; } case 4: /* String(int[]....) */ { //[ifJava5+] int[] cps = randomCodePointArray(); // XXX: offset might potentially break up a surrogate pair int offset = sr.nextInt(cps.length); int length = cps.length - offset; s = new String(cps, offset, length); os = new OrigString(cps, offset, length); for (int i = 0; i < s.length(); i++) b.set(i, sr.nextBoolean()); s = new String(s, new Taint(b, s.length())); sfs = new SafeString(os, new SafeTaint(b, s.length())); break; //[fiJava5+] // ...else fall through } case 5: /* String(String...) */ { StringElem otherse; otherse = getRandomStringElem(); if (otherse == null) return; s = new String(otherse.getString()); sfs = new SafeString(otherse.getSafeString()); break; } case 6: /* String(StringBuilder...) */ { //[ifJava5+] StringBuilderElem othersbe; othersbe = removeRandomStringBuilderElem(); if (othersbe == null) return; s = new String(othersbe.getStringBuilder()); sfs = new SafeString(othersbe.getSafeStringBuilder()); stringBuilderList.add(othersbe); break; //[fiJava5+] //...else fall through } case 7: /* String(StringBuffer...) */ { StringBufferElem othersbe; othersbe = removeRandomStringBufferElem(); if (othersbe == null) return; s = new String(othersbe.getStringBuffer()); sfs = new SafeString(othersbe.getSafeStringBuffer()); stringBufferList.add(othersbe); break; } default: throw new RuntimeException("switch error"); } StringElem se = new StringElem(s, sfs, sr.nextInt()); se.verify(); se.addOp(StringMethod.S_NEW); stringList.add(se); } private void testStringCharAt(StringElem se) { String s = se.getString(); SafeString sfs = se.getSafeString(); int index; if (sr.nextInt(16) == 0) index = sr.nextInt(); else index = sr.nextInt(s.length()); if (index < 0 || index >= s.length()) { SafeString oldsfs = new SafeString(se.getSafeString()); boolean caught = false; try { s.charAt(index); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(se.toString()); caught = false; try { sfs.charAt(index); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfs.verify(s)) throw new IllegalArgumentException(se.toString()); } else { if (s.charAt(index) != sfs.charAt(index)) throw new IllegalArgumentException(se.toString()); } } //[ifJava5+] private void testStringCodePointAt(StringElem se) { String s = se.getString(); SafeString sfs = se.getSafeString(); int index; if (sr.nextInt(16) == 0) index = sr.nextInt(); else index = sr.nextInt(s.length()); if (index < 0 || index >= s.length()) { SafeString oldsfs = new SafeString(se.getSafeString()); boolean caught = false; try { s.codePointAt(index); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(se.toString()); caught = false; try { sfs.codePointAt(index); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfs.verify(s)) throw new IllegalArgumentException(se.toString()); } else { if (s.codePointAt(index) != sfs.codePointAt(index)) throw new IllegalArgumentException(se.toString()); } } private void testStringCodePointBefore(StringElem se) { String s = se.getString(); SafeString sfs = se.getSafeString(); int index; if (sr.nextInt(16) == 0) index = sr.nextInt(); else index = 1 + sr.nextInt(s.length()); if (index < 1 || index > s.length()) { SafeString oldsfs = new SafeString(se.getSafeString()); boolean caught = false; try { s.codePointBefore(index); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(se.toString()); caught = false; try { sfs.codePointBefore(index); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfs.verify(s)) throw new IllegalArgumentException(se.toString()); } else { if (s.codePointBefore(index) != sfs.codePointBefore(index)) throw new IllegalArgumentException(se.toString()); } } private void testStringCodePointCount(StringElem se) { String s = se.getString(); SafeString sfs = se.getSafeString(); int beginIndex, endIndex; if (sr.nextInt(16) == 0) { beginIndex = sr.nextInt(); endIndex = sr.nextInt(); } else { beginIndex = sr.nextInt(s.length()); endIndex = beginIndex + sr.nextInt(s.length() + 1 - beginIndex); } if (beginIndex < 0 || endIndex > s.length() || beginIndex > endIndex) { SafeString oldsfs = new SafeString(se.getSafeString()); boolean caught = false; try { s.codePointCount(beginIndex, endIndex); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(se.toString()); caught = false; try { sfs.codePointCount(beginIndex, endIndex); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfs.verify(s)) throw new IllegalArgumentException(se.toString()); } else { if (s.codePointCount(beginIndex, endIndex) != sfs.codePointCount(beginIndex, endIndex)) throw new IllegalArgumentException(se.toString()); } } private void testStringCodePoint(StringElem se) { switch (sr.nextInt(3)) { case 0: testStringCodePointAt(se); break; case 1: testStringCodePointBefore(se); break; case 2: testStringCodePointCount(se); break; default: throw new RuntimeException("switched failed"); } } //[fiJava5+] private void testStringConcat(StringElem se) { String s = se.getString(); SafeString sfs = se.getSafeString(); StringElem otherse; SafeString newsfs; String news; StringElem newse; otherse = getRandomStringElem(); news = s.concat(otherse.getString()); newsfs = sfs.concat(otherse.getSafeString()); otherse.verify(); if (!newsfs.verify(news) || news.length() != s.length() + otherse.getString().length()) throw new IllegalArgumentException("Concat verify failed"); Taint newt = news.@internal@taint(); Taint othert = otherse.getString().@internal@taint(); if (newt == null) newt = new Taint(false, news.length()); if (othert == null) othert = new Taint(false, otherse.getString().length()); for (int i = s.length(); i < news.length(); i++) { if (news.charAt(i) != otherse.getString().charAt(i - se.getString().length()) || newt.get(i) != othert.get(i - se.getString().length())) throw new IllegalArgumentException("Concat taint/data failed"); } newse = new StringElem(news, newsfs, sr.nextInt()); newse.addOp(StringMethod.S_NEW); newse.verify(); stringList.add(newse); } private void testStringCompareTo(StringElem se) { String s = se.getString(); SafeString sfs = se.getSafeString(); StringElem otherse = getRandomStringElem(); boolean ignoreCase = sr.nextBoolean(); if (ignoreCase) { if (s.compareToIgnoreCase(otherse.getString()) != sfs.compareToIgnoreCase(otherse.getSafeString())) throw new IllegalArgumentException(se.toString()); } else { if (s.compareTo(otherse.getString()) != sfs.compareTo(otherse.getSafeString())) throw new IllegalArgumentException(se.toString()); } } private void testStringContains(StringElem se) { //[ifJava5+] String s = se.getString(); SafeString sfs = se.getSafeString(); CharSequenceElem cse = randomCharSequenceElem(); if (s.contains(cse.getCharSequence()) != sfs.contains(cse.getSafeCharSequence())) throw new IllegalArgumentException(se.toString()); cse.release(); //[fiJava5+] } private void testStringContentEquals(StringElem se) { String s = se.getString(); SafeString sfs = se.getSafeString(); StringBufferElem sbe; CharSequenceElem cse; if (sr.nextBoolean()) { sbe = removeRandomStringBufferElem(); if (sbe == null) return; if (s.contentEquals(sbe.getStringBuffer()) != sfs.contentEquals(sbe.getSafeStringBuffer())) throw new IllegalArgumentException(se.toString()); } //[ifJava5+] else { cse = randomCharSequenceElem(); if (cse == null) return; if (s.contentEquals(cse.getCharSequence()) != sfs.contentEquals(cse.getSafeCharSequence())) throw new IllegalArgumentException(se.toString()); cse.release(); } //[fiJava5+] } private void testStringCopyValueOf() { String s; SafeString sfs; char[] c = randomCharArray(); int offset, count; offset = sr.nextInt(c.length); count = sr.nextInt(c.length - offset); if (sr.nextBoolean()) { s = String.copyValueOf(c); sfs = SafeString.copyValueOf(c); } else { s = String.copyValueOf(c, offset, count); sfs = SafeString.copyValueOf(c, offset, count); } sfs.verify(s); } private void testStringSubstring(StringElem se) { String s = se.getString(); int beginIndex, endIndex; StringElem subse; String subs; SafeString subsfs; if (sr.nextInt(16) == 0) { beginIndex = sr.nextInt(); endIndex = sr.nextInt(); } else { beginIndex = sr.nextInt(s.length()); endIndex = beginIndex + sr.nextInt(s.length()+ 1 - beginIndex); } if (beginIndex < 0 || endIndex > s.length() || beginIndex > endIndex) { /* Exception time */ SafeString oldsfs = new SafeString(se.getSafeString()); boolean caught = false; try { subs = s.substring(beginIndex, endIndex); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(se.toString()); caught = false; try { subsfs = se.getSafeString().substring(beginIndex, endIndex); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfs.verify(s)) throw new IllegalArgumentException(se.toString()); } else { if (endIndex == s.length() && sr.nextBoolean()) { subs = s.substring(beginIndex); subsfs = se.getSafeString().substring(beginIndex); } else { subs = s.substring(beginIndex, endIndex); subsfs = se.getSafeString().substring(beginIndex, endIndex); } subsfs.verify(subs); Taint t = s.@internal@taint(); Taint subt = subs.@internal@taint(); if (t == null) t = new Taint(false, s.length()); if (subt == null) subt = new Taint(false, subs.length()); for (int i = beginIndex; i < endIndex; i++) if (s.charAt(i) != subs.charAt(i - beginIndex) || t.get(i) != subt.get(i-beginIndex)) throw new IllegalArgumentException("string taint/data bad"); subse = new StringElem(subs, subsfs, sr.nextInt()); subse.verify(); subse.addOp(StringMethod.S_SUBSTRING); stringList.add(subse); } } private void testStringSubSequence(StringElem se) { String s = se.getString(); SafeString sfs = se.getSafeString(); int beginIndex, endIndex; CharSequence subs; SafeCharSequence subsfs; if (sr.nextInt(16) == 0) { beginIndex = sr.nextInt(); endIndex = sr.nextInt(); } else { beginIndex = sr.nextInt(s.length()); endIndex = beginIndex + sr.nextInt(s.length()+ 1 - beginIndex); } if (beginIndex < 0 || endIndex > s.length() || beginIndex > endIndex) { /* Exception time */ SafeString oldsfs = new SafeString(se.getSafeString()); boolean caught = false; try { subs = s.subSequence(beginIndex, endIndex); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(se.toString()); caught = false; try { subsfs = (SafeCharSequence) sfs.subSequence(beginIndex, endIndex); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfs.verify(s)) throw new IllegalArgumentException(se.toString()); } else { subs = s.subSequence(beginIndex, endIndex); subsfs = (SafeCharSequence) sfs.subSequence(beginIndex, endIndex); subsfs.toSafeString().verify(subs.toString()); Taint t = s.@internal@taint(); Taint subt = subs.toString().@internal@taint(); if (t == null) t = new Taint(false, s.length()); if (subt == null) subt = new Taint(false, subs.length()); for (int i = beginIndex; i < endIndex; i++) { if (s.charAt(i) != subs.charAt(i - beginIndex) || t.get(i) != subt.get(i-beginIndex)) throw new IllegalArgumentException("string taint/data bad"); } } } private void testStringToCharArray(StringElem se) { if (!Arrays.equals(se.getString().toCharArray(), se.getSafeString().toCharArray())) throw new IllegalArgumentException(se.toString()); } private void testStringToString(StringElem se) { String s = se.getString(); SafeString sfs = se.getSafeString(); sfs.verify(s.toString()); sfs.verify(sfs.toString()); if (s.toString() != s) throw new IllegalArgumentException(se.toString()); } private void testStringTrim(StringElem se) { String s = se.getString(); SafeString sfs = se.getSafeString(); String trims = s.trim(); SafeString trimsfs = sfs.trim(); StringElem trimse = new StringElem(trims, trimsfs, sr.nextInt()); trimse.verify(); trimse.addOp(StringMethod.S_TRIM); stringList.add(trimse); } //[ifJava5+] private void verifyStringCase(String orig, String result, Locale l, boolean isUpper) { int olen = orig.length(), rlen = result.length(); int ocount, rcount; int i, j; Taint otaint = orig.@internal@taint(); Taint rtaint = result.@internal@taint(); if (otaint == null) otaint = new Taint(false, orig.length()); if (rtaint == null) rtaint = new Taint(false, result.length()); for (i = 0, j = 0; i < olen && j < rlen ; i += ocount, j += rcount) { int ochar = orig.codePointAt(i); int rchar; boolean tainted = false, changed = false; ocount = Character.charCount(ochar); if (isUpper) rchar = String.@internal@toUpperCaseEx(orig, i, l); else rchar = String.@internal@toLowerCaseEx(orig, i, l); if (!String.@internal@isError(rchar)) { rcount = Character.charCount(rchar); if (result.codePointAt(j) != rchar) throw new IllegalArgumentException("conversion error"); } else { char[] rtmp; if (isUpper) { rtmp = String.@internal@toUpperCaseCharArray(orig, i, l); rcount = rtmp.length; } else { rtmp = String.@internal@toLowerCaseCharArray(orig, i, l); rcount = rtmp.length; } for (int m = 0; m < rtmp.length; m++) if (result.charAt(j+m) != rtmp[m]) throw new IllegalArgumentException("conversion error"); } if (ocount != rcount) changed = true; for (int k = 0; !changed && k < ocount; k++) if (orig.charAt(i+k) != result.charAt(j+k)) changed = true; for (int k = 0 ;k < ocount; k++) if (otaint.get(i+k)) tainted = true; if (!changed) { for (int m = 0; m < ocount; m++) if (otaint.get(i+m) != rtaint.get(j+m)) throw new IllegalArgumentException("taint error"); } else { for (int m = 0; m < rcount; m++) if (rtaint.get(j+m) != tainted) throw new IllegalArgumentException("taint error"); } } if (i != olen || j != rlen) throw new IllegalArgumentException("toXCase length error"); } private void verifySafeStringCase(SafeString orig, SafeString result, Locale l, boolean isUpper) { int olen = orig.length(), rlen = result.length(); int ocount, rcount; int i, j; SafeTaint otaint = orig.taint(); SafeTaint rtaint = result.taint(); for (i = 0, j = 0; i < olen && j < rlen ; i += ocount, j += rcount) { int ochar = orig.codePointAt(i); int rchar; boolean tainted = false, changed = false; ocount = Character.charCount(ochar); if (isUpper) rchar = orig.toUpperCaseEx(i, l); else rchar = orig.toLowerCaseEx(i, l); if (!SafeString.isError(rchar)) { rcount = Character.charCount(rchar); if (result.codePointAt(j) != rchar) throw new IllegalArgumentException("conversion error"); } else { char[] rtmp; if (isUpper) { rtmp = orig.toUpperCaseCharArray(i, l); rcount = rtmp.length; } else { rtmp = orig.toLowerCaseCharArray(i, l); rcount = rtmp.length; } for (int m = 0; m < rtmp.length; m++) if (result.charAt(j+m) != rtmp[m]) throw new IllegalArgumentException("conversion error"); } if (ocount != rcount) changed = true; for (int k = 0; !changed && k < ocount; k++) if (orig.charAt(i+k) != result.charAt(j+k)) changed = true; for (int k = 0 ;k < ocount; k++) if (otaint.get(i+k)) tainted = true; if (!changed) { for (int m = 0; m < ocount; m++) if (otaint.get(i+m) != rtaint.get(j+m)) throw new IllegalArgumentException("taint error"); } else { for (int m = 0; m < rcount; m++) if (rtaint.get(j+m) != tainted) throw new IllegalArgumentException("taint error"); } } if (i != olen || j != rlen) throw new IllegalArgumentException("toXCase length error"); } //[fiJava5+] //[ifJava4] private void verifyStringCase(String orig, String result, Locale l, boolean isUpper) { int olen = orig.length(), rlen = result.length(); int rcount, i, j; Taint otaint = orig.@internal@taint(); Taint rtaint = result.@internal@taint(); if (otaint == null) otaint = new Taint(false, orig.length()); if (rtaint == null) rtaint = new Taint(false, result.length()); if (isUpper == false) { if (!otaint.asBitSet().equals(rtaint.asBitSet()) || olen != rlen) throw new IllegalArgumentException("Unexpected value for " + "toLowerCase: orig " + orig + " result " + result); return; } for (i = 0, j = 0; i < olen && j < rlen ; i++, j += rcount) { char ochar = orig.charAt(i); char[] rchars = new char[] {String.@internal@toUpperCaseEx(ochar)}; boolean tainted = otaint.get(i), changed = false; if ("tr".equals(l.getLanguage()) && (ochar == 'i' || ochar == '\u0131')) { if (ochar == 'i') rchars[0] = '\u0130'; else rchars[0] = 'I'; rcount = 1; } else if (!String.@internal@isError(rchars[0])) { rcount = 1; } else { rchars = String.@internal@toUpperCaseCharArray(ochar); rcount = rchars.length; } for (int m = 0; m < rcount; m++) { if (result.charAt(j+m) != rchars[m]) throw new IllegalArgumentException("conversion error"); if (rtaint.get(j+m) != tainted) throw new IllegalArgumentException("taint error"); } } if (i != olen || j != rlen) throw new IllegalArgumentException("toXCase length error"); } private void verifySafeStringCase(SafeString orig, SafeString result, Locale l, boolean isUpper) { int olen = orig.length(), rlen = result.length(); int rcount, i, j; SafeTaint otaint = orig.taint(); SafeTaint rtaint = result.taint(); if (isUpper == false) { if (!otaint.asBitSet().equals(rtaint.asBitSet()) || olen != rlen) throw new IllegalArgumentException("Unexpected value for " + "toLowerCase: orig " + orig + " result " + result); return; } for (i = 0, j = 0; i < olen && j < rlen ; i++, j += rcount) { char ochar = orig.charAt(i); char[] rchars = new char[] {SafeString.toUpperCaseEx(ochar)}; boolean tainted = otaint.get(i), changed = false; if ("tr".equals(l.getLanguage()) && (ochar == 'i' || ochar == '\u0131')) { if (ochar == 'i') rchars[0] = '\u0130'; else rchars[0] = 'I'; rcount = 1; } else if (!SafeString.isError(rchars[0])) { rcount = 1; } else { rchars = SafeString.toUpperCaseCharArray(ochar); rcount = rchars.length; } for (int m = 0; m < rcount; m++) { if (result.charAt(j+m) != rchars[m]) throw new IllegalArgumentException("conversion error"); if (rtaint.get(j+m) != tainted) throw new IllegalArgumentException("taint error"); } } if (i != olen || j != rlen) throw new IllegalArgumentException("toXCase length error"); } //[fiJava4] private void testStringToLowerCase(StringElem se) { String s = se.getString(); SafeString sfs = se.getSafeString(); Locale l; String lowers; SafeString lowersfs; StringElem lowerse; if (sr.nextBoolean()) { l = randomLocale(); lowers = s.toLowerCase(l); lowersfs = sfs.toLowerCase(l); } else { l = Locale.getDefault(); lowers = s.toLowerCase(); lowersfs = sfs.toLowerCase(); } lowerse = new StringElem(lowers, lowersfs, sr.nextInt()); lowerse.verify(); verifyStringCase(s, lowers, l, false); verifySafeStringCase(sfs, lowersfs, l, false); lowerse.addOp(StringMethod.S_TOLOWERCASE); stringList.add(lowerse); } private void testStringToUpperCase(StringElem se) { String s = se.getString(); SafeString sfs = se.getSafeString(); Locale l; String uppers; SafeString uppersfs; StringElem upperse; if (sr.nextBoolean()) { l = randomLocale(); uppers = s.toUpperCase(l); uppersfs = sfs.toUpperCase(l); } else { l = Locale.getDefault(); uppers = s.toUpperCase(); uppersfs = sfs.toUpperCase(); } upperse = new StringElem(uppers, uppersfs, sr.nextInt()); upperse.verify(); verifyStringCase(s, uppers, l, true); verifySafeStringCase(sfs, uppersfs, l, true); upperse.addOp(StringMethod.S_TOUPPERCASE); stringList.add(upperse); } private void testStringValueOf() { String s = null; SafeString sfs = null; StringElem se; switch(sr.nextInt(9)) { case 0: { boolean b = sr.nextBoolean(); s = String.valueOf(b); sfs = SafeString.valueOf(b); break; } case 1: { char c = randomChar(); s = String.valueOf(c); sfs = SafeString.valueOf(c); break; } case 2: { char[] c = randomCharArray(); s = String.valueOf(c); sfs = SafeString.valueOf(c); break; } case 3: { char[] c = randomCharArray(); int offset, len; if (sr.nextInt(16) == 0) { offset = sr.nextInt(); len = sr.nextInt(); } else { offset = sr.nextInt(c.length); len = sr.nextInt(c.length - offset); } if (offset < 0 || len < 0 || offset + len > c.length || offset + len < 0) { /* Exception time */ boolean caught = false; try { s = String.valueOf(c, offset, len); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(s); caught = false; try { sfs = SafeString.valueOf(c, offset, len); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(s); } else { s = String.valueOf(c, offset, len); sfs = SafeString.valueOf(c, offset, len); } break; } case 4: { double d = sr.nextDouble(); s = String.valueOf(d); sfs = SafeString.valueOf(d); break; } case 5: { float f = sr.nextFloat(); s = String.valueOf(f); sfs = SafeString.valueOf(f); break; } case 6: { int i = sr.nextInt(); s = String.valueOf(i); sfs = SafeString.valueOf(i); break; } case 7: { long l = sr.nextLong(); s = String.valueOf(l); sfs = SafeString.valueOf(l); break; } case 8: { StringElem otherse = getRandomStringElem(); s = String.valueOf(otherse.getString()); sfs = SafeString.valueOf(otherse.getSafeString()); break; } default: throw new RuntimeException("switch"); } if (s == null || sfs == null) { if (sfs != null || s != null) throw new IllegalArgumentException("nullity"); return; } se = new StringElem(s, sfs, sr.nextInt()); se.verify(); se.addOp(StringMethod.S_VALUEOF); stringList.add(se); } private void testStringEndsWith(StringElem se) { String s = se.getString(); SafeString sfs = se.getSafeString(); StringElem otherse = getRandomStringElem(); String others = otherse.getString(); SafeString othersfs = otherse.getSafeString(); otherse.verify(); if (s.endsWith(others) != sfs.endsWith(othersfs)) throw new IllegalArgumentException(se.toString()); } private void testStringEquals(StringElem se) { String s = se.getString(); SafeString sfs = se.getSafeString(); StringElem otherse = getRandomStringElem(); String others = otherse.getString(); SafeString othersfs = otherse.getSafeString(); boolean ignoreCase = sr.nextBoolean(); otherse.verify(); if (ignoreCase) { if (s.equalsIgnoreCase(others) != sfs.equalsIgnoreCase(othersfs)) throw new IllegalArgumentException(se.toString()); } else { if (s.equals(others) != sfs.equals(othersfs)) throw new IllegalArgumentException(se.toString()); } } private void testStringDeprecatedGetBytes(StringElem se) { String s = se.getString(); SafeString sfs = se.getSafeString(); int srcBegin, srcEnd, dstBegin; byte[] b, sfb; int len = sr.nextInt(s.getBytes().length); b = new byte[len]; sfb = new byte[len]; if (sr.nextInt(16) == 0) { srcBegin = sr.nextInt(); srcEnd = sr.nextInt(); dstBegin = sr.nextInt(); } else { srcBegin = sr.nextInt(s.length()); srcEnd = srcBegin + sr.nextInt(Math.min(s.length() - srcBegin, len)); dstBegin = sr.nextInt(len - (srcEnd - srcBegin) + 1); } if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > s.length() || dstBegin < 0 || dstBegin + (srcEnd - srcBegin) > len) { SafeString oldsfs = new SafeString(se.getSafeString()); boolean caught = false; try { s.getBytes(srcBegin, srcEnd, b, dstBegin); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(se.toString()); caught = false; try { sfs.getBytes(srcBegin, srcEnd, sfb, dstBegin); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfs.verify(s)) throw new IllegalArgumentException(se.toString()); } else { s.getBytes(srcBegin, srcEnd, b, dstBegin); sfs.getBytes(srcBegin, srcEnd, sfb, dstBegin); if (!Arrays.equals(b, sfb)) throw new IllegalArgumentException(se.toString()); } } private void testStringGetBytes(StringElem se) throws UnsupportedEncodingException { String s = se.getString(); SafeString sfs = se.getSafeString(); byte[] b = null, sfb = null; Charset c = randomCharset(); switch (sr.nextInt(4)) { case 0: b = s.getBytes(); sfb = sfs.getBytes(); break; case 1: //[ifJava6] b = s.getBytes(c); sfb = sfs.getBytes(c); break; //[fiJava6] // ...else fall through case 2: b = s.getBytes(c.name()); sfb = sfs.getBytes(c.name()); break; case 3: testStringDeprecatedGetBytes(se); return; default: throw new RuntimeException("switch"); } if (!Arrays.equals(b,sfb)) throw new IllegalArgumentException(se.toString()); } private void testStringGetChars(StringElem se) { String s = se.getString(); SafeString sfs = se.getSafeString(); int srcBegin, srcEnd, dstBegin; char[] c, sfc; int len = sr.nextInt(s.length()); c = new char[len]; sfc = new char[len]; if (sr.nextInt(16) == 0) { srcBegin = sr.nextInt(); srcEnd = sr.nextInt(); dstBegin = sr.nextInt(); } else { srcBegin = sr.nextInt(s.length()); srcEnd = srcBegin + sr.nextInt(Math.min(s.length() - srcBegin, len)); dstBegin = sr.nextInt(len - (srcEnd - srcBegin) + 1); } if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > s.length() || dstBegin < 0 || dstBegin + (srcEnd - srcBegin) > len) { SafeString oldsfs = new SafeString(se.getSafeString()); boolean caught = false; try { s.getChars(srcBegin, srcEnd, c, dstBegin); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(se.toString()); caught = false; try { sfs.getChars(srcBegin, srcEnd, sfc, dstBegin); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfs.verify(s)) throw new IllegalArgumentException(se.toString()); } else { s.getChars(srcBegin, srcEnd, c, dstBegin); sfs.getChars(srcBegin, srcEnd, sfc, dstBegin); if (!Arrays.equals(c, sfc)) throw new IllegalArgumentException(se.toString()); } } private void testStringHashCode(StringElem se) { String s = se.getString(); SafeString sfs = se.getSafeString(); if (s.hashCode() != sfs.hashCode()) throw new IllegalArgumentException(se.toString()); } private void testStringIndexOfChar(StringElem se) { String s = se.getString(); SafeString sfs = se.getSafeString(); int ch; int fromIndex; boolean useIndex = sr.nextBoolean(); //[ifJava5+] ch = randomCodePoint(); //[fiJava5+] //[ifJava4] ch = randomChar(); //[fiJava4] if (sr.nextInt(16) == 0) fromIndex = sr.nextInt(); else fromIndex = sr.nextInt(s.length()); if (useIndex) { if (s.indexOf(ch, fromIndex) != sfs.indexOf(ch, fromIndex)) throw new IllegalArgumentException(se.toString()); } else { if (s.indexOf(ch) != sfs.indexOf(ch)) throw new IllegalArgumentException(se.toString()); } } private void testStringIndexOfString(StringElem se) { String s = se.getString(); SafeString sfs = se.getSafeString(); StringElem otherse; int fromIndex; boolean useIndex = sr.nextBoolean(); otherse = getRandomStringElem(); otherse.verify(); if (sr.nextInt(16) == 0) fromIndex = sr.nextInt(); else fromIndex = sr.nextInt(s.length()); if (useIndex) { if (s.indexOf(otherse.getString(), fromIndex) != sfs.indexOf(otherse.getSafeString(), fromIndex)) throw new IllegalArgumentException(se.toString()); } else { if (s.indexOf(otherse.getString()) != sfs.indexOf(otherse.getSafeString())) throw new IllegalArgumentException(se.toString()); } } private void testStringIndexOf(StringElem se) { if (sr.nextBoolean()) testStringIndexOfChar(se); else testStringIndexOfString(se); } //[ifJava6] private void testStringIsEmpty(StringElem se) { if (se.getString().isEmpty() != se.getSafeString().isEmpty()) throw new IllegalArgumentException(se.toString()); } //[fiJava6] private void testStringLastIndexOfChar(StringElem se) { String s = se.getString(); SafeString sfs = se.getSafeString(); int ch; int fromIndex; boolean useIndex = sr.nextBoolean(); //[ifJava5+] ch = randomCodePoint(); //[fiJava5+] //[ifJava4] ch = randomChar(); //[fiJava4] if (sr.nextInt(16) == 0) fromIndex = sr.nextInt(); else fromIndex = sr.nextInt(s.length()); if (useIndex) { if (s.lastIndexOf(ch, fromIndex) != sfs.lastIndexOf(ch, fromIndex)) throw new IllegalArgumentException(se.toString()); } else { if (s.lastIndexOf(ch) != sfs.lastIndexOf(ch)) throw new IllegalArgumentException(se.toString()); } } private void testStringLastIndexOfString(StringElem se) { String s = se.getString(); SafeString sfs = se.getSafeString(); StringElem otherse; int fromIndex; boolean useIndex = sr.nextBoolean(); otherse = getRandomStringElem(); otherse.verify(); if (sr.nextInt(16) == 0) fromIndex = sr.nextInt(); else fromIndex = sr.nextInt(s.length()); if (useIndex) { if (s.lastIndexOf(otherse.getString(), fromIndex) != sfs.lastIndexOf(otherse.getSafeString(), fromIndex)) throw new IllegalArgumentException(se.toString()); } else { if (s.lastIndexOf(otherse.getString()) != sfs.lastIndexOf(otherse.getSafeString())) throw new IllegalArgumentException(se.toString()); } } private void testStringLastIndexOf(StringElem se) { if (sr.nextBoolean()) testStringLastIndexOfChar(se); else testStringLastIndexOfString(se); } private void testStringLength(StringElem se) { if (se.getString().length() != se.getSafeString().length()) throw new IllegalArgumentException(se.toString()); } //[ifJava5+] private void testStringOffsetByCodePoints(StringElem se) { String s = se.getString(); SafeString sfs = se.getSafeString(); int index; int codePointOffset; if (sr.nextInt(16) == 0) { index = sr.nextInt(); codePointOffset = sr.nextInt(); } else { index = sr.nextInt(s.length()); boolean sign = sr.nextBoolean(); if (sign) codePointOffset = -sr.nextInt(s.codePointCount(0, index)); else codePointOffset = sr.nextInt(s.codePointCount(index,s.length())); } if (index < 0 || index > s.length() || (codePointOffset > 0 && codePointOffset > s.codePointCount(index, s.length())) || (codePointOffset < 0 && -codePointOffset > s.codePointCount(0,index))) { SafeString oldsfs = new SafeString(se.getSafeString()); boolean caught = false; try { s.offsetByCodePoints(index, codePointOffset); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(se.toString()); caught = false; try { sfs.offsetByCodePoints(index, codePointOffset); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfs.verify(s)) throw new IllegalArgumentException(se.toString()); } else { if (s.offsetByCodePoints(index, codePointOffset) != sfs.offsetByCodePoints(index, codePointOffset)) throw new IllegalArgumentException(se.toString()); } } //[fiJava5+] private void testStringStartsWith(StringElem se) { String s = se.getString(); SafeString sfs = se.getSafeString(); StringElem otherse = getRandomStringElem(); if (s.startsWith(otherse.getString()) != sfs.startsWith(otherse.getSafeString())) throw new IllegalArgumentException(se.toString()); } private void testStringIsTainted(StringElem se) { String s = se.getString(); SafeString sfs = se.getSafeString(); if (s.@internal@isTainted() != sfs.isTainted()) throw new IllegalArgumentException(se.toString()); } private void testStringSerialize(StringElem se) throws IOException, ClassNotFoundException { String s = se.getString(); SafeString sfs = new SafeString(se.getSafeString().origString(), new SafeTaint(false, s.length())); ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream os = new ObjectOutputStream(bout); os.writeObject(s); os.flush(); os.close(); ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); ObjectInputStream is = new ObjectInputStream(bin); s = (String) is.readObject(); is.close(); bin.close(); bout.close(); if (s.@internal@isTainted()) throw new RuntimeException("Corrupted Serialization"); StringElem newSe = new StringElem(s, sfs, sr.nextInt()); newSe.verify(); se.addOp(StringMethod.S_SERIALIZE); newSe.addOp(StringMethod.S_SERIALIZE); stringList.add(newSe); } public void testString() throws IllegalArgumentException, UnsupportedEncodingException, IOException, ClassNotFoundException { int op = sr.nextInt(StringMethod.S_END); StringElem se = null; if (stringList.size() < threads * 4) op = StringMethod.S_NEW; if (op != StringMethod.S_NEW) { se = (StringElem) stringList.get(sr.nextInt(stringList.size())); se.verify(); se.addOp(op); } switch(op) { case StringMethod.S_NEW: testStringNew(); break; case StringMethod.S_CHARAT: testStringCharAt(se); break; case StringMethod.S_CODEPOINT: //[ifJava5+] testStringCodePoint(se); break; //[fiJava5+] //...else fall through case StringMethod.S_COMPARETO: testStringCompareTo(se); break; case StringMethod.S_CONCAT: testStringConcat(se); break; case StringMethod.S_CONTAINS: testStringContains(se); break; case StringMethod.S_CONTENTEQUALS: testStringContentEquals(se); break; case StringMethod.S_COPYVALUEOF: testStringCopyValueOf(); break; case StringMethod.S_ENDSWITH: testStringEndsWith(se); break; case StringMethod.S_EQUALS: testStringEquals(se); break; case StringMethod.S_GETBYTES: testStringGetBytes(se); break; case StringMethod.S_GETCHARS: testStringGetChars(se); break; case StringMethod.S_HASHCODE: testStringHashCode(se); break; case StringMethod.S_INDEXOF: testStringIndexOf(se); break; case StringMethod.S_ISEMPTY: //[ifJava6] testStringIsEmpty(se); break; //[fiJava6] //...else fall through case StringMethod.S_LASTINDEXOF: testStringLastIndexOf(se); break; case StringMethod.S_LENGTH: testStringLength(se); break; case StringMethod.S_OFFSETBYCODEPOINTS: //XXX This method is actually buggy in Java 5, test only in //Java 6 //[ifJava6] testStringOffsetByCodePoints(se); break; //[fiJava6] //...else fall through case StringMethod.S_STARTSWITH: testStringStartsWith(se); break; case StringMethod.S_SUBSEQUENCE: testStringSubSequence(se); break; case StringMethod.S_SUBSTRING: testStringSubstring(se); break; case StringMethod.S_TOCHARARRAY: testStringToCharArray(se); break; case StringMethod.S_TOLOWERCASE: testStringToLowerCase(se); break; case StringMethod.S_TOSTRING: testStringToString(se); break; case StringMethod.S_TOUPPERCASE: testStringToUpperCase(se); break; case StringMethod.S_TRIM: testStringTrim(se); break; case StringMethod.S_VALUEOF: testStringValueOf(); break; case StringMethod.S_ISTAINTED: testStringIsTainted(se); break; case StringMethod.S_SERIALIZE: testStringSerialize(se); break; default: throw new RuntimeException("switch"); } if (op != StringMethod.S_NEW) se.verify(); } //[ifJava5+] private void testStringBuilderNew() { StringBuilder sb = null; SafeStringBuilder sfsb = null; StringBuilderElem sbe; switch(sr.nextInt(4)) { case 0: // StringBuilder() sb = new StringBuilder(); sfsb = new SafeStringBuilder(); break; case 1: // StringBuilder(int capacity) { int capacity = sr.nextInt(maxlen); sb = new StringBuilder(capacity); sfsb = new SafeStringBuilder(capacity); break; } case 2: // StringBuilder(String s) { StringElem se = getRandomStringElem(); if (se == null) return; sb = new StringBuilder(se.getString()); sfsb = new SafeStringBuilder(se.getSafeString()); break; } case 3: // StringBuilder(CharSequence seq) { CharSequenceElem cse = randomCharSequenceElem(); sb = new StringBuilder(cse.getCharSequence()); sfsb = new SafeStringBuilder(cse.getSafeCharSequence()); cse.release(); break; } default: throw new RuntimeException("switch"); } sbe = new StringBuilderElem(sb, sfsb, sr.nextInt()); sbe.addOp(StringBuilderMethod.SB_NEW); sbe.verify(); stringBuilderList.add(sbe); } private void verifyStringBuilderAppendString(StringBuilder sb, int oldLength, String str) { Taint sbt = sb.toString().@internal@taint(); Taint strt = str.@internal@taint(); if (sbt == null) sbt = new Taint(false, sb.length()); if (strt == null) strt = new Taint(false, str.length()); if (sb.length() != oldLength + str.length()) throw new IllegalArgumentException("append string length check:" + sb + "appended: " + str); for (int i = oldLength; i < sb.length(); i++) if (sb.charAt(i) != str.charAt(i - oldLength) || sbt.get(i) != strt.get(i - oldLength)) throw new IllegalArgumentException("append string taint check"); } private void verifyStringBuilderAppendStringBuffer(StringBuilder sb, int oldLength, StringBuffer othersb) { Taint sbt = sb.toString().@internal@taint(); Taint othersbt = othersb.toString().@internal@taint(); if (sbt == null) sbt = new Taint(false, sb.length()); if (othersbt == null) othersbt = new Taint(false, othersb.length()); if (sb.length() != oldLength + othersb.length()) throw new IllegalArgumentException("append string length check:" + sb + "appended: " + othersb); for (int i = oldLength; i < sb.length(); i++) if (sb.charAt(i) != othersb.charAt(i - oldLength) || sbt.get(i) != othersbt.get(i - oldLength)) throw new IllegalArgumentException("append string taint check"); } private void verifySafeStringBuilderAppendSafeString(SafeStringBuilder sfsb, int oldLength, SafeString sfs) { SafeTaint sfsbt = sfsb.taint(); SafeTaint sfstrt = sfs.taint(); if (sfsb.length() != oldLength + sfs.length()) throw new IllegalArgumentException("append string length check:" + sfsb + "appended: " + sfs); for (int i = oldLength; i < sfsb.length(); i++) if (sfsb.charAt(i) != sfs.charAt(i - oldLength) || sfsbt.get(i) != sfstrt.get(i - oldLength)) throw new IllegalArgumentException("append string taint check"); } private void verifySafeStringBuilderAppendSafeStringBuffer( SafeStringBuilder sfsb, int oldLength, SafeStringBuffer othersfsb) { SafeTaint sfsbt = sfsb.taint(); SafeTaint othersfsbt = othersfsb.taint(); if (sfsb.length() != oldLength + othersfsb.length()) throw new IllegalArgumentException("append string length check:" + sfsb + "appended: " + othersfsb); for (int i = oldLength; i < sfsb.length(); i++) if (sfsb.charAt(i) != othersfsb.charAt(i - oldLength) || sfsbt.get(i) != othersfsbt.get(i - oldLength)) throw new IllegalArgumentException("append string taint check"); } private void testStringBuilderAppend(StringBuilderElem sbe) { StringBuilder sb = sbe.getStringBuilder(); SafeStringBuilder sfsb = sbe.getSafeStringBuilder(); int oldLen = sb.length(); StringBuilder retsb = null; SafeStringBuilder retsfsb = null; switch(sr.nextInt(14)) { case 0 : // append(boolean) { boolean b = sr.nextBoolean(); retsb = sb.append(b); retsfsb = sfsb.append(b); break; } case 1: // append(char c) { char c = randomChar(); retsb = sb.append(c); retsfsb = sfsb.append(c); break; } case 2: // append(char[] str, int offset, int len) { char[] str = randomCharArray(); int offset = sr.nextInt(str.length); int length = str.length - offset; retsb = sb.append(str, offset, length); retsfsb = sfsb.append(str, offset, length); break; } case 3: // append(double d) { double d = sr.nextDouble(); retsb = sb.append(d); retsfsb = sfsb.append(d); break; } case 4: // append(float f) { float f = sr.nextFloat(); retsb = sb.append(f); retsfsb = sfsb.append(f); break; } case 5: // append(int i) { int i = sr.nextInt(); retsb = sb.append(i); retsfsb = sfsb.append(i); break; } case 6: // append(long lng) { long lng = sr.nextLong(); retsb = sb.append(lng); retsfsb = sfsb.append(lng); break; } case 7: // append(Object obj) { Object o = new Object(); retsb = sb.append(o); retsfsb = sfsb.append(o); break; } case 8: // append(String s) { StringElem se = getRandomStringElem(); if (se == null) return; retsb = sb.append(se.getString()); retsfsb = sfsb.append(se.getSafeString()); verifyStringBuilderAppendString(sb, oldLen, se.getString()); verifySafeStringBuilderAppendSafeString(sfsb, oldLen, se.getSafeString()); break; } case 9: // append(StringBuffer sb) { StringBufferElem othersbe = removeRandomStringBufferElem(); if (othersbe == null) return; othersbe.verify(); retsb = sb.append(othersbe.getStringBuffer()); retsfsb = sfsb.append(othersbe.getSafeStringBuffer()); verifyStringBuilderAppendStringBuffer(sb, oldLen, othersbe.getStringBuffer()); verifySafeStringBuilderAppendSafeStringBuffer(sfsb, oldLen, othersbe.getSafeStringBuffer()); othersbe.verify(); stringBufferList.add(othersbe); break; } case 10: // append(char[] str) { char[] str = randomCharArray(); retsb = sb.append(str); retsfsb = sfsb.append(str); break; } case 11: // appendCodePoint(int codePoint) { int codePoint = randomCodePoint(); retsb = sb.appendCodePoint(codePoint); retsfsb = sfsb.appendCodePoint(codePoint); break; } case 12: // append(CharSequence s) { CharSequenceElem cse = randomCharSequenceElem(); retsb = sb.append(cse.getCharSequence()); retsfsb = sfsb.append(cse.getSafeCharSequence()); cse.release(); break; } case 13: // append(CharSequence s, int start, int end) { CharSequenceElem cse = randomCharSequenceElem(); CharSequence cs = cse.getCharSequence(); SafeCharSequence sfcs = cse.getSafeCharSequence(); int start = sr.nextInt(cs.length()); int end = start + sr.nextInt(cs.length() + 1 - start); retsb = sb.append(cs, start, end); retsfsb = sfsb.append(sfcs, start, end); cse.release(); break; } default: throw new RuntimeException("switch"); } if (retsb != sb || retsfsb != sfsb) throw new IllegalArgumentException(sbe.toString()); } private void testStringBuilderCapacity(StringBuilderElem sbe) { StringBuilder sb = sbe.getStringBuilder(); SafeStringBuilder sfsb = sbe.getSafeStringBuilder(); if (sb.capacity() < 0 || sfsb.capacity() < 0) throw new IllegalArgumentException("negative capacity"); } private void testStringBuilderCharAt(StringBuilderElem sbe) { StringBuilder sb = sbe.getStringBuilder(); SafeStringBuilder sfsb = sbe.getSafeStringBuilder(); int index; if (sr.nextInt(16) == 0) index = sr.nextInt(); else index = sr.nextInt(sb.length()); if (index >= sb.length() || index < 0) { SafeStringBuilder oldsfsb=new SafeStringBuilder(sfsb.toSafeString()); boolean caught = false; try { sb.charAt(index); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.charAt(index); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { if (sb.charAt(index) != sfsb.charAt(index)) throw new IllegalArgumentException(sbe.toString()); } } private void testStringBuilderEnsureCapacity(StringBuilderElem sbe) { StringBuilder sb = sbe.getStringBuilder(); SafeStringBuilder sfsb = sbe.getSafeStringBuilder(); int capacity; if (sr.nextInt(16) != 0) capacity = -sr.nextInt(maxlen); else capacity = sr.nextInt(maxlen); sb.ensureCapacity(capacity); sfsb.ensureCapacity(capacity); } private void testStringBuilderIndexOf(StringBuilderElem sbe) { StringBuilder sb = sbe.getStringBuilder(); SafeStringBuilder sfsb = sbe.getSafeStringBuilder(); StringElem se; int index; boolean useIndex = sr.nextBoolean(); se = getRandomStringElem(); if (se == null) return; if (sr.nextInt(16) == 0) index = sr.nextInt(); else index = sr.nextInt(sb.length()); if (useIndex) { if (sb.indexOf(se.getString(), index) != sfsb.indexOf(se.getSafeString(), index)) throw new IllegalArgumentException(sbe.toString()); } else { if (sb.indexOf(se.getString()) != sfsb.indexOf(se.getSafeString())) throw new IllegalArgumentException(sbe.toString()); } } private void testStringBuilderGetChars(StringBuilderElem sbe) { StringBuilder sb = sbe.getStringBuilder(); SafeStringBuilder sfsb = sbe.getSafeStringBuilder(); int srcBegin, srcEnd, dstBegin; char[] c, sfc; int len = sr.nextInt(sb.length()); c = new char[len]; sfc = new char[len]; if (sr.nextInt(16) == 0) { srcBegin = sr.nextInt(); srcEnd = sr.nextInt(); dstBegin = sr.nextInt(); } else { srcBegin = sr.nextInt(sb.length()); srcEnd = srcBegin + sr.nextInt(Math.min(sb.length() - srcBegin, len)); dstBegin = sr.nextInt(len - (srcEnd - srcBegin) + 1); } if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > sb.length() || dstBegin < 0 || dstBegin + (srcEnd - srcBegin) > len) { SafeStringBuilder oldsbfs=new SafeStringBuilder(sfsb.toSafeString()); boolean caught = false; try { sb.getChars(srcBegin, srcEnd, c, dstBegin); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.getChars(srcBegin, srcEnd, sfc, dstBegin); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsbfs.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { sb.getChars(srcBegin, srcEnd, c, dstBegin); sfsb.getChars(srcBegin, srcEnd, sfc, dstBegin); if (!Arrays.equals(c, sfc)) throw new IllegalArgumentException(sbe.toString()); } } private void testStringBuilderCodePointAt(StringBuilderElem sbe) { StringBuilder sb = sbe.getStringBuilder(); SafeStringBuilder sfsb = sbe.getSafeStringBuilder(); int index; if (sr.nextInt(16) == 0) index = sr.nextInt(); else index = sr.nextInt(sb.length()); if (index < 0 || index >= sb.length()) { SafeStringBuilder oldsfsb=new SafeStringBuilder(sfsb.toSafeString()); boolean caught = false; try { sb.codePointAt(index); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.codePointAt(index); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { if (sb.codePointAt(index) != sfsb.codePointAt(index)) throw new IllegalArgumentException(sbe.toString()); } } private void testStringBuilderCodePointBefore(StringBuilderElem sbe) { StringBuilder sb = sbe.getStringBuilder(); SafeStringBuilder sfsb = sbe.getSafeStringBuilder(); int index; if (sr.nextInt(16) == 0) index = sr.nextInt(); else index = 1 + sr.nextInt(sb.length()); if (index < 1 || index > sb.length()) { SafeStringBuilder oldsfsb=new SafeStringBuilder(sfsb.toSafeString()); boolean caught = false; try { sb.codePointBefore(index); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.codePointBefore(index); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { if (sb.codePointBefore(index) != sfsb.codePointBefore(index)) throw new IllegalArgumentException(sbe.toString()); } } private void testStringBuilderCodePointCount(StringBuilderElem sbe) { StringBuilder sb = sbe.getStringBuilder(); SafeStringBuilder sfsb = sbe.getSafeStringBuilder(); int beginIndex, endIndex; if (sr.nextInt(16) == 0) { beginIndex = sr.nextInt(); endIndex = sr.nextInt(); } else { beginIndex = sr.nextInt(sb.length()); endIndex = sr.nextInt(sb.length() + 1 - beginIndex); } if (beginIndex < 0 || endIndex > sb.length() || beginIndex > endIndex) { SafeStringBuilder oldsfsb=new SafeStringBuilder(sfsb.toSafeString()); boolean caught = false; try { sb.codePointCount(beginIndex, endIndex); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.codePointCount(beginIndex, endIndex); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { if (sb.codePointCount(beginIndex, endIndex) != sfsb.codePointCount(beginIndex, endIndex)) throw new IllegalArgumentException(sbe.toString()); } } private void testStringBuilderCodePoint(StringBuilderElem sbe) { switch (sr.nextInt(3)) { case 0: testStringBuilderCodePointAt(sbe); break; case 1: testStringBuilderCodePointBefore(sbe); break; case 2: testStringBuilderCodePointCount(sbe); break; default: throw new RuntimeException("switched failed"); } } private void testStringBuilderDelete(StringBuilderElem sbe) { StringBuilder sb = sbe.getStringBuilder(); SafeStringBuilder sfsb = sbe.getSafeStringBuilder(); int oldLen = sb.length(); int beginIndex, endIndex; boolean useCharAt = false; if (sr.nextInt() == 0) { beginIndex = sr.nextInt(); endIndex = sr.nextInt(); } else { beginIndex = sr.nextInt(sb.length()); switch(sr.nextInt(3)) { case 0: case 1: endIndex = beginIndex + sr.nextInt(maxlen); break; case 2: endIndex = beginIndex + 1; useCharAt = true; break; default: throw new RuntimeException("switch"); } } if (beginIndex < 0 || beginIndex > endIndex || beginIndex > sb.length() || (useCharAt && beginIndex == sb.length())) { SafeStringBuilder oldsfsb=new SafeStringBuilder(sfsb.toSafeString()); boolean caught = false; try { if (useCharAt) sb.deleteCharAt(beginIndex); else sb.delete(beginIndex, endIndex); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { if (useCharAt) sfsb.deleteCharAt(beginIndex); else sfsb.delete(beginIndex, endIndex); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { StringBuilder retsb; SafeStringBuilder retsfsb; if (useCharAt) { retsb = sb.deleteCharAt(beginIndex); retsfsb = sfsb.deleteCharAt(beginIndex); if (sb.length() - oldLen != -1) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.delete(beginIndex, endIndex); retsfsb = sfsb.delete(beginIndex, endIndex); endIndex = Math.min(endIndex, oldLen); if (sb.length() - oldLen != beginIndex - endIndex) throw new IllegalArgumentException(sbe.toString()); } if (retsb != sb || retsfsb != sfsb) throw new IllegalArgumentException(sbe.toString()); } } private void verifyStringBuilderInsertString(StringBuilder sb, int oldLength, int offset, String str) { Taint sbt = sb.toString().@internal@taint(); Taint strt = str.@internal@taint(); if (sbt == null) sbt = new Taint(false, sb.length()); if (strt == null) strt = new Taint(false, str.length()); if (sb.length() != oldLength + str.length()) throw new IllegalArgumentException("insert string length check:" + sb + "inserted: " + str); for (int i = offset; i < offset + str.length(); i++) if (sb.charAt(i) != str.charAt(i - offset) || sbt.get(i) != strt.get(i - offset)) throw new IllegalArgumentException("insert string taint check"); } private void verifySafeStringBuilderInsertSafeString(SafeStringBuilder sfsb, int oldLength, int offset, SafeString sfs) { SafeTaint sfsbt = sfsb.taint(); SafeTaint sfstrt = sfs.taint(); if (sfsb.length() != oldLength + sfs.length()) throw new IllegalArgumentException("insert string length check:" + sfsb + "inserted: " + sfs); for (int i = offset; i < offset + sfs.length(); i++) if (sfsb.charAt(i) != sfs.charAt(i - offset) || sfsbt.get(i) != sfstrt.get(i - offset)) throw new IllegalArgumentException("insert string taint check"); } private void testStringBuilderInsert(StringBuilderElem sbe) { StringBuilder sb = sbe.getStringBuilder(); SafeStringBuilder sfsb = sbe.getSafeStringBuilder(); SafeStringBuilder oldsfsb = new SafeStringBuilder(sfsb.toSafeString()); int oldLen = sb.length(); int offset; boolean except = false; StringBuilder retsb = null; SafeStringBuilder retsfsb = null; if (sr.nextInt(16) == 0) offset = sr.nextInt(); else offset = sr.nextInt(sb.length() + 1); if (offset < 0 || offset > sb.length()) except = true; switch(sr.nextInt(12)) { case 0 : // insert(int offset, boolean) { boolean b = sr.nextBoolean(); if (except) { boolean caught = false; try { sb.insert(offset, b); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.insert(offset, b); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.insert(offset, b); retsfsb = sfsb.insert(offset, b); } break; } case 1: // insert(int offset, char c) { char c = randomChar(); if (except) { boolean caught = false; try { sb.insert(offset, c); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.insert(offset, c); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.insert(offset, c); retsfsb = sfsb.insert(offset, c); } break; } case 2: // insert(int offset, char[] str, int offset, int len) { char[] str = randomCharArray(); int index = sr.nextInt(str.length); int length = str.length - offset; if (except || index + length > str.length || ((index|length) < 0)) { boolean caught = false; try { sb.insert(offset, str, index, length); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.insert(offset, str, index, length); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.insert(offset, str, index, length); retsfsb = sfsb.insert(offset, str, index, length); } break; } case 3: // insert(int offset, double d) { double d = sr.nextDouble(); if (except) { boolean caught = false; try { sb.insert(offset, d); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.insert(offset, d); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.insert(offset, d); retsfsb = sfsb.insert(offset, d); } break; } case 4: // insert(int offset, float f) { float f = sr.nextFloat(); if (except) { boolean caught = false; try { sb.insert(offset, f); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.insert(offset, f); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.insert(offset, f); retsfsb = sfsb.insert(offset, f); } break; } case 5: // insert(int offset, int i) { int i = sr.nextInt(); if (except) { boolean caught = false; try { sb.insert(offset, i); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.insert(offset, i); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.insert(offset, i); retsfsb = sfsb.insert(offset, i); } break; } case 6: // insert(int offset, long lng) { long lng = sr.nextLong(); if (except) { boolean caught = false; try { sb.insert(offset, lng); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.insert(offset, lng); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.insert(offset, lng); retsfsb = sfsb.insert(offset, lng); } break; } case 7: // insert(int offset, Object obj) { Object o = new Object(); if (except) { boolean caught = false; try { sb.insert(offset, o); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.insert(offset, o); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.insert(offset, o); retsfsb = sfsb.insert(offset, o); } break; } case 8: // insert(int offset, String s) { StringElem se = getRandomStringElem(); if (se == null) return; if (except) { boolean caught = false; try { sb.insert(offset, se.getString()); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.insert(offset, se.getSafeString()); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.insert(offset, se.getString()); retsfsb = sfsb.insert(offset, se.getSafeString()); verifyStringBuilderInsertString(sb, oldLen, offset, se.getString()); verifySafeStringBuilderInsertSafeString(sfsb, oldLen, offset, se.getSafeString()); } break; } case 9: // insert(int offset, char[] str) { char[] str = randomCharArray(); if (except) { boolean caught = false; try { sb.insert(offset, str); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.insert(offset, str); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.insert(offset, str); retsfsb = sfsb.insert(offset, str); } break; } case 10: // insert(int dstOffset, CharSequence s) { CharSequenceElem cse = randomCharSequenceElem(); if (except) { boolean caught = false; try { sb.insert(offset, cse.getCharSequence()); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.insert(offset, cse.getSafeCharSequence()); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.insert(offset, cse.getCharSequence()); retsfsb = sfsb.insert(offset, cse.getSafeCharSequence()); } cse.release(); break; } case 11: //insert(int dstOffset, CharSequence s, int start, int end) { CharSequenceElem cse = randomCharSequenceElem(); CharSequence cs = cse.getCharSequence(); SafeCharSequence sfcs = cse.getSafeCharSequence(); int start = sr.nextInt(cs.length()); int end = start + sr.nextInt(cs.length() + 1 - start); if (except) { boolean caught = false; try { sb.insert(offset, cs, start, end); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.insert(offset, sfcs, start, end); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.insert(offset, cs, start, end); retsfsb = sfsb.insert(offset, sfcs, start, end); } cse.release(); break; } default: throw new RuntimeException("switch"); } if (retsb == null || retsfsb == null) { if (retsb != null || retsfsb != null) throw new IllegalArgumentException(sbe.toString()); } else { if (retsb != sb || retsfsb != sfsb) throw new IllegalArgumentException(sbe.toString()); } } private void testStringBuilderLastIndexOf(StringBuilderElem sbe) { StringBuilder sb = sbe.getStringBuilder(); SafeStringBuilder sfsb = sbe.getSafeStringBuilder(); StringElem se; int index; boolean useIndex = sr.nextBoolean(); se = getRandomStringElem(); if (se == null) return; if (sr.nextInt(16) == 0) index = sr.nextInt(); else index = sr.nextInt(sb.length()); if (useIndex) { if (sb.lastIndexOf(se.getString(), index) != sfsb.lastIndexOf(se.getSafeString(), index)) throw new IllegalArgumentException(sbe.toString()); } else { if (sb.lastIndexOf(se.getString()) != sfsb.lastIndexOf(se.getSafeString())) throw new IllegalArgumentException(sbe.toString()); } } private void testStringBuilderOffsetByCodePoints(StringBuilderElem sbe) { StringBuilder sb = sbe.getStringBuilder(); SafeStringBuilder sfsb = sbe.getSafeStringBuilder(); int index; int codePointOffset; if (sr.nextInt(16) == 0) { index = sr.nextInt(); codePointOffset = sr.nextInt(); } else { index = sr.nextInt(sb.length()); boolean sign = sr.nextBoolean(); if (sign) codePointOffset = -sr.nextInt(sb.codePointCount(0, index)); else codePointOffset = sr.nextInt(sb.codePointCount(index,sb.length())); } if (index < 0 || index > sb.length() || (codePointOffset > 0 && codePointOffset > sb.codePointCount(index, sb.length())) || (codePointOffset < 0 && -codePointOffset > sb.codePointCount(0,index))) { SafeStringBuilder oldsfsb=new SafeStringBuilder(sfsb.toSafeString()); boolean caught = false; try { sb.offsetByCodePoints(index, codePointOffset); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.offsetByCodePoints(index, codePointOffset); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { if (sb.offsetByCodePoints(index, codePointOffset) != sfsb.offsetByCodePoints(index, codePointOffset)) throw new IllegalArgumentException(sbe.toString()); } } private void testStringBuilderReplace(StringBuilderElem sbe) { StringBuilder sb = sbe.getStringBuilder(); SafeStringBuilder sfsb = sbe.getSafeStringBuilder(); StringElem se = getRandomStringElem(); if (se == null) return; String s = se.getString(); SafeString sfs = se.getSafeString(); int oldLen = sb.length(); int beginIndex, endIndex; if (sr.nextInt() == 0) { beginIndex = sr.nextInt(); endIndex = sr.nextInt(); } else { beginIndex = sr.nextInt(sb.length()); endIndex = beginIndex + sr.nextInt(maxlen); } if (beginIndex < 0 || beginIndex > endIndex || beginIndex > sb.length()) { SafeStringBuilder oldsfsb=new SafeStringBuilder(sfsb.toSafeString()); boolean caught = false; try { sb.replace(beginIndex, endIndex, s); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.replace(beginIndex, endIndex, sfs); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { StringBuilder retsb = sb.replace(beginIndex, endIndex, s); SafeStringBuilder retsfsb = sfsb.replace(beginIndex, endIndex, sfs); endIndex = Math.min(endIndex, oldLen); if (sb.length() - oldLen != beginIndex - endIndex + s.length()) throw new IllegalArgumentException(sbe.toString()); Taint sbt = sb.toString().@internal@taint(); if (sbt == null) sbt = new Taint(false, sb.length()); for (int i = beginIndex; i < s.length(); i++) if (sb.charAt(i) != sfs.charAt(i - beginIndex) || sbt.get(i) != sfs.taint().get(i - beginIndex)) throw new IllegalArgumentException(sbe.toString()); if (retsb != sb || retsfsb != sfsb) throw new IllegalArgumentException(sbe.toString()); } } private void testStringBuilderSetCharAt(StringBuilderElem sbe) { StringBuilder sb = sbe.getStringBuilder(); SafeStringBuilder sfsb = sbe.getSafeStringBuilder(); char c = randomChar(); int index; if (sr.nextInt(16) == 0) index = sr.nextInt(); else index = sr.nextInt(sb.length()); if (index < 0 || index >= sb.length()) { SafeStringBuilder oldsfsb=new SafeStringBuilder(sfsb.toSafeString()); boolean caught = false; try { sb.setCharAt(index, c); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.setCharAt(index, c); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { sb.setCharAt(index, c); sfsb.setCharAt(index, c); Taint sbt = sb.toString().@internal@taint(); if (sbt == null) sbt = new Taint(false, sb.length()); if (sb.charAt(index) != c || sfsb.charAt(index) != c || sbt.get(index) || sfsb.taint().get(index)) throw new IllegalArgumentException(sbe.toString()); } } private void testStringBuilderSetLength(StringBuilderElem sbe) { StringBuilder sb = sbe.getStringBuilder(); SafeStringBuilder sfsb = sbe.getSafeStringBuilder(); int m = maxlen < sb.length() ? sb.length() + 1024 : maxlen; int len; if (sr.nextInt(16) == 0) len = -sr.nextInt(m); else len = sr.nextInt(m); if (len < 0) { SafeStringBuilder oldsfsb=new SafeStringBuilder(sfsb.toSafeString()); boolean caught = false; try { sb.setLength(len); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.setLength(len); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { sb.setLength(len); sfsb.setLength(len); if (sb.length() != len || sfsb.length() != len) throw new IllegalArgumentException(sbe.toString()); } } private void testStringBuilderSubSequence(StringBuilderElem sbe) { StringBuilder sb = sbe.getStringBuilder(); SafeStringBuilder sfsb = sbe.getSafeStringBuilder(); int beginIndex, endIndex; CharSequence subs; SafeCharSequence subsfs; if (sr.nextInt(16) == 0) { beginIndex = sr.nextInt(); endIndex = sr.nextInt(); } else { beginIndex = sr.nextInt(sb.length()); endIndex = beginIndex + sr.nextInt(sb.length() + 1 - beginIndex); } if (beginIndex < 0 || endIndex > sb.length() || beginIndex > endIndex) { SafeStringBuilder oldsfsb=new SafeStringBuilder(sfsb.toSafeString()); boolean caught = false; try { subs = sb.subSequence(beginIndex, endIndex); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { subsfs = sfsb.subSequence(beginIndex, endIndex); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { subs = sb.subSequence(beginIndex, endIndex); subsfs = sfsb.subSequence(beginIndex, endIndex); subsfs.toSafeString().verify(subs.toString()); Taint t = sb.toString().@internal@taint(); Taint subt = subs.toString().@internal@taint(); if (t == null) t = new Taint(false, sb.length()); if (subt == null) subt = new Taint(false, subs.length()); for (int i = beginIndex; i < endIndex; i++) { if (sb.charAt(i) != subs.charAt(i - beginIndex) || t.get(i) != subt.get(i-beginIndex)) throw new IllegalArgumentException("string taint/data bad"); } } } private void testStringBuilderReverse(StringBuilderElem sbe) { StringBuilder sb = sbe.getStringBuilder(); SafeStringBuilder sfsb = sbe.getSafeStringBuilder(); StringBuilder retsb; SafeStringBuilder retsfsb; int len = sb.length(); retsb = sb.reverse(); retsfsb = sfsb.reverse(); sbe.verify(); if (sb.length() != len || retsb != sb || retsfsb != sfsb) throw new IllegalArgumentException(sbe.toString()); } private void testStringBuilderLength(StringBuilderElem sbe) { if (sbe.getStringBuilder().length() != sbe.getSafeStringBuilder().length()) throw new IllegalArgumentException(sbe.toString()); } private void testStringBuilderSubstring(StringBuilderElem sbe) { StringBuilder sb = sbe.getStringBuilder(); SafeStringBuilder sfsb = sbe.getSafeStringBuilder(); int beginIndex, endIndex; StringElem subse; String subs; SafeString subsfs; if (sr.nextInt(16) == 0) { beginIndex = sr.nextInt(); endIndex = sr.nextInt(); } else { beginIndex = sr.nextInt(sb.length()); endIndex = beginIndex + sr.nextInt(sb.length()+1 - beginIndex); } if (beginIndex < 0 || endIndex > sb.length() || beginIndex > endIndex) { SafeStringBuilder oldsfsb=new SafeStringBuilder(sfsb.toSafeString()); boolean caught = false; try { subs = sb.substring(beginIndex, endIndex); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { subsfs = sfsb.substring(beginIndex, endIndex); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { if (endIndex == sb.length() && sr.nextBoolean()) { subs = sb.substring(beginIndex); subsfs = sfsb.substring(beginIndex); } else { subs = sb.substring(beginIndex, endIndex); subsfs = sfsb.substring(beginIndex, endIndex); } subsfs.verify(subs); Taint t = sb.toString().@internal@taint(); Taint subt = subs.@internal@taint(); if (t == null) t = new Taint(false, sb.length()); if (subt == null) subt = new Taint(false, subs.length()); for (int i = beginIndex; i < endIndex; i++) if (sb.charAt(i) != subs.charAt(i - beginIndex) || t.get(i) != subt.get(i-beginIndex)) throw new IllegalArgumentException("string taint/data bad"); subse = new StringElem(subs, subsfs, sr.nextInt()); subse.verify(); subse.addOp("[" + sbe.toString() + "] StringBuilder.substring"); stringList.add(subse); } } private void testStringBuilderToString(StringBuilderElem sbe) { StringBuilder sb = sbe.getStringBuilder(); SafeStringBuilder sfsb = sbe.getSafeStringBuilder(); String s = sb.toString(); SafeString sfs = sfsb.toSafeString(); StringElem se = new StringElem(s, sfs, sr.nextInt()); se.verify(); sbe.verify(s); se.addOp("[" + sbe.toString() + "] StringBuilder.toString"); stringList.add(se); } private void testStringBuilderSerialize(StringBuilderElem sbe) throws IOException, ClassNotFoundException { StringBuilder sb = sbe.getStringBuilder(); SafeStringBuilder sfsb = sbe.getSafeStringBuilder(); sbe.verify(); sfsb = new SafeStringBuilder(new SafeString( sfsb.toSafeString().origString(), new SafeTaint(false, sfsb.length()))); ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream os = new ObjectOutputStream(bout); os.writeObject(sb); os.flush(); os.close(); ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); ObjectInputStream is = new ObjectInputStream(bin); sb = (StringBuilder) is.readObject(); is.close(); bin.close(); bout.close(); if (sb.toString().@internal@isTainted()) throw new RuntimeException("Corrupted Serialization"); StringBuilderElem newSbe = new StringBuilderElem(sb,sfsb,sr.nextInt()); newSbe.verify(); sbe.addOp(StringBuilderMethod.SB_SERIALIZE); // XXX BUG TODO // Apparent JVM Bug - if we add newSbe to stringBufferList, // codePointAt will later return incorrect values _very_ rarely. // This occurs only on objects that were previously serialized, // and only for the codePointAt method. StringBuffer is similarly // affected. Interestingly, when this bug occurs, the // sb.toString().equals(sfsb.toString()) holds -- so it's clearly not // actual data corruption. For now we just don't add newSbe to the // stringBufferList to work around this issue. } private void testStringBuilderTrimToSize(StringBuilderElem sbe) { sbe.getStringBuilder().trimToSize(); sbe.getSafeStringBuilder().trimToSize(); } public void testStringBuilder() throws IllegalArgumentException, IOException, ClassNotFoundException { int op = sr.nextInt(StringBuilderMethod.SB_END); StringBuilderElem sbe = null; if (stringBuilderList.size() < threads * 2) op = StringBuilderMethod.SB_NEW; if (op != StringBuilderMethod.SB_NEW) { sbe = removeRandomStringBuilderElem(); if (sbe == null) { op = StringBuilderMethod.SB_NEW; } else { sbe.verify(); sbe.addOp(op); } } switch(op) { case StringBuilderMethod.SB_NEW: testStringBuilderNew(); break; case StringBuilderMethod.SB_APPEND: testStringBuilderAppend(sbe); break; case StringBuilderMethod.SB_CAPACITY: testStringBuilderCapacity(sbe); break; case StringBuilderMethod.SB_CHARAT: testStringBuilderCharAt(sbe); break; case StringBuilderMethod.SB_CODEPOINT: testStringBuilderCodePoint(sbe); break; case StringBuilderMethod.SB_DELETE: testStringBuilderDelete(sbe); break; case StringBuilderMethod.SB_ENSURECAPACITY: testStringBuilderEnsureCapacity(sbe); break; case StringBuilderMethod.SB_GETCHARS: testStringBuilderGetChars(sbe); break; case StringBuilderMethod.SB_INDEXOF: testStringBuilderIndexOf(sbe); break; case StringBuilderMethod.SB_INSERT: testStringBuilderInsert(sbe); break; case StringBuilderMethod.SB_LASTINDEXOF: testStringBuilderLastIndexOf(sbe); break; case StringBuilderMethod.SB_LENGTH: testStringBuilderLength(sbe); break; case StringBuilderMethod.SB_OFFSETBYCODEPOINTS: testStringBuilderOffsetByCodePoints(sbe); break; case StringBuilderMethod.SB_REPLACE: testStringBuilderReplace(sbe); break; case StringBuilderMethod.SB_REVERSE: testStringBuilderReverse(sbe); break; case StringBuilderMethod.SB_SETCHARAT: testStringBuilderSetCharAt(sbe); break; case StringBuilderMethod.SB_SETLENGTH: testStringBuilderSetLength(sbe); break; case StringBuilderMethod.SB_SUBSEQUENCE: testStringBuilderSubSequence(sbe); break; case StringBuilderMethod.SB_SUBSTRING: testStringBuilderSubstring(sbe); break; case StringBuilderMethod.SB_TOSTRING: testStringBuilderToString(sbe); break; case StringBuilderMethod.SB_TRIMTOSIZE: testStringBuilderTrimToSize(sbe); break; case StringBuilderMethod.SB_SERIALIZE: testStringBuilderSerialize(sbe); break; default: throw new RuntimeException("switch"); } if (op != StringBuilderMethod.SB_NEW) { sbe.verify(); stringBuilderList.add(sbe); } } //[fiJava5+] private void testStringBufferNew() { StringBuffer sb = null; SafeStringBuffer sfsb = null; StringBufferElem sbe; switch(sr.nextInt(4)) { case 0: /* StringBuffer() */ sb = new StringBuffer(); sfsb = new SafeStringBuffer(); break; case 1: /* StringBuffer(int capacity) */ { int capacity = sr.nextInt(maxlen); sb = new StringBuffer(capacity); sfsb = new SafeStringBuffer(capacity); break; } case 2: /* StringBuffer(CharSequence seq) */ { //[ifJava5+] CharSequenceElem cse = randomCharSequenceElem(); sb = new StringBuffer(cse.getCharSequence()); sfsb = new SafeStringBuffer(cse.getSafeCharSequence()); cse.release(); break; //[fiJava5+] // ...else fall through } case 3: { StringElem se = getRandomStringElem(); if (se == null) return; sb = new StringBuffer(se.getString()); sfsb = new SafeStringBuffer(se.getSafeString()); break; } default: throw new RuntimeException("switch"); } sbe = new StringBufferElem(sb, sfsb, sr.nextInt()); sbe.addOp(StringBufferMethod.SB_NEW); sbe.verify(); stringBufferList.add(sbe); } private void verifyStringBufferAppendString(StringBuffer sb, int oldLength, String str) { Taint sbt = sb.toString().@internal@taint(); Taint strt = str.@internal@taint(); if (sbt == null) sbt = new Taint(false, sb.length()); if (strt == null) strt = new Taint(false, str.length()); if (sb.length() != oldLength + str.length()) throw new IllegalArgumentException("append string length check:" + sb + "appended: " + str); for (int i = oldLength; i < sb.length(); i++) if (sb.charAt(i) != str.charAt(i - oldLength) || sbt.get(i) != strt.get(i - oldLength)) throw new IllegalArgumentException("append string taint check"); } private void verifyStringBufferAppendStringBuffer(StringBuffer sb, int oldLength, StringBuffer othersb) { Taint sbt = sb.toString().@internal@taint(); Taint othersbt = othersb.toString().@internal@taint(); if (sbt == null) sbt = new Taint(false, sb.length()); if (othersbt == null) othersbt = new Taint(false, othersb.length()); if (sb.length() != oldLength + othersb.length()) throw new IllegalArgumentException("append string length check:" + sb + "appended: " + othersb); for (int i = oldLength; i < sb.length(); i++) if (sb.charAt(i) != othersb.charAt(i - oldLength) || sbt.get(i) != othersbt.get(i - oldLength)) throw new IllegalArgumentException("append string taint check"); } private void verifySafeStringBufferAppendSafeString(SafeStringBuffer sfsb, int oldLength, SafeString sfs) { SafeTaint sfsbt = sfsb.taint(); SafeTaint sfstrt = sfs.taint(); if (sfsb.length() != oldLength + sfs.length()) throw new IllegalArgumentException("append string length check:" + sfsb + "appended: " + sfs); for (int i = oldLength; i < sfsb.length(); i++) if (sfsb.charAt(i) != sfs.charAt(i - oldLength) || sfsbt.get(i) != sfstrt.get(i - oldLength)) throw new IllegalArgumentException("append string taint check"); } private void verifySafeStringBufferAppendSafeStringBuffer( SafeStringBuffer sfsb, int oldLength, SafeStringBuffer othersfsb) { SafeTaint sfsbt = sfsb.taint(); SafeTaint othersfsbt = othersfsb.taint(); if (sfsb.length() != oldLength + othersfsb.length()) throw new IllegalArgumentException("append string length check:" + sfsb + "appended: " + othersfsb); for (int i = oldLength; i < sfsb.length(); i++) if (sfsb.charAt(i) != othersfsb.charAt(i - oldLength) || sfsbt.get(i) != othersfsbt.get(i - oldLength)) throw new IllegalArgumentException("append string taint check"); } private void testStringBufferAppend(StringBufferElem sbe) { StringBuffer sb = sbe.getStringBuffer(); SafeStringBuffer sfsb = sbe.getSafeStringBuffer(); int oldLen = sb.length(); StringBuffer retsb = null; SafeStringBuffer retsfsb = null; switch(sr.nextInt(14)) { case 0 : /* append(boolean) */ { boolean b = sr.nextBoolean(); retsb = sb.append(b); retsfsb = sfsb.append(b); break; } case 1: /* append(char c) */ { char c = randomChar(); retsb = sb.append(c); retsfsb = sfsb.append(c); break; } case 2: /* append(char[] str, int offset, int len */ { char[] str = randomCharArray(); int offset = sr.nextInt(str.length); int length = str.length - offset; retsb = sb.append(str, offset, length); retsfsb = sfsb.append(str, offset, length); break; } case 3: /* append(double d) */ { double d = sr.nextDouble(); retsb = sb.append(d); retsfsb = sfsb.append(d); break; } case 4: /* append(float f) */ { float f = sr.nextFloat(); retsb = sb.append(f); retsfsb = sfsb.append(f); break; } case 5: /* append(int i) */ { int i = sr.nextInt(); retsb = sb.append(i); retsfsb = sfsb.append(i); break; } case 6: /* append(long lng) */ { long lng = sr.nextLong(); retsb = sb.append(lng); retsfsb = sfsb.append(lng); break; } case 7: /* append(Object obj) */ { Object o = new Object(); retsb = sb.append(o); retsfsb = sfsb.append(o); break; } case 8: /* append(String s) */ { StringElem se = getRandomStringElem(); if (se == null) return; retsb = sb.append(se.getString()); retsfsb = sfsb.append(se.getSafeString()); verifyStringBufferAppendString(sb, oldLen, se.getString()); verifySafeStringBufferAppendSafeString(sfsb, oldLen, se.getSafeString()); break; } case 9: /* append(StringBuffer sb) */ { StringBufferElem othersbe = removeRandomStringBufferElem(); if (othersbe == null) return; othersbe.verify(); retsb = sb.append(othersbe.getStringBuffer()); retsfsb = sfsb.append(othersbe.getSafeStringBuffer()); verifyStringBufferAppendStringBuffer(sb, oldLen, othersbe.getStringBuffer()); verifySafeStringBufferAppendSafeStringBuffer(sfsb, oldLen, othersbe.getSafeStringBuffer()); othersbe.verify(); stringBufferList.add(othersbe); break; } case 10: // appendCodePoint(int codePoint) { //[ifJava5+] int codePoint = randomCodePoint(); retsb = sb.appendCodePoint(codePoint); retsfsb = sfsb.appendCodePoint(codePoint); break; //[fiJava5+] // ...else fall through } case 11: // append(CharSequence s) { //[ifJava5+] CharSequenceElem cse = randomCharSequenceElem(); retsb = sb.append(cse.getCharSequence()); retsfsb = sfsb.append(cse.getSafeCharSequence()); cse.release(); break; //[fiJava5+] // ...else fall through } case 12: // append(CharSequence s, int start, int end) { //[ifJava5+] CharSequenceElem cse = randomCharSequenceElem(); CharSequence cs = cse.getCharSequence(); SafeCharSequence sfcs = cse.getSafeCharSequence(); int start = sr.nextInt(cs.length()); int end = start + sr.nextInt(cs.length() + 1 - start); retsb = sb.append(cs, start, end); retsfsb = sfsb.append(sfcs, start, end); cse.release(); break; //[fiJava5+] // ...else fall through } case 13: /* append(char[] str) */ { char[] str = randomCharArray(); retsb = sb.append(str); retsfsb = sfsb.append(str); break; } default: throw new RuntimeException("switch"); } if (retsb != sb || retsfsb != sfsb) throw new IllegalArgumentException(sbe.toString()); } private void testStringBufferCapacity(StringBufferElem sbe) { StringBuffer sb = sbe.getStringBuffer(); SafeStringBuffer sfsb = sbe.getSafeStringBuffer(); if (sb.capacity() < 0 || sfsb.capacity() < 0) throw new IllegalArgumentException("negative capacity"); } private void testStringBufferCharAt(StringBufferElem sbe) { StringBuffer sb = sbe.getStringBuffer(); SafeStringBuffer sfsb = sbe.getSafeStringBuffer(); int index; if (sr.nextInt(16) == 0) index = sr.nextInt(); else index = sr.nextInt(sb.length()); if (index >= sb.length() || index < 0) { SafeStringBuffer oldsfsb=new SafeStringBuffer(sfsb.toSafeString()); boolean caught = false; try { sb.charAt(index); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.charAt(index); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { if (sb.charAt(index) != sfsb.charAt(index)) throw new IllegalArgumentException(sbe.toString()); } } private void testStringBufferEnsureCapacity(StringBufferElem sbe) { StringBuffer sb = sbe.getStringBuffer(); SafeStringBuffer sfsb = sbe.getSafeStringBuffer(); int capacity; if (sr.nextInt(16) != 0) capacity = -sr.nextInt(maxlen); else capacity = sr.nextInt(maxlen); sb.ensureCapacity(capacity); sfsb.ensureCapacity(capacity); } private void testStringBufferIndexOf(StringBufferElem sbe) { StringBuffer sb = sbe.getStringBuffer(); SafeStringBuffer sfsb = sbe.getSafeStringBuffer(); StringElem se; int index; boolean useIndex = sr.nextBoolean(); se = getRandomStringElem(); if (se == null) return; if (sr.nextInt(16) == 0) index = sr.nextInt(); else index = sr.nextInt(sb.length()); if (useIndex) { if (sb.indexOf(se.getString(), index) != sfsb.indexOf(se.getSafeString(), index)) throw new IllegalArgumentException(sbe.toString()); } else { if (sb.indexOf(se.getString()) != sfsb.indexOf(se.getSafeString())) throw new IllegalArgumentException(sbe.toString()); } } private void testStringBufferGetChars(StringBufferElem sbe) { StringBuffer sb = sbe.getStringBuffer(); SafeStringBuffer sfsb = sbe.getSafeStringBuffer(); int srcBegin, srcEnd, dstBegin; char[] c, sfc; int len = sr.nextInt(sb.length()); c = new char[len]; sfc = new char[len]; if (sr.nextInt(16) == 0) { srcBegin = sr.nextInt(); srcEnd = sr.nextInt(); dstBegin = sr.nextInt(); } else { srcBegin = sr.nextInt(sb.length()); srcEnd = srcBegin + sr.nextInt(Math.min(sb.length() - srcBegin, len)); dstBegin = sr.nextInt(len - (srcEnd - srcBegin) + 1); } if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > sb.length() || dstBegin < 0 || dstBegin + (srcEnd - srcBegin) > len) { SafeStringBuffer oldsbfs=new SafeStringBuffer(sfsb.toSafeString()); boolean caught = false; try { sb.getChars(srcBegin, srcEnd, c, dstBegin); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.getChars(srcBegin, srcEnd, sfc, dstBegin); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsbfs.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { sb.getChars(srcBegin, srcEnd, c, dstBegin); sfsb.getChars(srcBegin, srcEnd, sfc, dstBegin); if (!Arrays.equals(c, sfc)) throw new IllegalArgumentException(sbe.toString()); } } //[ifJava5+] private void testStringBufferCodePointAt(StringBufferElem sbe) { StringBuffer sb = sbe.getStringBuffer(); SafeStringBuffer sfsb = sbe.getSafeStringBuffer(); int index; if (sr.nextInt(16) == 0) index = sr.nextInt(); else index = sr.nextInt(sb.length()); if (index < 0 || index >= sb.length()) { SafeStringBuffer oldsfsb=new SafeStringBuffer(sfsb.toSafeString()); boolean caught = false; try { sb.codePointAt(index); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.codePointAt(index); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { if (sb.codePointAt(index) != sfsb.codePointAt(index)) throw new IllegalArgumentException(sbe.toString()); } } private void testStringBufferCodePointBefore(StringBufferElem sbe) { StringBuffer sb = sbe.getStringBuffer(); SafeStringBuffer sfsb = sbe.getSafeStringBuffer(); int index; if (sr.nextInt(16) == 0) index = sr.nextInt(); else index = 1 + sr.nextInt(sb.length()); if (index < 1 || index > sb.length()) { SafeStringBuffer oldsfsb=new SafeStringBuffer(sfsb.toSafeString()); boolean caught = false; try { sb.codePointBefore(index); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.codePointBefore(index); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { if (sb.codePointBefore(index) != sfsb.codePointBefore(index)) throw new IllegalArgumentException(sbe.toString()); } } private void testStringBufferCodePointCount(StringBufferElem sbe) { StringBuffer sb = sbe.getStringBuffer(); SafeStringBuffer sfsb = sbe.getSafeStringBuffer(); int beginIndex, endIndex; if (sr.nextInt(16) == 0) { beginIndex = sr.nextInt(); endIndex = sr.nextInt(); } else { beginIndex = sr.nextInt(sb.length()); endIndex = beginIndex + sr.nextInt(sb.length() + 1 - beginIndex); } if (beginIndex < 0 || endIndex > sb.length() || beginIndex > endIndex) { SafeStringBuffer oldsfsb=new SafeStringBuffer(sfsb.toSafeString()); boolean caught = false; try { sb.codePointCount(beginIndex, endIndex); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.codePointCount(beginIndex, endIndex); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { if (sb.codePointCount(beginIndex, endIndex) != sfsb.codePointCount(beginIndex, endIndex)) throw new IllegalArgumentException(sbe.toString()); } } private void testStringBufferCodePoint(StringBufferElem sbe) { switch (sr.nextInt(3)) { case 0: testStringBufferCodePointAt(sbe); break; case 1: testStringBufferCodePointBefore(sbe); break; case 2: testStringBufferCodePointCount(sbe); break; default: throw new RuntimeException("switched failed"); } } //[fiJava5+] private void testStringBufferDelete(StringBufferElem sbe) { StringBuffer sb = sbe.getStringBuffer(); SafeStringBuffer sfsb = sbe.getSafeStringBuffer(); int oldLen = sb.length(); int beginIndex, endIndex; boolean useCharAt = false; if (sr.nextInt() == 0) { beginIndex = sr.nextInt(); endIndex = sr.nextInt(); } else { beginIndex = sr.nextInt(sb.length()); switch(sr.nextInt(3)) { case 0: case 1: endIndex = beginIndex + sr.nextInt(maxlen); break; case 2: endIndex = beginIndex + 1; useCharAt = true; break; default: throw new RuntimeException("switch"); } } if (beginIndex < 0 || beginIndex > endIndex || beginIndex > sb.length() || (useCharAt && beginIndex == sb.length())) { SafeStringBuffer oldsfsb=new SafeStringBuffer(sfsb.toSafeString()); boolean caught = false; try { if (useCharAt) sb.deleteCharAt(beginIndex); else sb.delete(beginIndex, endIndex); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { if (useCharAt) sfsb.deleteCharAt(beginIndex); else sfsb.delete(beginIndex, endIndex); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { StringBuffer retsb; SafeStringBuffer retsfsb; if (useCharAt) { retsb = sb.deleteCharAt(beginIndex); retsfsb = sfsb.deleteCharAt(beginIndex); if (sb.length() - oldLen != -1) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.delete(beginIndex, endIndex); retsfsb = sfsb.delete(beginIndex, endIndex); endIndex = Math.min(endIndex, oldLen); if (sb.length() - oldLen != beginIndex - endIndex) throw new IllegalArgumentException(sbe.toString()); } if (retsb != sb || retsfsb != sfsb) throw new IllegalArgumentException(sbe.toString()); } } private void verifyStringBufferInsertString(StringBuffer sb, int oldLength, int offset, String str) { Taint sbt = sb.toString().@internal@taint(); Taint strt = str.@internal@taint(); if (sbt == null) sbt = new Taint(false, sb.length()); if (strt == null) strt = new Taint(false, str.length()); if (sb.length() != oldLength + str.length()) throw new IllegalArgumentException("insert string length check:" + sb + "inserted: " + str); for (int i = offset; i < offset + str.length(); i++) if (sb.charAt(i) != str.charAt(i - offset) || sbt.get(i) != strt.get(i - offset)) throw new IllegalArgumentException("insert string taint check"); } private void verifySafeStringBufferInsertSafeString(SafeStringBuffer sfsb, int oldLength, int offset, SafeString sfs) { SafeTaint sfsbt = sfsb.taint(); SafeTaint sfstrt = sfs.taint(); if (sfsb.length() != oldLength + sfs.length()) throw new IllegalArgumentException("insert string length check:" + sfsb + "inserted: " + sfs); for (int i = offset; i < offset + sfs.length(); i++) if (sfsb.charAt(i) != sfs.charAt(i - offset) || sfsbt.get(i) != sfstrt.get(i - offset)) throw new IllegalArgumentException("insert string taint check"); } private void testStringBufferInsert(StringBufferElem sbe) { StringBuffer sb = sbe.getStringBuffer(); SafeStringBuffer sfsb = sbe.getSafeStringBuffer(); SafeStringBuffer oldsfsb = new SafeStringBuffer(sfsb.toSafeString()); int oldLen = sb.length(); int offset; boolean except = false; StringBuffer retsb = null; SafeStringBuffer retsfsb = null; if (sr.nextInt(16) == 0) offset = sr.nextInt(); else offset = sr.nextInt(sb.length() + 1); if (offset < 0 || offset > sb.length()) except = true; switch(sr.nextInt(12)) { case 0 : /* insert(int offset, boolean) */ { boolean b = sr.nextBoolean(); if (except) { boolean caught = false; try { sb.insert(offset, b); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.insert(offset, b); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.insert(offset, b); retsfsb = sfsb.insert(offset, b); } break; } case 1: /* insert(int offset, char c) */ { char c = randomChar(); if (except) { boolean caught = false; try { sb.insert(offset, c); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.insert(offset, c); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.insert(offset, c); retsfsb = sfsb.insert(offset, c); } break; } case 2: /* insert(int offset, char[] str, int offset, int len) */ { char[] str = randomCharArray(); int index = sr.nextInt(str.length); int length = str.length - offset; if (except || index + length > str.length || ((index|length) < 0)) { boolean caught = false; try { sb.insert(offset, str, index, length); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.insert(offset, str, index, length); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.insert(offset, str, index, length); retsfsb = sfsb.insert(offset, str, index, length); } break; } case 3: /* insert(int offset, double d) */ { double d = sr.nextDouble(); if (except) { boolean caught = false; try { sb.insert(offset, d); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.insert(offset, d); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.insert(offset, d); retsfsb = sfsb.insert(offset, d); } break; } case 4: /* insert(int offset, float f) */ { float f = sr.nextFloat(); if (except) { boolean caught = false; try { sb.insert(offset, f); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.insert(offset, f); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.insert(offset, f); retsfsb = sfsb.insert(offset, f); } break; } case 5: /* insert(int offset, int i) */ { int i = sr.nextInt(); if (except) { boolean caught = false; try { sb.insert(offset, i); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.insert(offset, i); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.insert(offset, i); retsfsb = sfsb.insert(offset, i); } break; } case 6: /* insert(int offset, long lng) */ { long lng = sr.nextLong(); if (except) { boolean caught = false; try { sb.insert(offset, lng); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.insert(offset, lng); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.insert(offset, lng); retsfsb = sfsb.insert(offset, lng); } break; } case 7: /* insert(int offset, Object obj) */ { Object o = new Object(); if (except) { boolean caught = false; try { sb.insert(offset, o); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.insert(offset, o); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.insert(offset, o); retsfsb = sfsb.insert(offset, o); } break; } case 8: /* insert(int offset, String s) */ { StringElem se = getRandomStringElem(); if (se == null) return; if (except) { boolean caught = false; try { sb.insert(offset, se.getString()); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.insert(offset, se.getSafeString()); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.insert(offset, se.getString()); retsfsb = sfsb.insert(offset, se.getSafeString()); verifyStringBufferInsertString(sb, oldLen, offset, se.getString()); verifySafeStringBufferInsertSafeString(sfsb, oldLen, offset, se.getSafeString()); } break; } case 9: // insert(int dstOffset, CharSequence s) { //[ifJava5+] CharSequenceElem cse = randomCharSequenceElem(); if (except) { boolean caught = false; try { sb.insert(offset, cse.getCharSequence()); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.insert(offset, cse.getSafeCharSequence()); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.insert(offset, cse.getCharSequence()); retsfsb = sfsb.insert(offset, cse.getSafeCharSequence()); } cse.release(); break; //[fiJava5+] // ...else fall through } case 10: // insert(int dstOffset, CharSequence s, int start, // int end) { //[ifJava5+] CharSequenceElem cse = randomCharSequenceElem(); CharSequence cs = cse.getCharSequence(); SafeCharSequence sfcs = cse.getSafeCharSequence(); int start = sr.nextInt(cs.length()); int end = start + sr.nextInt(cs.length() + 1 - start); if (except) { boolean caught = false; try { sb.insert(offset, cs, start, end); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.insert(offset, sfcs, start, end); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.insert(offset, cs, start, end); retsfsb = sfsb.insert(offset, sfcs, start, end); } cse.release(); break; //[fiJava5+] // ...else fall through } case 11: /* insert(int offset, char[] str) */ { char[] str = randomCharArray(); if (except) { boolean caught = false; try { sb.insert(offset, str); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.insert(offset, str); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { retsb = sb.insert(offset, str); retsfsb = sfsb.insert(offset, str); } break; } default: throw new RuntimeException("switch"); } if (retsb == null || retsfsb == null) { if (retsb != null || retsfsb != null) throw new IllegalArgumentException(sbe.toString()); } else { if (retsb != sb || retsfsb != sfsb) throw new IllegalArgumentException(sbe.toString()); } } private void testStringBufferLastIndexOf(StringBufferElem sbe) { StringBuffer sb = sbe.getStringBuffer(); SafeStringBuffer sfsb = sbe.getSafeStringBuffer(); StringElem se; int index; boolean useIndex = sr.nextBoolean(); se = getRandomStringElem(); if (se == null) return; if (sr.nextInt(16) == 0) index = sr.nextInt(); else index = sr.nextInt(sb.length()); if (useIndex) { if (sb.lastIndexOf(se.getString(), index) != sfsb.lastIndexOf(se.getSafeString(), index)) throw new IllegalArgumentException(sbe.toString()); } else { if (sb.lastIndexOf(se.getString()) != sfsb.lastIndexOf(se.getSafeString())) throw new IllegalArgumentException(sbe.toString()); } } //[ifJava5+] private void testStringBufferOffsetByCodePoints(StringBufferElem sbe) { StringBuffer sb = sbe.getStringBuffer(); SafeStringBuffer sfsb = sbe.getSafeStringBuffer(); int index; int codePointOffset; if (sr.nextInt(16) == 0) { index = sr.nextInt(); codePointOffset = sr.nextInt(); } else { index = sr.nextInt(sb.length()); boolean sign = sr.nextBoolean(); if (sign) codePointOffset = -sr.nextInt(sb.codePointCount(0, index)); else codePointOffset = sr.nextInt(sb.codePointCount(index,sb.length())); } if (index < 0 || index > sb.length() || (codePointOffset > 0 && codePointOffset > sb.codePointCount(index, sb.length())) || (codePointOffset < 0 && -codePointOffset > sb.codePointCount(0,index))) { SafeStringBuffer oldsfsb=new SafeStringBuffer(sfsb.toSafeString()); boolean caught = false; try { sb.offsetByCodePoints(index, codePointOffset); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.offsetByCodePoints(index, codePointOffset); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { if (sb.offsetByCodePoints(index, codePointOffset) != sfsb.offsetByCodePoints(index, codePointOffset)) throw new IllegalArgumentException(sbe.toString()); } } //[fiJava5+] private void testStringBufferReplace(StringBufferElem sbe) { StringBuffer sb = sbe.getStringBuffer(); SafeStringBuffer sfsb = sbe.getSafeStringBuffer(); StringElem se = getRandomStringElem(); if (se == null) return; String s = se.getString(); SafeString sfs = se.getSafeString(); int oldLen = sb.length(); int beginIndex, endIndex; if (sr.nextInt() == 0) { beginIndex = sr.nextInt(); endIndex = sr.nextInt(); } else { beginIndex = sr.nextInt(sb.length()); endIndex = beginIndex + sr.nextInt(maxlen); } if (beginIndex < 0 || beginIndex > endIndex || beginIndex > sb.length()) { SafeStringBuffer oldsfsb=new SafeStringBuffer(sfsb.toSafeString()); boolean caught = false; try { sb.replace(beginIndex, endIndex, s); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.replace(beginIndex, endIndex, sfs); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { StringBuffer retsb = sb.replace(beginIndex, endIndex, s); SafeStringBuffer retsfsb = sfsb.replace(beginIndex, endIndex, sfs); endIndex = Math.min(endIndex, oldLen); if (sb.length() - oldLen != beginIndex - endIndex + s.length()) throw new IllegalArgumentException(sbe.toString()); Taint t = sb.toString().@internal@taint(); if (t == null) t = new Taint(false, sb.length()); for (int i = beginIndex; i < s.length(); i++) if (sb.charAt(i) != sfs.charAt(i - beginIndex) || t.get(i) != sfs.taint().get(i - beginIndex)) throw new IllegalArgumentException(sbe.toString()); if (retsb != sb || retsfsb != sfsb) throw new IllegalArgumentException(sbe.toString()); } } private void testStringBufferSetCharAt(StringBufferElem sbe) { StringBuffer sb = sbe.getStringBuffer(); SafeStringBuffer sfsb = sbe.getSafeStringBuffer(); char c = randomChar(); int index; if (sr.nextInt(16) == 0) index = sr.nextInt(); else index = sr.nextInt(sb.length()); if (index < 0 || index >= sb.length()) { SafeStringBuffer oldsfsb=new SafeStringBuffer(sfsb.toSafeString()); boolean caught = false; try { sb.setCharAt(index, c); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.setCharAt(index, c); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { sb.setCharAt(index, c); sfsb.setCharAt(index, c); Taint t = sb.toString().@internal@taint(); if (t == null) t = new Taint(false, sb.length()); if (sb.charAt(index) != c || sfsb.charAt(index) != c || t.get(index) || sfsb.taint().get(index)) throw new IllegalArgumentException(sbe.toString()); } } private void testStringBufferSetLength(StringBufferElem sbe) { StringBuffer sb = sbe.getStringBuffer(); SafeStringBuffer sfsb = sbe.getSafeStringBuffer(); int m = maxlen < sb.length() ? sb.length() + 1024 : maxlen; int len; if (sr.nextInt(16) == 0) len = -sr.nextInt(m); else len = sr.nextInt(m); if (len < 0) { SafeStringBuffer oldsfsb=new SafeStringBuffer(sfsb.toSafeString()); boolean caught = false; try { sb.setLength(len); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { sfsb.setLength(len); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { sb.setLength(len); sfsb.setLength(len); if (sb.length() != len || sfsb.length() != len) throw new IllegalArgumentException(sbe.toString()); } } private void testStringBufferSubSequence(StringBufferElem sbe) { StringBuffer sb = sbe.getStringBuffer(); SafeStringBuffer sfsb = sbe.getSafeStringBuffer(); int beginIndex, endIndex; CharSequence subs; SafeCharSequence subsfs; if (sr.nextInt(16) == 0) { beginIndex = sr.nextInt(); endIndex = sr.nextInt(); } else { beginIndex = sr.nextInt(sb.length()); endIndex = beginIndex + sr.nextInt(sb.length() + 1 - beginIndex); } if (beginIndex < 0 || endIndex > sb.length() || beginIndex > endIndex) { /* Exception time */ SafeStringBuffer oldsfsb=new SafeStringBuffer(sfsb.toSafeString()); boolean caught = false; try { subs = sb.subSequence(beginIndex, endIndex); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { subsfs = (SafeCharSequence) sfsb.subSequence(beginIndex, endIndex); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { subs = sb.subSequence(beginIndex, endIndex); subsfs = (SafeCharSequence) sfsb.subSequence(beginIndex, endIndex); subsfs.toSafeString().verify(subs.toString()); Taint t = sb.toString().@internal@taint(); Taint subt = subs.toString().@internal@taint(); if (t == null) t = new Taint(false, sb.length()); if (subt == null) subt = new Taint(false, subs.length()); for (int i = beginIndex; i < endIndex; i++) { if (sb.charAt(i) != subs.charAt(i - beginIndex) || t.get(i) != subt.get(i-beginIndex)) throw new IllegalArgumentException("string taint/data bad"); } } } private void testStringBufferReverse(StringBufferElem sbe) { StringBuffer sb = sbe.getStringBuffer(); SafeStringBuffer sfsb = sbe.getSafeStringBuffer(); StringBuffer retsb; SafeStringBuffer retsfsb; int len = sb.length(); retsb = sb.reverse(); retsfsb = sfsb.reverse(); sbe.verify(); if (sb.length() != len || retsb != sb || retsfsb != sfsb) throw new IllegalArgumentException(sbe.toString()); } private void testStringBufferLength(StringBufferElem sbe) { if (sbe.getStringBuffer().length() != sbe.getSafeStringBuffer().length()) throw new IllegalArgumentException(sbe.toString()); } private void testStringBufferSubstring(StringBufferElem sbe) { StringBuffer sb = sbe.getStringBuffer(); SafeStringBuffer sfsb = sbe.getSafeStringBuffer(); int beginIndex, endIndex; StringElem subse; String subs; SafeString subsfs; if (sr.nextInt(16) == 0) { beginIndex = sr.nextInt(); endIndex = sr.nextInt(); } else { beginIndex = sr.nextInt(sb.length()); endIndex = beginIndex + sr.nextInt(sb.length()+1 - beginIndex); } if (beginIndex < 0 || endIndex > sb.length() || beginIndex > endIndex) { /* Exception time */ SafeStringBuffer oldsfsb=new SafeStringBuffer(sfsb.toSafeString()); boolean caught = false; try { subs = sb.substring(beginIndex, endIndex); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught) throw new IllegalArgumentException(sbe.toString()); caught = false; try { subsfs = sfsb.substring(beginIndex, endIndex); } catch (IndexOutOfBoundsException e) { caught = true; } if (!caught || !oldsfsb.verify(sb)) throw new IllegalArgumentException(sbe.toString()); } else { if (endIndex == sb.length() && sr.nextBoolean()) { subs = sb.substring(beginIndex); subsfs = sfsb.substring(beginIndex); } else { subs = sb.substring(beginIndex, endIndex); subsfs = sfsb.substring(beginIndex, endIndex); } subsfs.verify(subs); Taint t = sb.toString().@internal@taint(); Taint subt = subs.@internal@taint(); if (t == null) t = new Taint(false, sb.length()); if (subt == null) subt = new Taint(false, subs.length()); for (int i = beginIndex; i < endIndex; i++) if (sb.charAt(i) != subs.charAt(i - beginIndex) || t.get(i) != subt.get(i-beginIndex)) throw new IllegalArgumentException("string taint/data bad"); subse = new StringElem(subs, subsfs, sr.nextInt()); subse.verify(); subse.addOp("[" + sbe.toString() + "] StringBuffer.substring"); stringList.add(subse); } } private void testStringBufferToString(StringBufferElem sbe) { StringBuffer sb = sbe.getStringBuffer(); SafeStringBuffer sfsb = sbe.getSafeStringBuffer(); String s = sb.toString(); SafeString sfs = sfsb.toSafeString(); StringElem se = new StringElem(s, sfs, sr.nextInt()); se.verify(); sbe.verify(s); se.addOp("[" + sbe.toString() + "] StringBuffer.toString"); stringList.add(se); } private void testStringBufferTrimToSize(StringBufferElem sbe) { //[ifJava5+] sbe.getStringBuffer().trimToSize(); sbe.getSafeStringBuffer().trimToSize(); //[fiJava5+] } private void testStringBufferSerialize(StringBufferElem sbe) throws IOException, ClassNotFoundException { StringBuffer sb = sbe.getStringBuffer(); SafeStringBuffer sfsb = sbe.getSafeStringBuffer(); sfsb = new SafeStringBuffer(new SafeString( sfsb.toSafeString().origString(), new SafeTaint(false, sfsb.length()))); ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream os = new ObjectOutputStream(bout); os.writeObject(sb); os.flush(); os.close(); ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); ObjectInputStream is = new ObjectInputStream(bin); sb = (StringBuffer) is.readObject(); is.close(); bin.close(); bout.close(); if (sb.toString().@internal@isTainted()) throw new RuntimeException("Corrupted Serialization"); StringBufferElem newSbe = new StringBufferElem(sb,sfsb,sr.nextInt()); newSbe.verify(); sbe.addOp(StringBufferMethod.SB_SERIALIZE); } public void testStringBuffer() throws IllegalArgumentException, IOException, ClassNotFoundException { int op = sr.nextInt(StringBufferMethod.SB_END); StringBufferElem sbe = null; if (stringBufferList.size() < threads * 2) op = StringBufferMethod.SB_NEW; if (op != StringBufferMethod.SB_NEW) { sbe = removeRandomStringBufferElem(); if (sbe == null) { op = StringBufferMethod.SB_NEW; } else { sbe.verify(); sbe.addOp(op); } } switch(op) { case StringBufferMethod.SB_NEW: testStringBufferNew(); break; case StringBufferMethod.SB_APPEND: testStringBufferAppend(sbe); break; case StringBufferMethod.SB_CAPACITY: testStringBufferCapacity(sbe); break; case StringBufferMethod.SB_CHARAT: testStringBufferCharAt(sbe); break; case StringBufferMethod.SB_CODEPOINT: //[ifJava5+] testStringBufferCodePoint(sbe); break; //[fiJava5+] //...else fall through case StringBufferMethod.SB_DELETE: testStringBufferDelete(sbe); break; case StringBufferMethod.SB_ENSURECAPACITY: testStringBufferEnsureCapacity(sbe); break; case StringBufferMethod.SB_GETCHARS: testStringBufferGetChars(sbe); break; case StringBufferMethod.SB_INDEXOF: testStringBufferIndexOf(sbe); break; case StringBufferMethod.SB_INSERT: testStringBufferInsert(sbe); break; case StringBufferMethod.SB_LASTINDEXOF: testStringBufferLastIndexOf(sbe); break; case StringBufferMethod.SB_LENGTH: testStringBufferLength(sbe); break; case StringBufferMethod.SB_OFFSETBYCODEPOINTS: //[ifJava5+] testStringBufferOffsetByCodePoints(sbe); break; //[fiJava5+] //...else fall through case StringBufferMethod.SB_REPLACE: testStringBufferReplace(sbe); break; case StringBufferMethod.SB_REVERSE: testStringBufferReverse(sbe); break; case StringBufferMethod.SB_SETCHARAT: testStringBufferSetCharAt(sbe); break; case StringBufferMethod.SB_SETLENGTH: testStringBufferSetLength(sbe); break; case StringBufferMethod.SB_SUBSEQUENCE: testStringBufferSubSequence(sbe); break; case StringBufferMethod.SB_SUBSTRING: testStringBufferSubstring(sbe); break; case StringBufferMethod.SB_TOSTRING: testStringBufferToString(sbe); break; case StringBufferMethod.SB_TRIMTOSIZE: testStringBufferTrimToSize(sbe); break; case StringBufferMethod.SB_SERIALIZE: testStringBufferSerialize(sbe); break; default: throw new RuntimeException("switch"); } if (op != StringBufferMethod.SB_NEW) { sbe.verify(); stringBufferList.add(sbe); } } public void test() throws IllegalArgumentException, UnsupportedEncodingException, IOException, ClassNotFoundException { int op = sr.nextInt(3); switch(op) { case 0: testString(); break; case 1: //[ifJava5+] testStringBuilder(); break; //[fiJava5+] // ...else fall through case 2: testStringBuffer(); break; default: throw new RuntimeException("Broken switch"); } } public void run() { try { for (int i = 0; i < nrtest; i++) test(); } catch (OutOfMemoryError oom) { System.out.println(oom); oom.printStackTrace(); System.exit(0); } catch (Throwable e) { fail = true; System.out.println(e); e.printStackTrace(); } } public static void main(String[] args) { StringTest[] t; int ret = 0; PrintStream ps = null; SafeRandom[] randArray; Random rbase; String logfile = "StringTest.log"; long seed = System.currentTimeMillis(); threads = 1; for (int i = 0; i < args.length; i++) { if (args[i].equals("-s")) seed = Long.decode(args[++i]).longValue(); else if (args[i].equals("-t")) threads = Integer.decode(args[++i]).intValue(); else if (args[i].equals("-l")) maxlen = Integer.decode(args[++i]).intValue(); else if (args[i].equals("-n")) nrtest = Integer.decode(args[++i]).intValue(); else if (args[i].equals("-f")) logfile = args[++i]; else { System.out.println("Usage: java StringTest " + "[-t numberofTheads] [-s randomSeed] " + "[-l maximumLengthofNewString] " + "[-n NumberofTestsPerThread]" + "[-f logFileName]"); System.exit(-1); } } try { ps = new PrintStream(new FileOutputStream(logfile)); } catch (FileNotFoundException e) { System.out.println("Error opening logfile [" + logfile + "]: " + e); System.exit(-1); } ps.print("-s "); ps.print(seed); ps.print(" -t "); ps.print(threads); ps.print(" -l "); ps.print(maxlen); ps.print(" -n "); ps.print(nrtest); ps.print(" -f "); ps.print(logfile + "\n"); ps.flush(); ps.close(); /* else List l = new synchronedList(... ) */ t = new StringTest[threads]; randArray = new SafeRandom[threads]; rbase = new Random(seed); for (int i = 0; i < threads; i++) randArray[i] = new SafeRandom(rbase.nextLong()); for (int i = 0; i < threads; i++) { t[i] = new StringTest(randArray[i]); t[i].start(); } System.out.println("Started " + threads + " threads"); for (int i = 0; i < threads; i++) { try { t[i].join(); } catch (InterruptedException e) { System.out.println("Interrupted!: " + e); System.exit(-1); } } if (fail) ret = -1; if (Log.hasError() || Log.hasWarning() || Log.hasVuln()) { System.out.println("Error or Warning encountered -- check logs"); System.exit(-1); } System.exit(ret); } }