How do I releasing resources for fileinputstream and fileoutstream? - java

In my veracode scan, I have very low vulnerability: Improper Resource Shutdown or Release CWE ID 404
And here is my code:
public static boolean nioCopy(File source, File destination) {
boolean retval = false;
FileChannel inChannel = null, outChannel = null;
try {
inChannel = (new FileInputStream(source)).getChannel();
outChannel = (new FileOutputStream(destination)).getChannel();
long size = inChannel.size();
long position = 0;
while ( position < size )
{
position += inChannel.transferTo( position, WINDOWS_MAGIC_BUFFER_SIZE, outChannel );
}
retval = true;
} catch (FileNotFoundException e) {
e.printStackTrace();
retval = false;
} catch (IOException e) {
e.printStackTrace();
retval = false;
} finally {
try {
if (inChannel != null) {
inChannel.close();
}
if (outChannel != null) {
outChannel.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return retval;
}
Veracode is specifically pointing to this line:
outChannel = (new FileOutputStream(destination)).getChannel();
However, I believe I am releasing the resource in finally block. I was referring to this link: http://javaelegance.blogspot.com/2015/10/improper-resource-shutdown-or-release.html
What am I doing wrong here?

Assuming Java 8 or higher, use try with resources statements. See https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html. It basically will handle automatically closing closable objects for you.
try (inChannel = (new FileInputStream(source)).getChannel()) {
//Use inChannel
}
catch(IOException ex) {
//Handle exception
}

Related

Java InputStream with different Object Classes

my code has to read in two different Object Types (Bestellung, AKunde) through a ObjectOutputStream and save it in a csv file, which works.
But when i try to read them from the file it doesn't work.
Here is the code:
OutputStream:
LinkedList<Bestellung> bestellListe = verwaltungBestell.getBestellListe();
try {
fileOutputStream = new FileOutputStream(file);
outputStream = new ObjectOutputStream(fileOutputStream);
for (AKunde kunde : kundenliste) {
outputStream.writeObject(kunde);
}
for (Bestellung bestellung : bestellListe) {
outputStream.writeObject(bestellung);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fileOutputStream != null) {
fileOutputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
InputStream:
ArrayList<AKunde> kundenImport = new ArrayList<AKunde>();
ArrayList<Bestellung> bestellungenImport = new ArrayList<Bestellung>();
boolean cont = true;
try {
ObjectInputStream objectStream = new ObjectInputStream(new FileInputStream(directorie));
while (cont) {
AKunde kunde = null;
try {
kunde = (AKunde) objectStream.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
if (kunde != null) {
kundenImport.add(kunde);
} else {
cont = false;
}
}
while (cont) {
Bestellung bestellung = null;
try {
bestellung = (Bestellung) objectStream.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
if (bestellung != null) {
bestellungenImport.add(bestellung);
} else {
cont = false;
}
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
}
But it won't read the "Bestellungen" and won't save them into "bestellungenImport".
Anyone has a solution???
Your code never reaches the Bestellung reader part.
You have a false assumption that kunde =(AKunde)objectStream.readObject(); returns null.
Instead, it throws exception.
Oneway you can do is cast it like #luk2302.
Another way is to add a object count when writing your object stream:
outputStream.writeInt(kundenliste.size());
for (AKunde kunde : kundenliste) {
outputStream.writeObject(kunde);
}
outputStream.writeInt(bestellListe.size());
for (Bestellung bestellung : bestellListe) {
outputStream.writeObject(bestellung);
}
Then replace your while(cont) loop with a for each loop:
int kundeCount = objectStream.readInt();
for (int i = 0; i < kundeCount; i++) {
// Read and import kunde
}
You need to change your logic for reading objects. There are two main issues:
you never reset cont so the second while loop will never do anything
even if you did that you would always skip the first Bestellung since it was already read when the second loop is reached
I would propose something along the lines of:
Object object = objectStream.readObject();
if (object instanceof AKunde) {
kundenImport.add((AKunde) object);
} else if (object instanceof Bestellung) {
bestellungenImport.add((Bestellung) object);
} else {
// something else was read
}
You simply need to loop over this code and add proper error handling where needed.
I would suggest, you change the way you write your objects to ObjectOutputStream in the first place:
Directly write the kundenListe and bestellListe objects, so you dont't have to worry about types or number of elements when reading the objects again. Your stream of object then always contains two objects, the two lists.
// use try-with-resources if you're on Java 7 or newer
try (ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(file))) {
// write the complete list of objects
outputStream.writeObject(kundenliste);
outputStream.writeObject(bestellListe);
} catch (IOException e) {
e.printStackTrace(); //TODO proper exception handling
}
Then you could read it just like that:
ArrayList<AKunde> kundenImport = new ArrayList<>();
ArrayList<Bestellung> bestellungenImport = new ArrayList<>();
//again try-with-resources
try (ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(file))) {
kundenImport.addAll((List) inputStream.readObject());
bestellungenImport.addAll((List) inputStream.readObject());
} catch (IOException | ClassNotFoundException e) { //multi-catch, if Java 7 or newer
e.printStackTrace(); //TODO proper exception handling
}
Further reads:
The try-with-resources Statement
Catching Multiple Exception Types (...)

SSH connection leaving stale sessions on the server

I am programatically trying to connect to ssh running remotely. I am running a tomcat server instance. Whenever i need, from the code, i create a session, connect and execute a few commands that are needed within a try block and then close off the connection that was created as part of the finally block at all the places. Things work well and fine, but at some cases when i execute a w or netstat command on the ssh server, I see a few connections that are idle for more than a few hours and the ip address of those connections shows the connection to be from my application, but my java heap dump does not show any instance of my class in the memory, but i see ganymed related class instances in the heap.
I am using ganymed-ssh-260 library to connect to my server.
Is this something that someone has already seen?
Attaching the code snippet that connectes the ssh to the server
public class SSHExecutor{
private OutputStream stdin;
private InputStream stdout;
private InputStream stderr;
private Session sess;
private Connection conn;
public void createConnection(String hostname, int port, String userName, String password) throws Exception {
try {
conn = new Connection(hostname, port);
final boolean isAuthenticated = publicKeyAccess(hostname, userName, password);
if (!isAuthenticated) {
throw new IOException("Authentication failed.");
}
sess = conn.openSession();
final int xWidth = 90;
final int yWidth = 80;
sess.requestPTY("dumb", xWidth, yWidth, 0, 0, null);
sess.startShell();
stdin = sess.getStdin();
stdout = sess.getStdout();
stderr = sess.getStderr();
isConnectionActive = true;
final String response = getResponse();
if (response != null && response.toLowerCase().contains(ObjectConstants.CURRENTLY_NOT_AVAILABLE)) {
throw new IOException("Account is currently not available.");
}
} catch (Exception e) {
log.error("Problem in CreateConnection", e);
isConnectionActive = false;
throw e;
}
}
public String getResponse() {
final StringBuffer responseData = new StringBuffer();
try {
final int byteValue = 8192;
final byte[] buffer = new byte[byteValue];
try {
while (true) {
if ((stdout.available() == 0) && (stderr.available() == 0)) {
int conditions = 1;
if (promptString != null && promptString.length() > 0) {
final int fiveThousand = 5000;
conditions = sess.waitForCondition(ChannelCondition.STDOUT_DATA
| ChannelCondition.STDERR_DATA | ChannelCondition.EOF, fiveThousand);
} else {
conditions = sess.waitForCondition(ChannelCondition.STDOUT_DATA
| ChannelCondition.STDERR_DATA | ChannelCondition.EOF,
ObjectConstants.THOUSAND_FIVE_HUNDRED);
}
if ((conditions & ChannelCondition.TIMEOUT) != 0) {
break;
}
if ((conditions & ChannelCondition.EOF) != 0) {
if ((conditions & (ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA)) == 0) {
break;
}
}
}
while (stdout.available() > 0) {
final int len = stdout.read(buffer);
if (len > 0) {
responseData.append(new String(buffer, 0, len));
}
}
while (stderr.available() > 0) {
final int len = stderr.read(buffer);
if (len > 0) {
responseData.append(new String(buffer, 0, len));
}
}
if (promptString != null && promptString.length() > 0) {
if (responseData.indexOf(promptString) != -1) {
break;
}
}
}
} catch (Exception e) {
log.error("Read Error :", e);
}
} catch (Exception e) {
log.error("getResponse Error ", e);
}
return responseData.toString();
}
public String executeCommand(String command) throws IOException {
String response = null;
if (isConnectionActive && stdin != null) {
try {
stdin.write(command.getBytes());
stdin.flush();
response = getResponse();
} catch (IOException ie) {
throw ie;
} catch (Exception e) {
log.error("Exception in executeCommandForPage()", e);
response = e.getMessage();
}
} else {
response = "Connection not active.";
}
return response;
}
public void closeConnection() {
if (stderr != null) {
try {
stderr.close();
} catch (Exception e) {
log.error("Exception in closeConnection()", e);
}
}
if (stdout != null) {
try {
stdout.close();
} catch (Exception e) {
log.error("Exception in closeConnection()", e);
}
}
if (stdin != null) {
try {
stdin.close();
} catch (Exception e) {
log.error("Exception in closeConnection()", e);
}
}
if (sess != null) {
try {
sess.close();
} catch (Exception e) {
log.error("Exception in closeConnection()", e);
}
}
if (conn != null) {
try {
conn.close();
} catch (Exception e) {
log.error("Exception in closeConnection()", e);
}
}
}
}
You're creating a local Connection variable but you're testing what must be a member variable, which is always null, so you're never closing it.
If authentication fails you're leaking the connection.

Hadoop YARN Map Task running out of physical and virtual memory

I have the following method that I run from my map task in a multithreaded execution , however this works fine in a standalone mod e, but when I runt this in Hadoop YARN it runs out of the physical memory of 1GB and the virtual memory also shoots up.
I need to know if I am doing anything wrong from a programming perspective, I think I am closing all the streams that I am opening ASAP , so I see no reason for a memory leak to happen . Please advise.
Thanks.
public static void manageTheCurrentURL(String url) {
logger.trace("Entering the method manageTheCurrentURL ");
InputStream stream = null;
InputStream is = null;
ByteArrayOutputStream out = null;
WebDriver driver = null;
try {
if (StringUtils.isNotBlank(url)) {
caps.setJavascriptEnabled(true); // not really needed: JS
// enabled by default
caps.setCapability(
PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY,
"/usr/local/bin/phantomjs");
// Launch driver (will take care and ownership of the phantomjs
// process)
driver = new PhantomJSDriver(caps);
driver.get(url);
String htmlContent = driver.getPageSource();
if (htmlContent != null) {
is = new ByteArrayInputStream(htmlContent.getBytes());
ByteArrayDocumentSource byteArrayDocumentSource = new ByteArrayDocumentSource(
is, url, "text/html");
Any23 runner = new Any23();
runner.setHTTPUserAgent("test-user-agent");
out = new ByteArrayOutputStream();
TripleHandler handler = new NTriplesWriter(out);
try {
runner.extract(byteArrayDocumentSource, handler);
} catch (ExtractionException e) {
} finally {
if (driver != null) {
driver.quit();
//driver.close();
}
try {
handler.close();
} catch (TripleHandlerException e) {
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
}
}
}
if (out != null) {
stream = new ByteArrayInputStream(out.toByteArray());
Iterator<Node[]> it = new DeltaParser(stream);
if (it != null) {
SolrCallbackForNXParser callback = new SolrCallbackForNXParser(
url);
callback.startStory();
while (it.hasNext()) {
Node[] abc = it.next();
callback.processStory(abc);
}
callback.endStory();
}
}
}
}
} catch (IOException e) {
return;
}
finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
}
}
}
logger.trace("Exiting the method manageTheCurrentURL ");
}

Eclipse Juno : unassigned closeable value

I am wondering why I get this warning with the new eclipse Juno despite I think I correctly closed everything. Could you please tell me why I get this warning in the following piece of code?
public static boolean copyFile(String fileSource, String fileDestination)
{
try
{
// Create channel on the source (the line below generates a warning unassigned closeable value)
FileChannel srcChannel = new FileInputStream(fileSource).getChannel();
// Create channel on the destination (the line below generates a warning unassigned closeable value)
FileChannel dstChannel = new FileOutputStream(fileDestination).getChannel();
// Copy file contents from source to destination
dstChannel.transferFrom(srcChannel, 0, srcChannel.size());
// Close the channels
srcChannel.close();
dstChannel.close();
return true;
}
catch (IOException e)
{
return false;
}
}
IF you're running on Java 7, you can use the new try-with-resources blocks like so, and your streams will be automatically closed:
public static boolean copyFile(String fileSource, String fileDestination)
{
try(
FileInputStream srcStream = new FileInputStream(fileSource);
FileOutputStream dstStream = new FileOutputStream(fileDestination) )
{
dstStream.getChannel().transferFrom(srcStream.getChannel(), 0, srcStream.getChannel().size());
return true;
}
catch (IOException e)
{
return false;
}
}
You won't need to explicitly close the underlying channels. However if you're not using Java 7, you should write the code in a cumbersome old way, with finally blocks:
public static boolean copyFile(String fileSource, String fileDestination)
{
FileInputStream srcStream=null;
FileOutputStream dstStream=null;
try {
srcStream = new FileInputStream(fileSource);
dstStream = new FileOutputStream(fileDestination)
dstStream.getChannel().transferFrom(srcStream.getChannel(), 0, srcStream.getChannel().size());
return true;
}
catch (IOException e)
{
return false;
} finally {
try { srcStream.close(); } catch (Exception e) {}
try { dstStream.close(); } catch (Exception e) {}
}
}
See how much better the Java 7 version is :)
You should always close in finally because if an exception rise, you won't close the resources.
FileChannel srcChannel = null
try {
srcChannel = xxx;
} finally {
if (srcChannel != null) {
srcChannel.close();
}
}
Note: even if you put a return in the catch block, the finally block will be done.
eclipse is warning you about the FileInputStream and FileOutputStream that you can no longer reference.

"NegativeArraySizeException" - Custom Class Loader

I had a class loader working although I am now getting an error after adapting it to my new application. I believe it is because I am converting an integer to a long.
private byte[] loadClassData(String name) {
try {
JarInputStream jis = new JarInputStream(new ByteArrayInputStream(dec));
JarEntry entry = null;
String entryName = null;
while((entry = jis.getNextJarEntry()) != null)
{
entryName = entry.getName();
if(entryName.equalsIgnoreCase(name))
{
try{
classBytes = new byte[(int)entry.getSize()];
jis.read(classBytes, 0, classBytes.length);
return classBytes;
}catch(Exception ex){
ex.printStackTrace();
return null;
}
}
}
return classBytes;
} catch (IOException e) {
e.printStackTrace();
System.out.println(e.getMessage());
} catch (Exception ex) {
ex.printStackTrace();
System.out.println(ex.getMessage());
}
return null;
}
Anyways, that is the basics of it. I am getting an error on the " new byte[(int)entry.getSize()];" part.
"java.lang.NegativeArraySizeException"
Thanks.
Yes, because ZipEntry.getSize() can return -1. Even if it didn't return -1, you shouldn't assume that a single call to read will read all the data. You should read in a loop until the input stream returns -1.
I suggest you use ByteStreams.toByteArray(InputStream) from Guava for this.

Categories

Resources