Fix 2 bugs in LuaString.

* Number parsing did not check for overflow.
 * A circular dependency could cause random NullPointerExceptions at
   class loading time.
This commit is contained in:
Ian Farmer
2013-07-04 06:51:09 +00:00
parent e5d666efd0
commit 9aeb0e2eac

View File

@@ -67,13 +67,6 @@ public class LuaString extends LuaValue {
* ecause no LuaString whose backing exceeds this length will be put into the cache. */ * ecause no LuaString whose backing exceeds this length will be put into the cache. */
public static final int RECENT_STRINGS_MAX_LENGTH = 32; public static final int RECENT_STRINGS_MAX_LENGTH = 32;
/** Simple cache of recently created strings that are short.
* This is simply a list of strings, indexed by their hash codes modulo the cache size
* that have been recently constructed. If a string is being constructed frequently
* from different contexts, it will generally may show up as a cache hit and resolve
* to the same value. */
public static volatile LuaString recent_short_strings[] = new LuaString[RECENT_STRINGS_CACHE_SIZE];
/** The singleton instance representing lua {@code true} */ /** The singleton instance representing lua {@code true} */
public static LuaValue s_metatable; public static LuaValue s_metatable;
@@ -86,6 +79,26 @@ public class LuaString extends LuaValue {
/** The number of bytes that comprise this string */ /** The number of bytes that comprise this string */
public final int m_length; public final int m_length;
private static class Cache {
/** Simple cache of recently created strings that are short.
* This is simply a list of strings, indexed by their hash codes modulo the cache size
* that have been recently constructed. If a string is being constructed frequently
* from different contexts, it will generally may show up as a cache hit and resolve
* to the same value. */
public final LuaString recent_short_strings[] = new LuaString[RECENT_STRINGS_CACHE_SIZE];
public LuaString get(LuaString s) {
final int index = s.hashCode() & (RECENT_STRINGS_CACHE_SIZE - 1);
final LuaString cached = (LuaString) recent_short_strings[index];
if (cached != null && s.raweq(cached))
return cached;
recent_short_strings[index] = s;
return s;
}
static final Cache instance = new Cache();
}
/** /**
* Get a {@link LuaString} instance whose bytes match * Get a {@link LuaString} instance whose bytes match
* the supplied Java String using the UTF8 encoding. * the supplied Java String using the UTF8 encoding.
@@ -116,12 +129,7 @@ public class LuaString extends LuaValue {
if (bytes.length < RECENT_STRINGS_MAX_LENGTH) { if (bytes.length < RECENT_STRINGS_MAX_LENGTH) {
// Short string. Reuse the backing and check the cache of recent strings before returning. // Short string. Reuse the backing and check the cache of recent strings before returning.
final LuaString s = new LuaString(bytes, off, len); final LuaString s = new LuaString(bytes, off, len);
final int index = s.hashCode() & (RECENT_STRINGS_CACHE_SIZE - 1); return Cache.instance.get( s );
final LuaString cached = recent_short_strings[index];
if (cached != null && s.raweq(cached))
return cached;
recent_short_strings[index] = s;
return s;
} else if (len >= bytes.length / 2) { } else if (len >= bytes.length / 2) {
// Reuse backing only when more than half the bytes are part of the result. // Reuse backing only when more than half the bytes are part of the result.
return new LuaString(bytes, off, len); return new LuaString(bytes, off, len);
@@ -713,6 +721,8 @@ public class LuaString extends LuaValue {
if ( digit < 0 || digit >= base ) if ( digit < 0 || digit >= base )
return Double.NaN; return Double.NaN;
x = x * base + digit; x = x * base + digit;
if ( x < 0 )
return Double.NaN; // overflow
} }
return neg? -x: x; return neg? -x: x;
} }