提交 4695a8ae 编写于 作者: D dfuchs

6823527: java.util.logging.Handler has thread safety issues

Reviewed-by: dholmes, mchung
上级 eb24bc67
...@@ -26,9 +26,6 @@ ...@@ -26,9 +26,6 @@
package java.util.logging; package java.util.logging;
import java.io.*;
import java.net.*;
/** /**
* This <tt>Handler</tt> publishes log records to <tt>System.err</tt>. * This <tt>Handler</tt> publishes log records to <tt>System.err</tt>.
* By default the <tt>SimpleFormatter</tt> is used to generate brief summaries. * By default the <tt>SimpleFormatter</tt> is used to generate brief summaries.
...@@ -114,6 +111,7 @@ public class ConsoleHandler extends StreamHandler { ...@@ -114,6 +111,7 @@ public class ConsoleHandler extends StreamHandler {
* @param record description of the log event. A null record is * @param record description of the log event. A null record is
* silently ignored and is not published * silently ignored and is not published
*/ */
@Override
public void publish(LogRecord record) { public void publish(LogRecord record) {
super.publish(record); super.publish(record);
flush(); flush();
...@@ -124,6 +122,7 @@ public class ConsoleHandler extends StreamHandler { ...@@ -124,6 +122,7 @@ public class ConsoleHandler extends StreamHandler {
* to close the output stream. That is, we do <b>not</b> * to close the output stream. That is, we do <b>not</b>
* close <tt>System.err</tt>. * close <tt>System.err</tt>.
*/ */
@Override
public void close() { public void close() {
flush(); flush();
} }
......
...@@ -149,7 +149,7 @@ public class FileHandler extends StreamHandler { ...@@ -149,7 +149,7 @@ public class FileHandler extends StreamHandler {
private FileChannel lockFileChannel; private FileChannel lockFileChannel;
private File files[]; private File files[];
private static final int MAX_LOCKS = 100; private static final int MAX_LOCKS = 100;
private static java.util.HashMap<String, String> locks = new java.util.HashMap<>(); private static final java.util.HashMap<String, String> locks = new java.util.HashMap<>();
/** /**
* A metered stream is a subclass of OutputStream that * A metered stream is a subclass of OutputStream that
...@@ -157,7 +157,7 @@ public class FileHandler extends StreamHandler { ...@@ -157,7 +157,7 @@ public class FileHandler extends StreamHandler {
* (b) keeps track of how many bytes have been written * (b) keeps track of how many bytes have been written
*/ */
private class MeteredStream extends OutputStream { private class MeteredStream extends OutputStream {
OutputStream out; final OutputStream out;
int written; int written;
MeteredStream(OutputStream out, int written) { MeteredStream(OutputStream out, int written) {
...@@ -165,25 +165,30 @@ public class FileHandler extends StreamHandler { ...@@ -165,25 +165,30 @@ public class FileHandler extends StreamHandler {
this.written = written; this.written = written;
} }
@Override
public void write(int b) throws IOException { public void write(int b) throws IOException {
out.write(b); out.write(b);
written++; written++;
} }
@Override
public void write(byte buff[]) throws IOException { public void write(byte buff[]) throws IOException {
out.write(buff); out.write(buff);
written += buff.length; written += buff.length;
} }
@Override
public void write(byte buff[], int off, int len) throws IOException { public void write(byte buff[], int off, int len) throws IOException {
out.write(buff,off,len); out.write(buff,off,len);
written += len; written += len;
} }
@Override
public void flush() throws IOException { public void flush() throws IOException {
out.flush(); out.flush();
} }
@Override
public void close() throws IOException { public void close() throws IOException {
out.close(); out.close();
} }
...@@ -607,6 +612,7 @@ public class FileHandler extends StreamHandler { ...@@ -607,6 +612,7 @@ public class FileHandler extends StreamHandler {
* @param record description of the log event. A null record is * @param record description of the log event. A null record is
* silently ignored and is not published * silently ignored and is not published
*/ */
@Override
public synchronized void publish(LogRecord record) { public synchronized void publish(LogRecord record) {
if (!isLoggable(record)) { if (!isLoggable(record)) {
return; return;
...@@ -620,6 +626,7 @@ public class FileHandler extends StreamHandler { ...@@ -620,6 +626,7 @@ public class FileHandler extends StreamHandler {
// currently being called from untrusted code. // currently being called from untrusted code.
// So it is safe to raise privilege here. // So it is safe to raise privilege here.
AccessController.doPrivileged(new PrivilegedAction<Object>() { AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() { public Object run() {
rotate(); rotate();
return null; return null;
...@@ -634,6 +641,7 @@ public class FileHandler extends StreamHandler { ...@@ -634,6 +641,7 @@ public class FileHandler extends StreamHandler {
* @exception SecurityException if a security manager exists and if * @exception SecurityException if a security manager exists and if
* the caller does not have <tt>LoggingPermission("control")</tt>. * the caller does not have <tt>LoggingPermission("control")</tt>.
*/ */
@Override
public synchronized void close() throws SecurityException { public synchronized void close() throws SecurityException {
super.close(); super.close();
// Unlock any lock file. // Unlock any lock file.
...@@ -656,6 +664,7 @@ public class FileHandler extends StreamHandler { ...@@ -656,6 +664,7 @@ public class FileHandler extends StreamHandler {
private static class InitializationErrorManager extends ErrorManager { private static class InitializationErrorManager extends ErrorManager {
Exception lastException; Exception lastException;
@Override
public void error(String msg, Exception ex, int code) { public void error(String msg, Exception ex, int code) {
lastException = ex; lastException = ex;
} }
......
...@@ -47,12 +47,20 @@ import java.io.UnsupportedEncodingException; ...@@ -47,12 +47,20 @@ import java.io.UnsupportedEncodingException;
public abstract class Handler { public abstract class Handler {
private static final int offValue = Level.OFF.intValue(); private static final int offValue = Level.OFF.intValue();
private LogManager manager = LogManager.getLogManager(); private final LogManager manager = LogManager.getLogManager();
private Filter filter;
private Formatter formatter; // We're using volatile here to avoid synchronizing getters, which
private Level logLevel = Level.ALL; // would prevent other threads from calling isLoggable()
private ErrorManager errorManager = new ErrorManager(); // while publish() is executing.
private String encoding; // On the other hand, setters will be synchronized to exclude concurrent
// execution with more complex methods, such as StreamHandler.publish().
// We wouldn't want 'level' to be changed by another thread in the middle
// of the execution of a 'publish' call.
private volatile Filter filter;
private volatile Formatter formatter;
private volatile Level logLevel = Level.ALL;
private volatile ErrorManager errorManager = new ErrorManager();
private volatile String encoding;
// Package private support for security checking. When sealed // Package private support for security checking. When sealed
// is true, we access check updates to the class. // is true, we access check updates to the class.
...@@ -110,7 +118,7 @@ public abstract class Handler { ...@@ -110,7 +118,7 @@ public abstract class Handler {
* @exception SecurityException if a security manager exists and if * @exception SecurityException if a security manager exists and if
* the caller does not have <tt>LoggingPermission("control")</tt>. * the caller does not have <tt>LoggingPermission("control")</tt>.
*/ */
public void setFormatter(Formatter newFormatter) throws SecurityException { public synchronized void setFormatter(Formatter newFormatter) throws SecurityException {
checkPermission(); checkPermission();
// Check for a null pointer: // Check for a null pointer:
newFormatter.getClass(); newFormatter.getClass();
...@@ -138,7 +146,7 @@ public abstract class Handler { ...@@ -138,7 +146,7 @@ public abstract class Handler {
* @exception UnsupportedEncodingException if the named encoding is * @exception UnsupportedEncodingException if the named encoding is
* not supported. * not supported.
*/ */
public void setEncoding(String encoding) public synchronized void setEncoding(String encoding)
throws SecurityException, java.io.UnsupportedEncodingException { throws SecurityException, java.io.UnsupportedEncodingException {
checkPermission(); checkPermission();
if (encoding != null) { if (encoding != null) {
...@@ -174,7 +182,7 @@ public abstract class Handler { ...@@ -174,7 +182,7 @@ public abstract class Handler {
* @exception SecurityException if a security manager exists and if * @exception SecurityException if a security manager exists and if
* the caller does not have <tt>LoggingPermission("control")</tt>. * the caller does not have <tt>LoggingPermission("control")</tt>.
*/ */
public void setFilter(Filter newFilter) throws SecurityException { public synchronized void setFilter(Filter newFilter) throws SecurityException {
checkPermission(); checkPermission();
filter = newFilter; filter = newFilter;
} }
...@@ -198,7 +206,7 @@ public abstract class Handler { ...@@ -198,7 +206,7 @@ public abstract class Handler {
* @exception SecurityException if a security manager exists and if * @exception SecurityException if a security manager exists and if
* the caller does not have <tt>LoggingPermission("control")</tt>. * the caller does not have <tt>LoggingPermission("control")</tt>.
*/ */
public void setErrorManager(ErrorManager em) { public synchronized void setErrorManager(ErrorManager em) {
checkPermission(); checkPermission();
if (em == null) { if (em == null) {
throw new NullPointerException(); throw new NullPointerException();
...@@ -264,7 +272,7 @@ public abstract class Handler { ...@@ -264,7 +272,7 @@ public abstract class Handler {
* than this level will be discarded. * than this level will be discarded.
* @return the level of messages being logged. * @return the level of messages being logged.
*/ */
public synchronized Level getLevel() { public Level getLevel() {
return logLevel; return logLevel;
} }
...@@ -282,11 +290,11 @@ public abstract class Handler { ...@@ -282,11 +290,11 @@ public abstract class Handler {
* *
*/ */
public boolean isLoggable(LogRecord record) { public boolean isLoggable(LogRecord record) {
int levelValue = getLevel().intValue(); final int levelValue = getLevel().intValue();
if (record.getLevel().intValue() < levelValue || levelValue == offValue) { if (record.getLevel().intValue() < levelValue || levelValue == offValue) {
return false; return false;
} }
Filter filter = getFilter(); final Filter filter = getFilter();
if (filter == null) { if (filter == null) {
return true; return true;
} }
......
...@@ -88,7 +88,7 @@ package java.util.logging; ...@@ -88,7 +88,7 @@ package java.util.logging;
public class MemoryHandler extends Handler { public class MemoryHandler extends Handler {
private final static int DEFAULT_SIZE = 1000; private final static int DEFAULT_SIZE = 1000;
private Level pushLevel; private volatile Level pushLevel;
private int size; private int size;
private Handler target; private Handler target;
private LogRecord buffer[]; private LogRecord buffer[];
...@@ -188,6 +188,7 @@ public class MemoryHandler extends Handler { ...@@ -188,6 +188,7 @@ public class MemoryHandler extends Handler {
* @param record description of the log event. A null record is * @param record description of the log event. A null record is
* silently ignored and is not published * silently ignored and is not published
*/ */
@Override
public synchronized void publish(LogRecord record) { public synchronized void publish(LogRecord record) {
if (!isLoggable(record)) { if (!isLoggable(record)) {
return; return;
...@@ -227,6 +228,7 @@ public class MemoryHandler extends Handler { ...@@ -227,6 +228,7 @@ public class MemoryHandler extends Handler {
* Note that the current contents of the <tt>MemoryHandler</tt> * Note that the current contents of the <tt>MemoryHandler</tt>
* buffer are <b>not</b> written out. That requires a "push". * buffer are <b>not</b> written out. That requires a "push".
*/ */
@Override
public void flush() { public void flush() {
target.flush(); target.flush();
} }
...@@ -238,6 +240,7 @@ public class MemoryHandler extends Handler { ...@@ -238,6 +240,7 @@ public class MemoryHandler extends Handler {
* @exception SecurityException if a security manager exists and if * @exception SecurityException if a security manager exists and if
* the caller does not have <tt>LoggingPermission("control")</tt>. * the caller does not have <tt>LoggingPermission("control")</tt>.
*/ */
@Override
public void close() throws SecurityException { public void close() throws SecurityException {
target.close(); target.close();
setLevel(Level.OFF); setLevel(Level.OFF);
...@@ -252,11 +255,10 @@ public class MemoryHandler extends Handler { ...@@ -252,11 +255,10 @@ public class MemoryHandler extends Handler {
* @exception SecurityException if a security manager exists and if * @exception SecurityException if a security manager exists and if
* the caller does not have <tt>LoggingPermission("control")</tt>. * the caller does not have <tt>LoggingPermission("control")</tt>.
*/ */
public void setPushLevel(Level newLevel) throws SecurityException { public synchronized void setPushLevel(Level newLevel) throws SecurityException {
if (newLevel == null) { if (newLevel == null) {
throw new NullPointerException(); throw new NullPointerException();
} }
LogManager manager = LogManager.getLogManager();
checkPermission(); checkPermission();
pushLevel = newLevel; pushLevel = newLevel;
} }
...@@ -266,7 +268,7 @@ public class MemoryHandler extends Handler { ...@@ -266,7 +268,7 @@ public class MemoryHandler extends Handler {
* *
* @return the value of the <tt>pushLevel</tt> * @return the value of the <tt>pushLevel</tt>
*/ */
public synchronized Level getPushLevel() { public Level getPushLevel() {
return pushLevel; return pushLevel;
} }
...@@ -283,6 +285,7 @@ public class MemoryHandler extends Handler { ...@@ -283,6 +285,7 @@ public class MemoryHandler extends Handler {
* @return true if the <tt>LogRecord</tt> would be logged. * @return true if the <tt>LogRecord</tt> would be logged.
* *
*/ */
@Override
public boolean isLoggable(LogRecord record) { public boolean isLoggable(LogRecord record) {
return super.isLoggable(record); return super.isLoggable(record);
} }
......
...@@ -82,7 +82,6 @@ public class SocketHandler extends StreamHandler { ...@@ -82,7 +82,6 @@ public class SocketHandler extends StreamHandler {
private Socket sock; private Socket sock;
private String host; private String host;
private int port; private int port;
private String portProperty;
// Private method to configure a SocketHandler from LogManager // Private method to configure a SocketHandler from LogManager
// properties and/or default values as specified in the class // properties and/or default values as specified in the class
...@@ -177,6 +176,7 @@ public class SocketHandler extends StreamHandler { ...@@ -177,6 +176,7 @@ public class SocketHandler extends StreamHandler {
* @exception SecurityException if a security manager exists and if * @exception SecurityException if a security manager exists and if
* the caller does not have <tt>LoggingPermission("control")</tt>. * the caller does not have <tt>LoggingPermission("control")</tt>.
*/ */
@Override
public synchronized void close() throws SecurityException { public synchronized void close() throws SecurityException {
super.close(); super.close();
if (sock != null) { if (sock != null) {
...@@ -195,6 +195,7 @@ public class SocketHandler extends StreamHandler { ...@@ -195,6 +195,7 @@ public class SocketHandler extends StreamHandler {
* @param record description of the log event. A null record is * @param record description of the log event. A null record is
* silently ignored and is not published * silently ignored and is not published
*/ */
@Override
public synchronized void publish(LogRecord record) { public synchronized void publish(LogRecord record) {
if (!isLoggable(record)) { if (!isLoggable(record)) {
return; return;
......
...@@ -73,10 +73,9 @@ import java.io.*; ...@@ -73,10 +73,9 @@ import java.io.*;
*/ */
public class StreamHandler extends Handler { public class StreamHandler extends Handler {
private LogManager manager = LogManager.getLogManager();
private OutputStream output; private OutputStream output;
private boolean doneHeader; private boolean doneHeader;
private Writer writer; private volatile Writer writer;
// Private method to configure a StreamHandler from LogManager // Private method to configure a StreamHandler from LogManager
// properties and/or default values as specified in the class // properties and/or default values as specified in the class
...@@ -169,7 +168,8 @@ public class StreamHandler extends Handler { ...@@ -169,7 +168,8 @@ public class StreamHandler extends Handler {
* @exception UnsupportedEncodingException if the named encoding is * @exception UnsupportedEncodingException if the named encoding is
* not supported. * not supported.
*/ */
public void setEncoding(String encoding) @Override
public synchronized void setEncoding(String encoding)
throws SecurityException, java.io.UnsupportedEncodingException { throws SecurityException, java.io.UnsupportedEncodingException {
super.setEncoding(encoding); super.setEncoding(encoding);
if (output == null) { if (output == null) {
...@@ -201,6 +201,7 @@ public class StreamHandler extends Handler { ...@@ -201,6 +201,7 @@ public class StreamHandler extends Handler {
* @param record description of the log event. A null record is * @param record description of the log event. A null record is
* silently ignored and is not published * silently ignored and is not published
*/ */
@Override
public synchronized void publish(LogRecord record) { public synchronized void publish(LogRecord record) {
if (!isLoggable(record)) { if (!isLoggable(record)) {
return; return;
...@@ -240,6 +241,7 @@ public class StreamHandler extends Handler { ...@@ -240,6 +241,7 @@ public class StreamHandler extends Handler {
* @return true if the <tt>LogRecord</tt> would be logged. * @return true if the <tt>LogRecord</tt> would be logged.
* *
*/ */
@Override
public boolean isLoggable(LogRecord record) { public boolean isLoggable(LogRecord record) {
if (writer == null || record == null) { if (writer == null || record == null) {
return false; return false;
...@@ -250,6 +252,7 @@ public class StreamHandler extends Handler { ...@@ -250,6 +252,7 @@ public class StreamHandler extends Handler {
/** /**
* Flush any buffered messages. * Flush any buffered messages.
*/ */
@Override
public synchronized void flush() { public synchronized void flush() {
if (writer != null) { if (writer != null) {
try { try {
...@@ -294,6 +297,7 @@ public class StreamHandler extends Handler { ...@@ -294,6 +297,7 @@ public class StreamHandler extends Handler {
* @exception SecurityException if a security manager exists and if * @exception SecurityException if a security manager exists and if
* the caller does not have LoggingPermission("control"). * the caller does not have LoggingPermission("control").
*/ */
@Override
public synchronized void close() throws SecurityException { public synchronized void close() throws SecurityException {
flushAndClose(); flushAndClose();
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册