下面这段代码的作用是压缩,会用到ZipOutputStream
ZipOutputStream zipOutputStream = null;
try {
zipOutputStream = new ZipOutputStream(new FileOutputStream(zipPath));
} catch (FileNotFoundException e) {
throw new IllegalArgumentException("zipPath error " + "", e);
} finally {
if (null != zipOutputStream) {
try {
zipOutputStream.close();
} catch (IOException e) {
logger.error("", e);
}
}
}
错误放大版1:
ZipOutputStream zipOutputStream = null;
try {
FileOutputStream fileOutputStream = new FileOutputStream(zipPath);
throw new RuntimeException();
zipOutputStream = new ZipOutputStream(fileOutputStream);
} catch (FileNotFoundException e) {
throw new IllegalArgumentException("zipPath error " + "", e);
} finally {
if (null != zipOutputStream) {
try {
zipOutputStream.close();
} catch (IOException e) {
logger.error("", e);
}
}
}
错误放大版2:
ZipOutputStream zipOutputStream = null;
try {
zipOutputStream = new ZipOutputStream(new FileOutputStream(zipPath),null);
} catch (FileNotFoundException e) {
throw new IllegalArgumentException("zipPath error " + "", e);
} finally {
if (null != zipOutputStream) {
try {
zipOutputStream.close();
} catch (IOException e) {
logger.error("", e);
}
}
}
这里我有一个疑问,在new FileOutputStream(zipPath)的过程中如果已经打开了这个文件,但是在new ZipOutputStream过程中出错了,这个时候zipOutputStream并没有创建成功,所以在finally中不会调用close方法,造成的结果就是这个文件不会被关闭。
所以这种关闭方式是不是会有漏洞,还是我的理由有问题?
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号
这个例子有漏洞,不过漏洞不在这里,而是
FileOutputStream。如果
new ZipOutputStream()调用失败,这个构造方法会抛出运行时异常,而且不会关闭传递进来的FileOutputStream对象。由于调用者也不持有该对象的引用,也无法释放资源,会造成打开的文件描述符没有关闭。
如果使用java8的话可以用
try with,或者在finally块里面释放FileOutputStream对象持有的资源,这样是比较保险的做法。在这个过程中只会发生
FileNotFoundException异常,而此时ZipOutputStream对象还没有创建,没有任何流被打开,所以当然是不需要关闭的。所以这段代码没有问题输出:
结论:
发生
OutOfMemeoryError时,finally可以执行,但是catch和main方法后面的打印语句都没有执行,虚拟机直接奔溃了。我之前说发生内存溢出时finally不会执行是不对的,事实表明finally是会执行的,特此更正。
@brayden

解决方法很简单你直接close掉传递的FileOutputStream即可。
这个漏洞是存在的,可以从代码层面解决,这种装饰器模式虽然很好,但是对被装饰的对象管理不当就会出现这种情况。