mirror of https://github.com/apache/lucene.git
LUCENE-7800: Remove code that potentially rethrows checked exceptions from methods that don't declare them ("sneaky throw" hack).
This commit is contained in:
parent
c9bdce937a
commit
5a50887a4b
|
@ -97,6 +97,12 @@ Other
|
||||||
|
|
||||||
======================= Lucene 6.7.0 =======================
|
======================= Lucene 6.7.0 =======================
|
||||||
|
|
||||||
|
Other
|
||||||
|
|
||||||
|
* LUCENE-7800: Remove code that potentially rethrows checked exceptions
|
||||||
|
from methods that don't declare them ("sneaky throw" hack). (Robert Muir,
|
||||||
|
Uwe Schindler, Dawid Weiss)
|
||||||
|
|
||||||
======================= Lucene 6.6.0 =======================
|
======================= Lucene 6.6.0 =======================
|
||||||
|
|
||||||
New Features
|
New Features
|
||||||
|
|
|
@ -31,6 +31,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
package org.tartarus.snowball;
|
package org.tartarus.snowball;
|
||||||
|
|
||||||
|
import java.lang.reflect.UndeclaredThrowableException;
|
||||||
|
|
||||||
import org.apache.lucene.util.ArrayUtil;
|
import org.apache.lucene.util.ArrayUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -313,8 +315,10 @@ public abstract class SnowballProgram {
|
||||||
boolean res = false;
|
boolean res = false;
|
||||||
try {
|
try {
|
||||||
res = (boolean) w.method.invokeExact(this);
|
res = (boolean) w.method.invokeExact(this);
|
||||||
|
} catch (Error | RuntimeException e) {
|
||||||
|
throw e;
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
rethrow(e);
|
throw new UndeclaredThrowableException(e);
|
||||||
}
|
}
|
||||||
cursor = c + w.s_size;
|
cursor = c + w.s_size;
|
||||||
if (res) return w.result;
|
if (res) return w.result;
|
||||||
|
@ -376,8 +380,10 @@ public abstract class SnowballProgram {
|
||||||
boolean res = false;
|
boolean res = false;
|
||||||
try {
|
try {
|
||||||
res = (boolean) w.method.invokeExact(this);
|
res = (boolean) w.method.invokeExact(this);
|
||||||
|
} catch (Error | RuntimeException e) {
|
||||||
|
throw e;
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
rethrow(e);
|
throw new UndeclaredThrowableException(e);
|
||||||
}
|
}
|
||||||
cursor = c - w.s_size;
|
cursor = c - w.s_size;
|
||||||
if (res) return w.result;
|
if (res) return w.result;
|
||||||
|
@ -485,15 +491,5 @@ extern void debug(struct SN_env * z, int number, int line_count)
|
||||||
printf("'\n");
|
printf("'\n");
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Hack to rethrow unknown Exceptions from {@link MethodHandle#invoke}:
|
|
||||||
private static void rethrow(Throwable t) {
|
|
||||||
SnowballProgram.<Error>rethrow0(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private static <T extends Throwable> void rethrow0(Throwable t) throws T {
|
|
||||||
throw (T) t;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ package org.apache.lucene.util;
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.lang.invoke.MethodType;
|
import java.lang.invoke.MethodType;
|
||||||
|
import java.lang.reflect.UndeclaredThrowableException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An AttributeFactory creates instances of {@link AttributeImpl}s.
|
* An AttributeFactory creates instances of {@link AttributeImpl}s.
|
||||||
|
@ -28,8 +29,14 @@ public abstract class AttributeFactory {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an {@link AttributeImpl} for the supplied {@link Attribute} interface class.
|
* Returns an {@link AttributeImpl} for the supplied {@link Attribute} interface class.
|
||||||
|
*
|
||||||
|
* @throws UndeclaredThrowableException A wrapper runtime exception thrown if the
|
||||||
|
* constructor of the attribute class throws a checked exception.
|
||||||
|
* Note that attributes should not throw or declare
|
||||||
|
* checked exceptions; this may be verified and fail early in the future.
|
||||||
*/
|
*/
|
||||||
public abstract AttributeImpl createAttributeInstance(Class<? extends Attribute> attClass);
|
public abstract AttributeImpl createAttributeInstance(Class<? extends Attribute> attClass)
|
||||||
|
throws UndeclaredThrowableException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a correctly typed {@link MethodHandle} for the no-arg ctor of the given class.
|
* Returns a correctly typed {@link MethodHandle} for the no-arg ctor of the given class.
|
||||||
|
@ -66,9 +73,10 @@ public abstract class AttributeFactory {
|
||||||
public AttributeImpl createAttributeInstance(Class<? extends Attribute> attClass) {
|
public AttributeImpl createAttributeInstance(Class<? extends Attribute> attClass) {
|
||||||
try {
|
try {
|
||||||
return (AttributeImpl) constructors.get(attClass).invokeExact();
|
return (AttributeImpl) constructors.get(attClass).invokeExact();
|
||||||
} catch (Throwable t) {
|
} catch (Error | RuntimeException e) {
|
||||||
rethrow(t);
|
throw e;
|
||||||
throw new AssertionError();
|
} catch (Throwable e) {
|
||||||
|
throw new UndeclaredThrowableException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,23 +146,12 @@ public abstract class AttributeFactory {
|
||||||
protected A createInstance() {
|
protected A createInstance() {
|
||||||
try {
|
try {
|
||||||
return (A) constr.invokeExact();
|
return (A) constr.invokeExact();
|
||||||
} catch (Throwable t) {
|
} catch (Error | RuntimeException e) {
|
||||||
rethrow(t);
|
throw e;
|
||||||
throw new AssertionError();
|
} catch (Throwable e) {
|
||||||
|
throw new UndeclaredThrowableException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hack to rethrow unknown Exceptions from {@link MethodHandle#invoke}:
|
|
||||||
// TODO: remove the impl in test-framework, this one is more elegant :-)
|
|
||||||
static void rethrow(Throwable t) {
|
|
||||||
AttributeFactory.<Error>rethrow0(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private static <T extends Throwable> void rethrow0(Throwable t) throws T {
|
|
||||||
throw (T) t;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -189,14 +189,19 @@ public final class JavascriptCompiler {
|
||||||
final Map<String, Integer> externalsMap = new LinkedHashMap<>();
|
final Map<String, Integer> externalsMap = new LinkedHashMap<>();
|
||||||
final ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
final ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||||
|
|
||||||
|
try {
|
||||||
generateClass(getAntlrParseTree(), classWriter, externalsMap);
|
generateClass(getAntlrParseTree(), classWriter, externalsMap);
|
||||||
|
|
||||||
try {
|
|
||||||
final Class<? extends Expression> evaluatorClass = new Loader(parent)
|
final Class<? extends Expression> evaluatorClass = new Loader(parent)
|
||||||
.define(COMPILED_EXPRESSION_CLASS, classWriter.toByteArray());
|
.define(COMPILED_EXPRESSION_CLASS, classWriter.toByteArray());
|
||||||
final Constructor<? extends Expression> constructor = evaluatorClass.getConstructor(String.class, String[].class);
|
final Constructor<? extends Expression> constructor = evaluatorClass.getConstructor(String.class, String[].class);
|
||||||
|
|
||||||
return constructor.newInstance(sourceText, externalsMap.keySet().toArray(new String[externalsMap.size()]));
|
return constructor.newInstance(sourceText, externalsMap.keySet().toArray(new String[externalsMap.size()]));
|
||||||
|
} catch (RuntimeException re) {
|
||||||
|
if (re.getCause() instanceof ParseException) {
|
||||||
|
throw (ParseException)re.getCause();
|
||||||
|
}
|
||||||
|
throw re;
|
||||||
} catch (ReflectiveOperationException exception) {
|
} catch (ReflectiveOperationException exception) {
|
||||||
throw new IllegalStateException("An internal error occurred attempting to compile the expression (" + sourceText + ").", exception);
|
throw new IllegalStateException("An internal error occurred attempting to compile the expression (" + sourceText + ").", exception);
|
||||||
}
|
}
|
||||||
|
@ -209,7 +214,6 @@ public final class JavascriptCompiler {
|
||||||
* @throws ParseException on failure to parse
|
* @throws ParseException on failure to parse
|
||||||
*/
|
*/
|
||||||
private ParseTree getAntlrParseTree() throws ParseException {
|
private ParseTree getAntlrParseTree() throws ParseException {
|
||||||
try {
|
|
||||||
final ANTLRInputStream antlrInputStream = new ANTLRInputStream(sourceText);
|
final ANTLRInputStream antlrInputStream = new ANTLRInputStream(sourceText);
|
||||||
final JavascriptErrorHandlingLexer javascriptLexer = new JavascriptErrorHandlingLexer(antlrInputStream);
|
final JavascriptErrorHandlingLexer javascriptLexer = new JavascriptErrorHandlingLexer(antlrInputStream);
|
||||||
javascriptLexer.removeErrorListeners();
|
javascriptLexer.removeErrorListeners();
|
||||||
|
@ -217,12 +221,6 @@ public final class JavascriptCompiler {
|
||||||
javascriptParser.removeErrorListeners();
|
javascriptParser.removeErrorListeners();
|
||||||
javascriptParser.setErrorHandler(new JavascriptParserErrorStrategy());
|
javascriptParser.setErrorHandler(new JavascriptParserErrorStrategy());
|
||||||
return javascriptParser.compile();
|
return javascriptParser.compile();
|
||||||
} catch (RuntimeException re) {
|
|
||||||
if (re.getCause() instanceof ParseException) {
|
|
||||||
throw (ParseException)re.getCause();
|
|
||||||
}
|
|
||||||
throw re;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -291,14 +289,15 @@ public final class JavascriptCompiler {
|
||||||
boolean parens = ctx.LP() != null && ctx.RP() != null;
|
boolean parens = ctx.LP() != null && ctx.RP() != null;
|
||||||
Method method = parens ? functions.get(text) : null;
|
Method method = parens ? functions.get(text) : null;
|
||||||
|
|
||||||
|
try {
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
int arity = method.getParameterTypes().length;
|
int arity = method.getParameterTypes().length;
|
||||||
|
|
||||||
if (arguments != arity) {
|
if (arguments != arity) {
|
||||||
throwChecked(new ParseException(
|
throw new ParseException(
|
||||||
"Invalid expression '" + sourceText + "': Expected (" +
|
"Invalid expression '" + sourceText + "': Expected (" +
|
||||||
arity + ") arguments for function call (" + text + "), but found (" + arguments + ").",
|
arity + ") arguments for function call (" + text + "), but found (" + arguments + ").",
|
||||||
ctx.start.getStartIndex()));
|
ctx.start.getStartIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
typeStack.push(Type.DOUBLE_TYPE);
|
typeStack.push(Type.DOUBLE_TYPE);
|
||||||
|
@ -331,11 +330,15 @@ public final class JavascriptCompiler {
|
||||||
gen.invokeVirtual(FUNCTION_VALUES_TYPE, DOUBLE_VAL_METHOD);
|
gen.invokeVirtual(FUNCTION_VALUES_TYPE, DOUBLE_VAL_METHOD);
|
||||||
gen.cast(Type.DOUBLE_TYPE, typeStack.peek());
|
gen.cast(Type.DOUBLE_TYPE, typeStack.peek());
|
||||||
} else {
|
} else {
|
||||||
throwChecked(new ParseException("Invalid expression '" + sourceText + "': Unrecognized function call (" +
|
throw new ParseException("Invalid expression '" + sourceText + "': Unrecognized function call (" +
|
||||||
text + ").", ctx.start.getStartIndex()));
|
text + ").", ctx.start.getStartIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
} catch (ParseException e) {
|
||||||
|
// The API doesn't allow checked exceptions here, so propagate up the stack. This is unwrapped
|
||||||
|
// in getAntlrParseTree.
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -623,16 +626,6 @@ public final class JavascriptCompiler {
|
||||||
throw new IllegalStateException("Invalid expected type: " + typeStack.peek());
|
throw new IllegalStateException("Invalid expected type: " + typeStack.peek());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Needed to throw checked ParseException in this visitor (that does not allow it). */
|
|
||||||
private void throwChecked(Throwable t) {
|
|
||||||
this.<Error>throwChecked0(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private <T extends Throwable> void throwChecked0(Throwable t) throws T {
|
|
||||||
throw (T) t;
|
|
||||||
}
|
|
||||||
}.visit(parseTree);
|
}.visit(parseTree);
|
||||||
|
|
||||||
gen.returnValue();
|
gen.returnValue();
|
||||||
|
|
Loading…
Reference in New Issue