aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/share/classes/java/lang/Class.java25
-rw-r--r--src/share/classes/java/lang/invoke/MethodType.java2
-rw-r--r--src/share/classes/java/security/Signature.java28
-rw-r--r--src/share/classes/java/security/cert/CertificateRevokedException.java10
-rw-r--r--src/share/classes/java/util/logging/Logger.java11
-rw-r--r--src/share/classes/javax/crypto/CipherInputStream.java20
-rw-r--r--src/share/classes/sun/awt/image/BytePackedRaster.java8
-rw-r--r--src/share/classes/sun/invoke/util/VerifyAccess.java16
-rw-r--r--src/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java113
-rw-r--r--src/share/classes/sun/security/ssl/ClientHandshaker.java193
-rw-r--r--src/share/classes/sun/security/ssl/Handshaker.java13
-rw-r--r--src/share/classes/sun/security/ssl/SSLSessionImpl.java26
-rw-r--r--src/share/classes/sun/util/locale/BaseLocale.java88
-rw-r--r--src/share/classes/sun/util/locale/LocaleObjectCache.java4
-rw-r--r--src/share/javavm/export/jvm.h15
-rw-r--r--src/share/native/java/lang/Class.c7
-rw-r--r--src/share/native/sun/font/layout/ContextualSubstSubtables.cpp52
17 files changed, 528 insertions, 103 deletions
diff --git a/src/share/classes/java/lang/Class.java b/src/share/classes/java/lang/Class.java
index ea47cca2f..d400a6ac5 100644
--- a/src/share/classes/java/lang/Class.java
+++ b/src/share/classes/java/lang/Class.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -256,8 +256,8 @@ public final class Class<T> implements java.io.Serializable,
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
- return forName0(className, true,
- ClassLoader.getClassLoader(Reflection.getCallerClass()));
+ Class<?> caller = Reflection.getCallerClass();
+ return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
@@ -327,22 +327,27 @@ public final class Class<T> implements java.io.Serializable,
ClassLoader loader)
throws ClassNotFoundException
{
- if (sun.misc.VM.isSystemDomainLoader(loader)) {
- SecurityManager sm = System.getSecurityManager();
- if (sm != null) {
- ClassLoader ccl = ClassLoader.getClassLoader(Reflection.getCallerClass());
+ Class<?> caller = null;
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ // Reflective call to get caller class is only needed if a security manager
+ // is present. Avoid the overhead of making this call otherwise.
+ caller = Reflection.getCallerClass();
+ if (sun.misc.VM.isSystemDomainLoader(loader)) {
+ ClassLoader ccl = ClassLoader.getClassLoader(caller);
if (!sun.misc.VM.isSystemDomainLoader(ccl)) {
sm.checkPermission(
SecurityConstants.GET_CLASSLOADER_PERMISSION);
}
}
}
- return forName0(name, initialize, loader);
+ return forName0(name, initialize, loader, caller);
}
- /** Called after security checks have been made. */
+ /** Called after security check for system loader access checks have been made. */
private static native Class<?> forName0(String name, boolean initialize,
- ClassLoader loader)
+ ClassLoader loader,
+ Class<?> caller)
throws ClassNotFoundException;
/**
diff --git a/src/share/classes/java/lang/invoke/MethodType.java b/src/share/classes/java/lang/invoke/MethodType.java
index c26460048..08c17d789 100644
--- a/src/share/classes/java/lang/invoke/MethodType.java
+++ b/src/share/classes/java/lang/invoke/MethodType.java
@@ -653,7 +653,7 @@ class MethodType implements java.io.Serializable {
* @return the parameter types (as an immutable list)
*/
public List<Class<?>> parameterList() {
- return Collections.unmodifiableList(Arrays.asList(ptypes));
+ return Collections.unmodifiableList(Arrays.asList(ptypes.clone()));
}
/*non-public*/ Class<?> lastParameterType() {
diff --git a/src/share/classes/java/security/Signature.java b/src/share/classes/java/security/Signature.java
index 7c5bd96eb..939428412 100644
--- a/src/share/classes/java/security/Signature.java
+++ b/src/share/classes/java/security/Signature.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -590,6 +590,9 @@ public abstract class Signature extends SignatureSpi {
if (outbuf == null) {
throw new IllegalArgumentException("No output buffer given");
}
+ if (offset < 0 || len < 0) {
+ throw new IllegalArgumentException("offset or len is less than 0");
+ }
if (outbuf.length - offset < len) {
throw new IllegalArgumentException
("Output buffer too small for specified offset and length");
@@ -658,9 +661,16 @@ public abstract class Signature extends SignatureSpi {
public final boolean verify(byte[] signature, int offset, int length)
throws SignatureException {
if (state == VERIFY) {
- if ((signature == null) || (offset < 0) || (length < 0) ||
- (length > signature.length - offset)) {
- throw new IllegalArgumentException("Bad arguments");
+ if (signature == null) {
+ throw new IllegalArgumentException("signature is null");
+ }
+ if (offset < 0 || length < 0) {
+ throw new IllegalArgumentException
+ ("offset or length is less than 0");
+ }
+ if (signature.length - offset < length) {
+ throw new IllegalArgumentException
+ ("signature too small for specified offset and length");
}
return engineVerify(signature, offset, length);
@@ -713,6 +723,16 @@ public abstract class Signature extends SignatureSpi {
public final void update(byte[] data, int off, int len)
throws SignatureException {
if (state == SIGN || state == VERIFY) {
+ if (data == null) {
+ throw new IllegalArgumentException("data is null");
+ }
+ if (off < 0 || len < 0) {
+ throw new IllegalArgumentException("off or len is less than 0");
+ }
+ if (data.length - off < len) {
+ throw new IllegalArgumentException
+ ("data too small for specified offset and length");
+ }
engineUpdate(data, off, len);
} else {
throw new SignatureException("object not initialized for "
diff --git a/src/share/classes/java/security/cert/CertificateRevokedException.java b/src/share/classes/java/security/cert/CertificateRevokedException.java
index a54562706..505a007f5 100644
--- a/src/share/classes/java/security/cert/CertificateRevokedException.java
+++ b/src/share/classes/java/security/cert/CertificateRevokedException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -94,7 +94,10 @@ public class CertificateRevokedException extends CertificateException {
this.revocationDate = new Date(revocationDate.getTime());
this.reason = reason;
this.authority = authority;
- this.extensions = new HashMap<String, Extension>(extensions);
+ // make sure Map only contains correct types
+ this.extensions = Collections.checkedMap(new HashMap<>(),
+ String.class, Extension.class);
+ this.extensions.putAll(extensions);
}
/**
@@ -172,7 +175,8 @@ public class CertificateRevokedException extends CertificateException {
public String getMessage() {
return "Certificate has been revoked, reason: "
+ reason + ", revocation date: " + revocationDate
- + ", authority: " + authority + ", extensions: " + extensions;
+ + ", authority: " + authority + ", extension OIDs: "
+ + extensions.keySet();
}
/**
diff --git a/src/share/classes/java/util/logging/Logger.java b/src/share/classes/java/util/logging/Logger.java
index 90cbb87e1..4629320c1 100644
--- a/src/share/classes/java/util/logging/Logger.java
+++ b/src/share/classes/java/util/logging/Logger.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1934,6 +1934,9 @@ public class Logger {
}
setCallersClassLoaderRef(callersClass);
+ if (isSystemLogger && getCallersClassLoader() != null) {
+ checkPermission();
+ }
if (findResourceBundle(name, true) == null) {
// We've failed to find an expected ResourceBundle.
// unset the caller's ClassLoader since we were unable to find the
@@ -2168,11 +2171,13 @@ public class Logger {
return trb;
}
final String rbName = isSystemLogger
- ? trb.resourceBundleName
+ // ancestor of a system logger is expected to be a system logger.
+ // ignore resource bundle name if it's not.
+ ? (target.isSystemLogger ? trb.resourceBundleName : null)
: target.getResourceBundleName();
if (rbName != null) {
return LoggerBundle.get(rbName,
- findResourceBundle(rbName, true));
+ findResourceBundle(rbName, true));
}
target = isSystemLogger ? target.parent : target.getParent();
}
diff --git a/src/share/classes/javax/crypto/CipherInputStream.java b/src/share/classes/javax/crypto/CipherInputStream.java
index 0e80a6013..d777ca003 100644
--- a/src/share/classes/javax/crypto/CipherInputStream.java
+++ b/src/share/classes/javax/crypto/CipherInputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -88,6 +88,8 @@ public class CipherInputStream extends FilterInputStream {
private int ofinish = 0;
// stream status
private boolean closed = false;
+ // The stream has been read from. False if the stream has never been read.
+ private boolean read = false;
/**
* private convenience function.
@@ -103,13 +105,15 @@ public class CipherInputStream extends FilterInputStream {
private int getMoreData() throws IOException {
if (done) return -1;
int readin = input.read(ibuffer);
+ read = true;
if (readin == -1) {
done = true;
try {
obuffer = cipher.doFinal();
+ } catch (IllegalBlockSizeException | BadPaddingException e) {
+ obuffer = null;
+ throw new IOException(e);
}
- catch (IllegalBlockSizeException e) {obuffer = null;}
- catch (BadPaddingException e) {obuffer = null;}
if (obuffer == null)
return -1;
else {
@@ -120,7 +124,10 @@ public class CipherInputStream extends FilterInputStream {
}
try {
obuffer = cipher.update(ibuffer, 0, readin);
- } catch (IllegalStateException e) {obuffer = null;};
+ } catch (IllegalStateException e) {
+ obuffer = null;
+ throw e;
+ }
ostart = 0;
if (obuffer == null)
ofinish = 0;
@@ -308,6 +315,11 @@ public class CipherInputStream extends FilterInputStream {
}
}
catch (BadPaddingException | IllegalBlockSizeException ex) {
+ /* If no data has been read from the stream to be en/decrypted,
+ we supress any exceptions, and close quietly. */
+ if (read) {
+ throw new IOException(ex);
+ }
}
ostart = 0;
ofinish = 0;
diff --git a/src/share/classes/sun/awt/image/BytePackedRaster.java b/src/share/classes/sun/awt/image/BytePackedRaster.java
index bd3835d51..3e60f193a 100644
--- a/src/share/classes/sun/awt/image/BytePackedRaster.java
+++ b/src/share/classes/sun/awt/image/BytePackedRaster.java
@@ -1408,10 +1408,10 @@ public class BytePackedRaster extends SunWritableRaster {
}
}
- int lastbit = (dataBitOffset
- + (height-1) * scanlineStride * 8
- + (width-1) * pixelBitStride
- + pixelBitStride - 1);
+ long lastbit = (long) dataBitOffset
+ + (long) (height - 1) * (long) scanlineStride * 8
+ + (long) (width - 1) * (long) pixelBitStride
+ + (long) pixelBitStride - 1;
if (lastbit < 0 || lastbit / 8 >= data.length) {
throw new RasterFormatException("raster dimensions overflow " +
"array bounds");
diff --git a/src/share/classes/sun/invoke/util/VerifyAccess.java b/src/share/classes/sun/invoke/util/VerifyAccess.java
index a95aefbaf..fc870fc94 100644
--- a/src/share/classes/sun/invoke/util/VerifyAccess.java
+++ b/src/share/classes/sun/invoke/util/VerifyAccess.java
@@ -102,19 +102,24 @@ public class VerifyAccess {
case PUBLIC:
return true; // already checked above
case PROTECTED:
+ assert !defc.isInterface(); // protected members aren't allowed in interfaces
if ((allowedModes & PROTECTED_OR_PACKAGE_ALLOWED) != 0 &&
isSamePackage(defc, lookupClass))
return true;
if ((allowedModes & PROTECTED) == 0)
return false;
+ // Protected members are accessible by subclasses, which does not include interfaces.
+ // Interfaces are types, not classes. They should not have access to
+ // protected members in j.l.Object, even though it is their superclass.
if ((mods & STATIC) != 0 &&
!isRelatedClass(refc, lookupClass))
return false;
if ((allowedModes & PROTECTED) != 0 &&
- isSuperClass(defc, lookupClass))
+ isSubClass(lookupClass, defc))
return true;
return false;
case PACKAGE_ONLY: // That is, zero. Unmarked member is package-only access.
+ assert !defc.isInterface(); // package-private members aren't allowed in interfaces
return ((allowedModes & PACKAGE_ALLOWED) != 0 &&
isSamePackage(defc, lookupClass));
case PRIVATE:
@@ -129,12 +134,13 @@ public class VerifyAccess {
static boolean isRelatedClass(Class<?> refc, Class<?> lookupClass) {
return (refc == lookupClass ||
- refc.isAssignableFrom(lookupClass) ||
- lookupClass.isAssignableFrom(refc));
+ isSubClass(refc, lookupClass) ||
+ isSubClass(lookupClass, refc));
}
- static boolean isSuperClass(Class<?> defc, Class<?> lookupClass) {
- return defc.isAssignableFrom(lookupClass);
+ static boolean isSubClass(Class<?> lookupClass, Class<?> defc) {
+ return defc.isAssignableFrom(lookupClass) &&
+ !lookupClass.isInterface(); // interfaces are types, not classes.
}
static int getClassModifiers(Class<?> c) {
diff --git a/src/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java b/src/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java
index 6e73de70d..120fe7aac 100644
--- a/src/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java
+++ b/src/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,6 @@ import java.lang.annotation.*;
import java.lang.reflect.*;
import java.io.Serializable;
import java.util.*;
-import java.lang.annotation.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
@@ -45,6 +44,11 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable {
private final Map<String, Object> memberValues;
AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) {
+ Class<?>[] superInterfaces = type.getInterfaces();
+ if (!type.isAnnotation() ||
+ superInterfaces.length != 1 ||
+ superInterfaces[0] != java.lang.annotation.Annotation.class)
+ throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type.");
this.type = type;
this.memberValues = memberValues;
}
@@ -57,13 +61,17 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable {
if (member.equals("equals") && paramTypes.length == 1 &&
paramTypes[0] == Object.class)
return equalsImpl(args[0]);
- assert paramTypes.length == 0;
- if (member.equals("toString"))
+ if (paramTypes.length != 0)
+ throw new AssertionError("Too many parameters for an annotation method");
+
+ switch(member) {
+ case "toString":
return toStringImpl();
- if (member.equals("hashCode"))
+ case "hashCode":
return hashCodeImpl();
- if (member.equals("annotationType"))
+ case "annotationType":
return type;
+ }
// Handle annotation member accessors
Object result = memberValues.get(member);
@@ -129,7 +137,7 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable {
* Implementation of dynamicProxy.toString()
*/
private String toStringImpl() {
- StringBuffer result = new StringBuffer(128);
+ StringBuilder result = new StringBuilder(128);
result.append('@');
result.append(type.getName());
result.append('(');
@@ -277,6 +285,7 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable {
new PrivilegedAction<Method[]>() {
public Method[] run() {
final Method[] mm = type.getDeclaredMethods();
+ validateAnnotationMethods(mm);
AccessibleObject.setAccessible(mm, true);
return mm;
}
@@ -287,6 +296,94 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable {
private transient volatile Method[] memberMethods = null;
/**
+ * Validates that a method is structurally appropriate for an
+ * annotation type. As of Java SE 8, annotation types cannot
+ * contain static methods and the declared methods of an
+ * annotation type must take zero arguments and there are
+ * restrictions on the return type.
+ */
+ private void validateAnnotationMethods(Method[] memberMethods) {
+ /*
+ * Specification citations below are from JLS
+ * 9.6.1. Annotation Type Elements
+ */
+ boolean valid = true;
+ for(Method method : memberMethods) {
+ /*
+ * "By virtue of the AnnotationTypeElementDeclaration
+ * production, a method declaration in an annotation type
+ * declaration cannot have formal parameters, type
+ * parameters, or a throws clause.
+ *
+ * "By virtue of the AnnotationTypeElementModifier
+ * production, a method declaration in an annotation type
+ * declaration cannot be default or static."
+ */
+ if (method.getModifiers() != (Modifier.PUBLIC | Modifier.ABSTRACT) ||
+ method.isDefault() ||
+ method.getParameterCount() != 0 ||
+ method.getExceptionTypes().length != 0) {
+ valid = false;
+ break;
+ }
+
+ /*
+ * "It is a compile-time error if the return type of a
+ * method declared in an annotation type is not one of the
+ * following: a primitive type, String, Class, any
+ * parameterized invocation of Class, an enum type
+ * (section 8.9), an annotation type, or an array type
+ * (chapter 10) whose element type is one of the preceding
+ * types."
+ */
+ Class<?> returnType = method.getReturnType();
+ if (returnType.isArray()) {
+ returnType = returnType.getComponentType();
+ if (returnType.isArray()) { // Only single dimensional arrays
+ valid = false;
+ break;
+ }
+ }
+
+ if (!((returnType.isPrimitive() && returnType != void.class) ||
+ returnType == java.lang.String.class ||
+ returnType == java.lang.Class.class ||
+ returnType.isEnum() ||
+ returnType.isAnnotation())) {
+ valid = false;
+ break;
+ }
+
+ /*
+ * "It is a compile-time error if any method declared in an
+ * annotation type has a signature that is
+ * override-equivalent to that of any public or protected
+ * method declared in class Object or in the interface
+ * java.lang.annotation.Annotation."
+ *
+ * The methods in Object or Annotation meeting the other
+ * criteria (no arguments, contrained return type, etc.)
+ * above are:
+ *
+ * String toString()
+ * int hashCode()
+ * Class<? extends Annotation> annotationType()
+ */
+ String methodName = method.getName();
+ if ((methodName.equals("toString") && returnType == java.lang.String.class) ||
+ (methodName.equals("hashCode") && returnType == int.class) ||
+ (methodName.equals("annotationType") && returnType == java.lang.Class.class)) {
+ valid = false;
+ break;
+ }
+ }
+ if (valid)
+ return;
+ else
+ throw new AnnotationFormatError("Malformed method on an annotation type");
+ }
+
+ /**
* Implementation of dynamicProxy.hashCode()
*/
private int hashCodeImpl() {
@@ -330,7 +427,6 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable {
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
-
// Check to make sure that types have not evolved incompatibly
AnnotationType annotationType = null;
@@ -343,7 +439,6 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable {
Map<String, Class<?>> memberTypes = annotationType.memberTypes();
-
// If there are annotation members without values, that
// situation is handled by the invoke method.
for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
diff --git a/src/share/classes/sun/security/ssl/ClientHandshaker.java b/src/share/classes/sun/security/ssl/ClientHandshaker.java
index 5c3abbcda..5108528f2 100644
--- a/src/share/classes/sun/security/ssl/ClientHandshaker.java
+++ b/src/share/classes/sun/security/ssl/ClientHandshaker.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,6 +36,8 @@ import java.security.spec.ECParameterSpec;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
+import java.security.cert.CertificateParsingException;
+import javax.security.auth.x500.X500Principal;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
@@ -89,12 +91,66 @@ final class ClientHandshaker extends Handshaker {
private final static boolean enableSNIExtension =
Debug.getBooleanProperty("jsse.enableSNIExtension", true);
+ /*
+ * Allow unsafe server certificate change?
+ *
+ * Server certificate change during SSL/TLS renegotiation may be considered
+ * unsafe, as described in the Triple Handshake attacks:
+ *
+ * https://secure-resumption.com/tlsauth.pdf
+ *
+ * Endpoint identification (See
+ * SSLParameters.getEndpointIdentificationAlgorithm()) is a pretty nice
+ * guarantee that the server certificate change in renegotiation is legal.
+ * However, endpoing identification is only enabled for HTTPS and LDAP
+ * over SSL/TLS by default. It is not enough to protect SSL/TLS
+ * connections other than HTTPS and LDAP.
+ *
+ * The renegotiation indication extension (See RFC 5764) is a pretty
+ * strong guarantee that the endpoints on both client and server sides
+ * are identical on the same connection. However, the Triple Handshake
+ * attacks can bypass this guarantee if there is a session-resumption
+ * handshake between the initial full handshake and the renegotiation
+ * full handshake.
+ *
+ * Server certificate change may be unsafe and should be restricted if
+ * endpoint identification is not enabled and the previous handshake is
+ * a session-resumption abbreviated initial handshake, unless the
+ * identities represented by both certificates can be regraded as the
+ * same (See isIdentityEquivalent()).
+ *
+ * Considering the compatibility impact and the actual requirements to
+ * support server certificate change in practice, the system property,
+ * jdk.tls.allowUnsafeServerCertChange, is used to define whether unsafe
+ * server certificate change in renegotiation is allowed or not. The
+ * default value of the system property is "false". To mitigate the
+ * compactibility impact, applications may want to set the system
+ * property to "true" at their own risk.
+ *
+ * If the value of the system property is "false", server certificate
+ * change in renegotiation after a session-resumption abbreviated initial
+ * handshake is restricted (See isIdentityEquivalent()).
+ *
+ * If the system property is set to "true" explicitly, the restriction on
+ * server certificate change in renegotiation is disabled.
+ */
+ private final static boolean allowUnsafeServerCertChange =
+ Debug.getBooleanProperty("jdk.tls.allowUnsafeServerCertChange", false);
+
private List<SNIServerName> requestedServerNames =
Collections.<SNIServerName>emptyList();
private boolean serverNamesAccepted = false;
/*
+ * the reserved server certificate chain in previous handshaking
+ *
+ * The server certificate chain is only reserved if the previous
+ * handshake is a session-resumption abbreviated initial handshake.
+ */
+ private X509Certificate[] reservedServerCerts = null;
+
+ /*
* Constructors
*/
ClientHandshaker(SSLSocketImpl socket, SSLContextImpl context,
@@ -555,14 +611,19 @@ final class ClientHandshaker extends Handshaker {
// we wanted to resume, but the server refused
session = null;
if (!enableNewSession) {
- throw new SSLException
- ("New session creation is disabled");
+ throw new SSLException("New session creation is disabled");
}
}
}
if (resumingSession && session != null) {
setHandshakeSessionSE(session);
+ // Reserve the handshake state if this is a session-resumption
+ // abbreviated initial handshake.
+ if (isInitialHandshake) {
+ session.setAsSessionResumption(true);
+ }
+
return;
}
@@ -1064,6 +1125,13 @@ final class ClientHandshaker extends Handshaker {
}
/*
+ * Reset the handshake state if this is not an initial handshake.
+ */
+ if (!isInitialHandshake) {
+ session.setAsSessionResumption(false);
+ }
+
+ /*
* OK, it verified. If we're doing the fast handshake, add that
* "Finished" message to the hash of handshake messages, then send
* our own change_cipher_spec and Finished message for the server
@@ -1161,8 +1229,23 @@ final class ClientHandshaker extends Handshaker {
System.out.println("%% No cached client session");
}
}
- if ((session != null) && (session.isRejoinable() == false)) {
- session = null;
+ if (session != null) {
+ // If unsafe server certificate change is not allowed, reserve
+ // current server certificates if the previous handshake is a
+ // session-resumption abbreviated initial handshake.
+ if (!allowUnsafeServerCertChange && session.isSessionResumption()) {
+ try {
+ // If existing, peer certificate chain cannot be null.
+ reservedServerCerts =
+ (X509Certificate[])session.getPeerCertificates();
+ } catch (SSLPeerUnverifiedException puve) {
+ // Maybe not certificate-based, ignore the exception.
+ }
+ }
+
+ if (!session.isRejoinable()) {
+ session = null;
+ }
}
if (session != null) {
@@ -1331,9 +1414,28 @@ final class ClientHandshaker extends Handshaker {
}
X509Certificate[] peerCerts = mesg.getCertificateChain();
if (peerCerts.length == 0) {
- fatalSE(Alerts.alert_bad_certificate,
- "empty certificate chain");
+ fatalSE(Alerts.alert_bad_certificate, "empty certificate chain");
+ }
+
+ // Allow server certificate change in client side during renegotiation
+ // after a session-resumption abbreviated initial handshake?
+ //
+ // DO NOT need to check allowUnsafeServerCertChange here. We only
+ // reserve server certificates when allowUnsafeServerCertChange is
+ // flase.
+ if (reservedServerCerts != null) {
+ // It is not necessary to check the certificate update if endpoint
+ // identification is enabled.
+ String identityAlg = getEndpointIdentificationAlgorithmSE();
+ if ((identityAlg == null || identityAlg.length() == 0) &&
+ !isIdentityEquivalent(peerCerts[0], reservedServerCerts[0])) {
+
+ fatalSE(Alerts.alert_bad_certificate,
+ "server certificate change is restricted " +
+ "during renegotiation");
+ }
}
+
// ask the trust manager to verify the chain
X509TrustManager tm = sslContext.getX509TrustManager();
try {
@@ -1370,4 +1472,81 @@ final class ClientHandshaker extends Handshaker {
}
session.setPeerCertificates(peerCerts);
}
+
+ /*
+ * Whether the certificates can represent the same identity?
+ *
+ * The certificates can be used to represent the same identity:
+ * 1. If the subject alternative names of IP address are present in
+ * both certificates, they should be identical; otherwise,
+ * 2. if the subject alternative names of DNS name are present in
+ * both certificates, they should be identical; otherwise,
+ * 3. if the subject fields are present in both certificates, the
+ * certificate subjects and issuers should be identical.
+ */
+ private static boolean isIdentityEquivalent(X509Certificate thisCert,
+ X509Certificate prevCert) {
+ if (thisCert.equals(prevCert)) {
+ return true;
+ }
+
+ // check the iPAddress field in subjectAltName extension
+ Object thisIPAddress = getSubjectAltName(thisCert, 7); // 7: iPAddress
+ Object prevIPAddress = getSubjectAltName(prevCert, 7);
+ if (thisIPAddress != null && prevIPAddress!= null) {
+ // only allow the exactly match
+ return Objects.equals(thisIPAddress, prevIPAddress);
+ }
+
+ // check the dNSName field in subjectAltName extension
+ Object thisDNSName = getSubjectAltName(thisCert, 2); // 2: dNSName
+ Object prevDNSName = getSubjectAltName(prevCert, 2);
+ if (thisDNSName != null && prevDNSName!= null) {
+ // only allow the exactly match
+ return Objects.equals(thisDNSName, prevDNSName);
+ }
+
+ // check the certificate subject and issuer
+ X500Principal thisSubject = thisCert.getSubjectX500Principal();
+ X500Principal prevSubject = prevCert.getSubjectX500Principal();
+ X500Principal thisIssuer = thisCert.getIssuerX500Principal();
+ X500Principal prevIssuer = prevCert.getIssuerX500Principal();
+ if (!thisSubject.getName().isEmpty() &&
+ !prevSubject.getName().isEmpty() &&
+ thisSubject.equals(prevSubject) &&
+ thisIssuer.equals(prevIssuer)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /*
+ * Returns the subject alternative name of the specified type in the
+ * subjectAltNames extension of a certificate.
+ */
+ private static Object getSubjectAltName(X509Certificate cert, int type) {
+ Collection<List<?>> subjectAltNames;
+
+ try {
+ subjectAltNames = cert.getSubjectAlternativeNames();
+ } catch (CertificateParsingException cpe) {
+ if (debug != null && Debug.isOn("handshake")) {
+ System.out.println(
+ "Attempt to obtain subjectAltNames extension failed!");
+ }
+ return null;
+ }
+
+ if (subjectAltNames != null) {
+ for (List<?> subjectAltName : subjectAltNames) {
+ int subjectAltNameType = (Integer)subjectAltName.get(0);
+ if (subjectAltNameType == type) {
+ return subjectAltName.get(1);
+ }
+ }
+ }
+
+ return null;
+ }
}
diff --git a/src/share/classes/sun/security/ssl/Handshaker.java b/src/share/classes/sun/security/ssl/Handshaker.java
index 9fea3fada..ba65d966a 100644
--- a/src/share/classes/sun/security/ssl/Handshaker.java
+++ b/src/share/classes/sun/security/ssl/Handshaker.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -359,6 +359,17 @@ abstract class Handshaker {
}
}
+ String getEndpointIdentificationAlgorithmSE() {
+ SSLParameters paras;
+ if (conn != null) {
+ paras = conn.getSSLParameters();
+ } else {
+ paras = engine.getSSLParameters();
+ }
+
+ return paras.getEndpointIdentificationAlgorithm();
+ }
+
private void setVersionSE(ProtocolVersion protocolVersion) {
if (conn != null) {
conn.setVersion(protocolVersion);
diff --git a/src/share/classes/sun/security/ssl/SSLSessionImpl.java b/src/share/classes/sun/security/ssl/SSLSessionImpl.java
index 6cb4170d3..b5f304b6b 100644
--- a/src/share/classes/sun/security/ssl/SSLSessionImpl.java
+++ b/src/share/classes/sun/security/ssl/SSLSessionImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -115,6 +115,14 @@ final class SSLSessionImpl extends ExtendedSSLSession {
private Principal localPrincipal;
/*
+ * Is the session currently re-established with a session-resumption
+ * abbreviated initial handshake?
+ *
+ * Note that currently we only set this variable in client side.
+ */
+ private boolean isSessionResumption = false;
+
+ /*
* We count session creations, eventually for statistical data but
* also since counters make shorter debugging IDs than the big ones
* we use in the protocol for uniqueness-over-time.
@@ -325,6 +333,22 @@ final class SSLSessionImpl extends ExtendedSSLSession {
}
/**
+ * Return true if the session is currently re-established with a
+ * session-resumption abbreviated initial handshake.
+ */
+ boolean isSessionResumption() {
+ return isSessionResumption;
+ }
+
+ /**
+ * Resets whether the session is re-established with a session-resumption
+ * abbreviated initial handshake.
+ */
+ void setAsSessionResumption(boolean flag) {
+ isSessionResumption = flag;
+ }
+
+ /**
* Returns the name of the cipher suite in use on this session
*/
@Override
diff --git a/src/share/classes/sun/util/locale/BaseLocale.java b/src/share/classes/sun/util/locale/BaseLocale.java
index 6eee58290..e0e9ed060 100644
--- a/src/share/classes/sun/util/locale/BaseLocale.java
+++ b/src/share/classes/sun/util/locale/BaseLocale.java
@@ -31,6 +31,7 @@
*/
package sun.util.locale;
+import java.lang.ref.SoftReference;
public final class BaseLocale {
@@ -163,11 +164,11 @@ public final class BaseLocale {
return h;
}
- private static final class Key implements Comparable<Key> {
- private final String lang;
- private final String scrt;
- private final String regn;
- private final String vart;
+ private static final class Key {
+ private final SoftReference<String> lang;
+ private final SoftReference<String> scrt;
+ private final SoftReference<String> regn;
+ private final SoftReference<String> vart;
private final boolean normalized;
private final int hash;
@@ -179,10 +180,10 @@ public final class BaseLocale {
assert language.intern() == language
&& region.intern() == region;
- lang = language;
- scrt = "";
- regn = region;
- vart = "";
+ lang = new SoftReference(language);
+ scrt = new SoftReference("");
+ regn = new SoftReference(region);
+ vart = new SoftReference("");
this.normalized = true;
int h = language.hashCode();
@@ -203,40 +204,40 @@ public final class BaseLocale {
String variant, boolean normalized) {
int h = 0;
if (language != null) {
- lang = language;
+ lang = new SoftReference(language);
int len = language.length();
for (int i = 0; i < len; i++) {
h = 31*h + LocaleUtils.toLower(language.charAt(i));
}
} else {
- lang = "";
+ lang = new SoftReference("");
}
if (script != null) {
- scrt = script;
+ scrt = new SoftReference(script);
int len = script.length();
for (int i = 0; i < len; i++) {
h = 31*h + LocaleUtils.toLower(script.charAt(i));
}
} else {
- scrt = "";
+ scrt = new SoftReference("");
}
if (region != null) {
- regn = region;
+ regn = new SoftReference(region);
int len = region.length();
for (int i = 0; i < len; i++) {
h = 31*h + LocaleUtils.toLower(region.charAt(i));
}
} else {
- regn = "";
+ regn = new SoftReference("");
}
if (variant != null) {
- vart = variant;
+ vart = new SoftReference(variant);
int len = variant.length();
for (int i = 0; i < len; i++) {
h = 31*h + variant.charAt(i);
}
} else {
- vart = "";
+ vart = new SoftReference("");
}
hash = h;
this.normalized = normalized;
@@ -244,28 +245,31 @@ public final class BaseLocale {
@Override
public boolean equals(Object obj) {
- return (this == obj) ||
- (obj instanceof Key)
- && this.hash == ((Key)obj).hash
- && LocaleUtils.caseIgnoreMatch(((Key)obj).lang, this.lang)
- && LocaleUtils.caseIgnoreMatch(((Key)obj).scrt, this.scrt)
- && LocaleUtils.caseIgnoreMatch(((Key)obj).regn, this.regn)
- && ((Key)obj).vart.equals(vart); // variant is case sensitive in JDK!
+ if (this == obj) {
+ return true;
}
- @Override
- public int compareTo(Key other) {
- int res = LocaleUtils.caseIgnoreCompare(this.lang, other.lang);
- if (res == 0) {
- res = LocaleUtils.caseIgnoreCompare(this.scrt, other.scrt);
- if (res == 0) {
- res = LocaleUtils.caseIgnoreCompare(this.regn, other.regn);
- if (res == 0) {
- res = this.vart.compareTo(other.vart);
+ if (obj instanceof Key && this.hash == ((Key)obj).hash) {
+ String tl = this.lang.get();
+ String ol = ((Key)obj).lang.get();
+ if (tl != null && ol != null &&
+ LocaleUtils.caseIgnoreMatch(ol, tl)) {
+ String ts = this.scrt.get();
+ String os = ((Key)obj).scrt.get();
+ if (ts != null && os != null &&
+ LocaleUtils.caseIgnoreMatch(os, ts)) {
+ String tr = this.regn.get();
+ String or = ((Key)obj).regn.get();
+ if (tr != null && or != null &&
+ LocaleUtils.caseIgnoreMatch(or, tr)) {
+ String tv = this.vart.get();
+ String ov = ((Key)obj).vart.get();
+ return (ov != null && ov.equals(tv));
}
}
}
- return res;
+ }
+ return false;
}
@Override
@@ -278,10 +282,10 @@ public final class BaseLocale {
return key;
}
- String lang = LocaleUtils.toLowerString(key.lang).intern();
- String scrt = LocaleUtils.toTitleString(key.scrt).intern();
- String regn = LocaleUtils.toUpperString(key.regn).intern();
- String vart = key.vart.intern(); // preserve upper/lower cases
+ String lang = LocaleUtils.toLowerString(key.lang.get()).intern();
+ String scrt = LocaleUtils.toTitleString(key.scrt.get()).intern();
+ String regn = LocaleUtils.toUpperString(key.regn.get()).intern();
+ String vart = key.vart.get().intern(); // preserve upper/lower cases
return new Key(lang, scrt, regn, vart, true);
}
@@ -294,12 +298,18 @@ public final class BaseLocale {
@Override
protected Key normalizeKey(Key key) {
+ assert key.lang.get() != null &&
+ key.scrt.get() != null &&
+ key.regn.get() != null &&
+ key.vart.get() != null;
+
return Key.normalize(key);
}
@Override
protected BaseLocale createObject(Key key) {
- return new BaseLocale(key.lang, key.scrt, key.regn, key.vart);
+ return new BaseLocale(key.lang.get(), key.scrt.get(),
+ key.regn.get(), key.vart.get());
}
}
}
diff --git a/src/share/classes/sun/util/locale/LocaleObjectCache.java b/src/share/classes/sun/util/locale/LocaleObjectCache.java
index 88920aaf5..eae148088 100644
--- a/src/share/classes/sun/util/locale/LocaleObjectCache.java
+++ b/src/share/classes/sun/util/locale/LocaleObjectCache.java
@@ -57,8 +57,10 @@ public abstract class LocaleObjectCache<K, V> {
value = entry.get();
}
if (value == null) {
- key = normalizeKey(key);
V newVal = createObject(key);
+ // make sure key is normalized *after* the object creation
+ // so that newVal is assured to be created from a valid key.
+ key = normalizeKey(key);
if (key == null || newVal == null) {
// subclass must return non-null key/value object
return null;
diff --git a/src/share/javavm/export/jvm.h b/src/share/javavm/export/jvm.h
index ff5f823d8..9426a16d4 100644
--- a/src/share/javavm/export/jvm.h
+++ b/src/share/javavm/export/jvm.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -386,6 +386,19 @@ JNIEXPORT jclass JNICALL
JVM_FindClassFromBootLoader(JNIEnv *env, const char *name);
/*
+ * Find a class from a given class loader. Throws ClassNotFoundException.
+ * name: name of class
+ * init: whether initialization is done
+ * loader: class loader to look up the class. This may not be the same as the caller's
+ * class loader.
+ * caller: initiating class. The initiating class may be null when a security
+ * manager is not installed.
+ */
+JNIEXPORT jclass JNICALL
+JVM_FindClassFromCaller(JNIEnv *env, const char *name, jboolean init,
+ jobject loader, jclass caller);
+
+/*
* Find a class from a given class loader. Throw ClassNotFoundException
* or NoClassDefFoundError depending on the value of the last
* argument.
diff --git a/src/share/native/java/lang/Class.c b/src/share/native/java/lang/Class.c
index b0ba34349..2f5e6b5c8 100644
--- a/src/share/native/java/lang/Class.c
+++ b/src/share/native/java/lang/Class.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -97,7 +97,7 @@ Java_java_lang_Class_registerNatives(JNIEnv *env, jclass cls)
JNIEXPORT jclass JNICALL
Java_java_lang_Class_forName0(JNIEnv *env, jclass this, jstring classname,
- jboolean initialize, jobject loader)
+ jboolean initialize, jobject loader, jclass caller)
{
char *clname;
jclass cls = 0;
@@ -135,8 +135,7 @@ Java_java_lang_Class_forName0(JNIEnv *env, jclass this, jstring classname,
goto done;
}
- cls = JVM_FindClassFromClassLoader(env, clname, initialize,
- loader, JNI_FALSE);
+ cls = JVM_FindClassFromCaller(env, clname, initialize, loader, caller);
done:
if (clname != buf) {
diff --git a/src/share/native/sun/font/layout/ContextualSubstSubtables.cpp b/src/share/native/sun/font/layout/ContextualSubstSubtables.cpp
index 3707efdfb..e985b81cb 100644
--- a/src/share/native/sun/font/layout/ContextualSubstSubtables.cpp
+++ b/src/share/native/sun/font/layout/ContextualSubstSubtables.cpp
@@ -243,12 +243,22 @@ le_uint32 ContextualSubstitutionFormat1Subtable::process(const LETableReference
le_uint16 srSetCount = SWAPW(subRuleSetCount);
if (coverageIndex < srSetCount) {
+ LEReferenceToArrayOf<Offset> subRuleSetTableOffsetArrayRef(base, success,
+ &subRuleSetTableOffsetArray[coverageIndex], 1);
+ if (LE_FAILURE(success)) {
+ return 0;
+ }
Offset subRuleSetTableOffset = SWAPW(subRuleSetTableOffsetArray[coverageIndex]);
LEReferenceTo<SubRuleSetTable>
subRuleSetTable(base, success, (const SubRuleSetTable *) ((char *) this + subRuleSetTableOffset));
le_uint16 subRuleCount = SWAPW(subRuleSetTable->subRuleCount);
le_int32 position = glyphIterator->getCurrStreamPosition();
+ LEReferenceToArrayOf<Offset> subRuleTableOffsetArrayRef(base, success,
+ subRuleSetTable->subRuleTableOffsetArray, subRuleCount);
+ if (LE_FAILURE(success)) {
+ return 0;
+ }
for (le_uint16 subRule = 0; subRule < subRuleCount; subRule += 1) {
Offset subRuleTableOffset =
SWAPW(subRuleSetTable->subRuleTableOffsetArray[subRule]);
@@ -301,13 +311,22 @@ le_uint32 ContextualSubstitutionFormat2Subtable::process(const LETableReference
glyphIterator->getCurrGlyphID(),
success);
- if (setClass < scSetCount && subClassSetTableOffsetArray[setClass] != 0) {
+ if (setClass < scSetCount) {
+ LEReferenceToArrayOf<Offset>
+ subClassSetTableOffsetArrayRef(base, success, subClassSetTableOffsetArray, setClass);
+ if (LE_FAILURE(success)) { return 0; }
+ if (subClassSetTableOffsetArray[setClass] != 0) {
+
Offset subClassSetTableOffset = SWAPW(subClassSetTableOffsetArray[setClass]);
LEReferenceTo<SubClassSetTable>
subClassSetTable(base, success, (const SubClassSetTable *) ((char *) this + subClassSetTableOffset));
le_uint16 subClassRuleCount = SWAPW(subClassSetTable->subClassRuleCount);
le_int32 position = glyphIterator->getCurrStreamPosition();
-
+ LEReferenceToArrayOf<Offset>
+ subClassRuleTableOffsetArrayRef(base, success, subClassSetTable->subClassRuleTableOffsetArray, subClassRuleCount);
+ if (LE_FAILURE(success)) {
+ return 0;
+ }
for (le_uint16 scRule = 0; scRule < subClassRuleCount; scRule += 1) {
Offset subClassRuleTableOffset =
SWAPW(subClassSetTable->subClassRuleTableOffsetArray[scRule]);
@@ -331,6 +350,7 @@ le_uint32 ContextualSubstitutionFormat2Subtable::process(const LETableReference
glyphIterator->setCurrStreamPosition(position);
}
}
+ }
// XXX If we get here, the table is mal-formed...
}
@@ -442,13 +462,22 @@ le_uint32 ChainingContextualSubstitutionFormat1Subtable::process(const LETableRe
le_uint16 srSetCount = SWAPW(chainSubRuleSetCount);
if (coverageIndex < srSetCount) {
+ LEReferenceToArrayOf<Offset>
+ chainSubRuleSetTableOffsetArrayRef(base, success, chainSubRuleSetTableOffsetArray, coverageIndex);
+ if (LE_FAILURE(success)) {
+ return 0;
+ }
Offset chainSubRuleSetTableOffset = SWAPW(chainSubRuleSetTableOffsetArray[coverageIndex]);
LEReferenceTo<ChainSubRuleSetTable>
chainSubRuleSetTable(base, success, (const ChainSubRuleSetTable *) ((char *) this + chainSubRuleSetTableOffset));
le_uint16 chainSubRuleCount = SWAPW(chainSubRuleSetTable->chainSubRuleCount);
le_int32 position = glyphIterator->getCurrStreamPosition();
GlyphIterator tempIterator(*glyphIterator, emptyFeatureList);
-
+ LEReferenceToArrayOf<Offset>
+ chainSubRuleTableOffsetArrayRef(base, success, chainSubRuleSetTable->chainSubRuleTableOffsetArray, chainSubRuleCount);
+ if (LE_FAILURE(success)) {
+ return 0;
+ }
for (le_uint16 subRule = 0; subRule < chainSubRuleCount; subRule += 1) {
Offset chainSubRuleTableOffset =
SWAPW(chainSubRuleSetTable->chainSubRuleTableOffsetArray[subRule]);
@@ -530,6 +559,11 @@ le_uint32 ChainingContextualSubstitutionFormat2Subtable::process(const LETableRe
le_int32 setClass = inputClassDefinitionTable->getGlyphClass(inputClassDefinitionTable,
glyphIterator->getCurrGlyphID(),
success);
+ LEReferenceToArrayOf<Offset>
+ chainSubClassSetTableOffsetArrayRef(base, success, chainSubClassSetTableOffsetArray, setClass);
+ if (LE_FAILURE(success)) {
+ return 0;
+ }
if (setClass < scSetCount && chainSubClassSetTableOffsetArray[setClass] != 0) {
Offset chainSubClassSetTableOffset = SWAPW(chainSubClassSetTableOffsetArray[setClass]);
@@ -538,7 +572,11 @@ le_uint32 ChainingContextualSubstitutionFormat2Subtable::process(const LETableRe
le_uint16 chainSubClassRuleCount = SWAPW(chainSubClassSetTable->chainSubClassRuleCount);
le_int32 position = glyphIterator->getCurrStreamPosition();
GlyphIterator tempIterator(*glyphIterator, emptyFeatureList);
-
+ LEReferenceToArrayOf<Offset>
+ chainSubClassRuleTableOffsetArrayRef(base, success, chainSubClassSetTable->chainSubClassRuleTableOffsetArray, chainSubClassRuleCount);
+ if (LE_FAILURE(success)) {
+ return 0;
+ }
for (le_uint16 scRule = 0; scRule < chainSubClassRuleCount; scRule += 1) {
Offset chainSubClassRuleTableOffset =
SWAPW(chainSubClassSetTable->chainSubClassRuleTableOffsetArray[scRule]);
@@ -603,12 +641,14 @@ le_uint32 ChainingContextualSubstitutionFormat3Subtable::process(const LETableRe
}
le_uint16 backtrkGlyphCount = SWAPW(backtrackGlyphCount);
+ LEReferenceToArrayOf<Offset> backtrackGlyphArrayRef(base, success, backtrackCoverageTableOffsetArray, backtrkGlyphCount);
+ if (LE_FAILURE(success)) {
+ return 0;
+ }
le_uint16 inputGlyphCount = (le_uint16) SWAPW(backtrackCoverageTableOffsetArray[backtrkGlyphCount]);
LEReferenceToArrayOf<Offset> inputCoverageTableOffsetArray(base, success, &backtrackCoverageTableOffsetArray[backtrkGlyphCount + 1], inputGlyphCount+2); // offset
if (LE_FAILURE(success)) { return 0; }
const le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputCoverageTableOffsetArray[inputGlyphCount]);
-
- if( LE_FAILURE(success)) { return 0; }
LEReferenceToArrayOf<Offset> lookaheadCoverageTableOffsetArray(base, success, inputCoverageTableOffsetArray.getAlias(inputGlyphCount + 1, success), lookaheadGlyphCount+2);
if( LE_FAILURE(success) ) { return 0; }