Skip to content

Commit 9dac9e3

Browse files
committed
Fix: cancel FileIO finalizer if init fails
1 parent 8498ef0 commit 9dac9e3

File tree

1 file changed

+83
-71
lines changed
  • graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io

1 file changed

+83
-71
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java

Lines changed: 83 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -321,89 +321,101 @@ public void doInit(VirtualFrame frame, PFileIO self, Object nameobj, IONodes.IOM
321321
int flags = processMode(self, mode);
322322
auditNode.audit(OPEN, nameobj, mode.mode, flags);
323323

324-
boolean fdIsOwn = false;
325-
PythonContext ctxt = PythonContext.get(this);
326-
if (fd >= 0) {
327-
self.setCloseFD(closefd);
328-
self.setFD(fd, ctxt);
329-
} else {
330-
self.setCloseFD(true);
331-
if (errorProfile.profile(!closefd)) {
332-
throw raise(ValueError, CANNOT_USE_CLOSEFD);
333-
}
334-
335-
if (opener instanceof PNone) {
336-
self.setFD(open(frame, name, flags, 0666, ctxt, posixLib, exceptionProfile), ctxt);
324+
try {
325+
boolean fdIsOwn = false;
326+
PythonContext ctxt = PythonContext.get(this);
327+
if (fd >= 0) {
328+
self.setCloseFD(closefd);
329+
self.setFD(fd, ctxt);
337330
} else {
338-
Object fdobj = callOpener.execute(frame, opener, nameobj, flags);
339-
if (!indexCheckNode.execute(fdobj)) {
340-
throw raise(TypeError, EXPECTED_INT_FROM_OPENER);
331+
self.setCloseFD(true);
332+
if (errorProfile.profile(!closefd)) {
333+
throw raise(ValueError, CANNOT_USE_CLOSEFD);
341334
}
342335

343-
self.setFD(asSizeNode.executeExact(frame, fdobj), ctxt);
344-
if (self.getFD() < 0) {
345-
/*
346-
* The opener returned a negative but didn't set an exception. See issue
347-
* #27066
348-
*/
349-
throw raise(ValueError, OPENER_RETURNED_D, self.getFD());
336+
if (opener instanceof PNone) {
337+
self.setFD(open(frame, name, flags, 0666, ctxt, posixLib, exceptionProfile), ctxt);
338+
} else {
339+
Object fdobj = callOpener.execute(frame, opener, nameobj, flags);
340+
if (!indexCheckNode.execute(fdobj)) {
341+
throw raise(TypeError, EXPECTED_INT_FROM_OPENER);
342+
}
343+
344+
self.setFD(asSizeNode.executeExact(frame, fdobj), ctxt);
345+
if (self.getFD() < 0) {
346+
/*
347+
* The opener returned a negative but didn't set an exception. See issue
348+
* #27066
349+
*/
350+
throw raise(ValueError, OPENER_RETURNED_D, self.getFD());
351+
}
350352
}
353+
try {
354+
posixLib.setInheritable(ctxt.getPosixSupport(), self.getFD(), false);
355+
} catch (PosixSupportLibrary.PosixException e) {
356+
exceptionProfile.enter();
357+
throw raiseOSErrorFromPosixException(frame, e);
358+
}
359+
fdIsOwn = true;
351360
}
361+
self.setBlksize(DEFAULT_BUFFER_SIZE);
352362
try {
353-
posixLib.setInheritable(ctxt.getPosixSupport(), self.getFD(), false);
354-
} catch (PosixSupportLibrary.PosixException e) {
355-
exceptionProfile.enter();
356-
throw raiseOSErrorFromPosixException(frame, e);
357-
}
358-
fdIsOwn = true;
359-
}
360-
self.setBlksize(DEFAULT_BUFFER_SIZE);
361-
try {
362-
long[] fstatResult = posixLib.fstat(ctxt.getPosixSupport(), self.getFD());
363-
/*
364-
* On Unix, open will succeed for directories. In Python, there should be no file
365-
* objects referring to directories, so we need a check.
366-
*/
367-
if (errorProfile.profile(PosixSupportLibrary.isDIR(fstatResult[0]))) {
368-
errorCleanup(frame, self, fdIsOwn, posixClose);
369-
name = name == null ? Integer.toString(fd) : name;
370-
throw raiseOSError(frame, OSErrorEnum.EISDIR, name);
371-
}
372-
/*
373-
* // TODO: read fstatResult.st_blksize if (fstatResult[8] > 1)
374-
* self.setBlksize(fstatResult[8]); }
375-
*/
376-
} catch (PosixSupportLibrary.PosixException e) {
377-
exceptionProfile.enter();
378-
/*
379-
* Tolerate fstat() errors other than EBADF. See Issue #25717, where an anonymous
380-
* file on a Virtual Box shared folder filesystem would raise ENOENT.
381-
*/
382-
if (e.getErrorCode() == OSErrorEnum.EBADF.getNumber()) {
383-
errorCleanup(frame, self, fdIsOwn, posixClose);
384-
throw raiseOSErrorFromPosixException(frame, e);
385-
}
386-
}
387-
setAttr.execute(frame, self, NAME, nameobj);
388-
389-
if (self.isAppending()) {
390-
/*
391-
* For consistent behaviour, we explicitly seek to the end of file (otherwise, it
392-
* might be done only on the first write()).
393-
*/
394-
try {
395-
long res = posixLib.lseek(ctxt.getPosixSupport(), self.getFD(), 0, mapPythonSeekWhenceToPosix(SEEK_END));
396-
self.setSeekable(res >= 0 ? 1 : 0);
363+
long[] fstatResult = posixLib.fstat(ctxt.getPosixSupport(), self.getFD());
364+
/*
365+
* On Unix, open will succeed for directories. In Python, there should be no
366+
* file objects referring to directories, so we need a check.
367+
*/
368+
if (errorProfile.profile(PosixSupportLibrary.isDIR(fstatResult[0]))) {
369+
errorCleanup(frame, self, fdIsOwn, posixClose);
370+
name = name == null ? Integer.toString(fd) : name;
371+
throw raiseOSError(frame, OSErrorEnum.EISDIR, name);
372+
}
373+
/*
374+
* TODO: read fstatResult.st_blksize if (fstatResult[8] > 1)
375+
* self.setBlksize(fstatResult[8]); }
376+
*/
397377
} catch (PosixSupportLibrary.PosixException e) {
398378
exceptionProfile.enter();
399-
if (self.getSeekable() < 0) {
400-
self.setSeekable(0);
401-
}
402-
if (e.getErrorCode() != OSErrorEnum.ESPIPE.getNumber()) {
379+
/*
380+
* Tolerate fstat() errors other than EBADF. See Issue #25717, where an
381+
* anonymous file on a Virtual Box shared folder filesystem would raise ENOENT.
382+
*/
383+
if (e.getErrorCode() == OSErrorEnum.EBADF.getNumber()) {
403384
errorCleanup(frame, self, fdIsOwn, posixClose);
404385
throw raiseOSErrorFromPosixException(frame, e);
405386
}
406387
}
388+
setAttr.execute(frame, self, NAME, nameobj);
389+
390+
if (self.isAppending()) {
391+
/*
392+
* For consistent behaviour, we explicitly seek to the end of file (otherwise,
393+
* it might be done only on the first write()).
394+
*/
395+
try {
396+
long res = posixLib.lseek(ctxt.getPosixSupport(), self.getFD(), 0, mapPythonSeekWhenceToPosix(SEEK_END));
397+
self.setSeekable(res >= 0 ? 1 : 0);
398+
} catch (PosixSupportLibrary.PosixException e) {
399+
exceptionProfile.enter();
400+
if (self.getSeekable() < 0) {
401+
self.setSeekable(0);
402+
}
403+
if (e.getErrorCode() != OSErrorEnum.ESPIPE.getNumber()) {
404+
errorCleanup(frame, self, fdIsOwn, posixClose);
405+
throw raiseOSErrorFromPosixException(frame, e);
406+
}
407+
}
408+
}
409+
} catch (PException e) {
410+
/*
411+
* IMPORTANT: In case of any error that happens during initialization, we need reset
412+
* the file descriptor such that the finalizer won't close it. This is necessary
413+
* because the file descriptor value could be reused and then this (broken) instance
414+
* would incorrectly close another resource that accidentally got the same file
415+
* descriptor value.
416+
*/
417+
self.setClosed();
418+
throw e;
407419
}
408420
}
409421

0 commit comments

Comments
 (0)