HADOOP-15331. Fix a race condition causing parsing error of java.io.BufferedInputStream in class org.apache.hadoop.conf.Configuration. Contributed by Miklos Szegedi.

This commit is contained in:
Yufei Gu 2018-03-22 11:04:37 -07:00
parent dae5051828
commit 268c29a5f5
2 changed files with 35 additions and 1 deletions

View File

@ -816,8 +816,11 @@ public Configuration(boolean loadDefaults) {
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Configuration(Configuration other) { public Configuration(Configuration other) {
this.resources = (ArrayList<Resource>) other.resources.clone();
synchronized(other) { synchronized(other) {
// Make sure we clone a finalized state
// Resources like input streams can be processed only once
other.getProps();
this.resources = (ArrayList<Resource>) other.resources.clone();
if (other.properties != null) { if (other.properties != null) {
this.properties = (Properties)other.properties.clone(); this.properties = (Properties)other.properties.clone();
} }

View File

@ -17,6 +17,7 @@
*/ */
package org.apache.hadoop.conf; package org.apache.hadoop.conf;
import java.io.BufferedInputStream;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -2419,4 +2420,34 @@ public void testInvalidTags() throws Exception {
System.setOut(output); System.setOut(output);
} }
} }
/**
* Test race conditions between clone() and getProps().
* Test for race conditions in the way Hadoop handles the Configuration
* class. The scenario is the following. Let's assume that there are two
* threads sharing the same Configuration class. One adds some resources
* to the configuration, while the other one clones it. Resources are
* loaded lazily in a deferred call to loadResources(). If the cloning
* happens after adding the resources but before parsing them, some temporary
* resources like input stream pointers are cloned. Eventually both copies
* will load the same input stream resources.
* One parses the input stream XML and closes it updating it's own copy of
* the resource. The other one has another pointer to the same input stream.
* When it tries to load it, it will crash with a stream closed exception.
*/
@Test
public void testResourceRace() {
InputStream is =
new BufferedInputStream(new ByteArrayInputStream(
"<configuration></configuration>".getBytes()));
Configuration config = new Configuration();
// Thread 1
config.addResource(is);
// Thread 2
Configuration confClone = new Configuration(conf);
// Thread 2
confClone.get("firstParse");
// Thread 1
config.get("secondParse");
}
} }