Skip to content

Commit 96458bc

Browse files
committed
[GR-21335] Improve errno handling in PosixModuleBuiltins
PullRequest: graalpython/824
2 parents 30c9491 + c7e0197 commit 96458bc

File tree

7 files changed

+442
-371
lines changed

7 files changed

+442
-371
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java

Lines changed: 294 additions & 342 deletions
Large diffs are not rendered by default.

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -273,7 +273,7 @@ private Object createSocketInternal(VirtualFrame frame, LazyPythonClass cls, int
273273
if (getContext().getEnv().isNativeAccessAllowed()) {
274274
PSocket oldSocket = getContext().getResources().getSocket(fileno);
275275
if (oldSocket == null) {
276-
throw raiseOSError(frame, OSErrorEnum.EBADF.getNumber());
276+
throw raiseOSError(frame, OSErrorEnum.EBADF);
277277
}
278278
PSocket newSocket = factory().createSocket(cls, family == -1 ? oldSocket.getFamily() : family, type == -1 ? oldSocket.getType() : type, proto == -1 ? oldSocket.getProto() : proto,
279279
fileno);
@@ -629,17 +629,17 @@ Object close(VirtualFrame frame, int fd) {
629629
PSocket socket = getContext().getResources().getSocket(fd);
630630

631631
if (socket == null) {
632-
throw raiseOSError(frame, OSErrorEnum.EBADF.getNumber());
632+
throw raiseOSError(frame, OSErrorEnum.EBADF);
633633
}
634634

635635
if (!socket.isOpen()) {
636-
throw raiseOSError(frame, OSErrorEnum.EBADF.getNumber());
636+
throw raiseOSError(frame, OSErrorEnum.EBADF);
637637
}
638638

639639
try {
640640
socket.close();
641641
} catch (IOException e) {
642-
throw raiseOSError(frame, OSErrorEnum.EBADF.getNumber());
642+
throw raiseOSError(frame, OSErrorEnum.EBADF);
643643
}
644644
getContext().getResources().close(socket.getFileno());
645645
return PNone.NONE;

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/OSErrorEnum.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -40,6 +40,8 @@
4040
*/
4141
package com.oracle.graal.python.builtins.objects.exception;
4242

43+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
44+
4345
public enum OSErrorEnum {
4446

4547
/**
@@ -206,4 +208,25 @@ public String getMessage() {
206208
public int getNumber() {
207209
return number;
208210
}
211+
212+
@TruffleBoundary
213+
public static OSErrorEnum fromMessage(String message) {
214+
for (OSErrorEnum oserror : values()) {
215+
if (message.equals(oserror.getMessage())) {
216+
return oserror;
217+
}
218+
}
219+
return null;
220+
}
221+
222+
@TruffleBoundary
223+
public static OSErrorEnum fromNumber(int number) {
224+
OSErrorEnum[] values = values();
225+
for (int i = number; i < values.length; i++) {
226+
if (values[i].getNumber() == number) {
227+
return values[i];
228+
}
229+
}
230+
return null;
231+
}
209232
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PRaiseOSErrorNode.java

Lines changed: 95 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -40,6 +40,22 @@
4040
*/
4141
package com.oracle.graal.python.nodes;
4242

43+
import java.io.FileNotFoundException;
44+
import java.io.IOException;
45+
import java.nio.channels.ClosedChannelException;
46+
import java.nio.channels.NonReadableChannelException;
47+
import java.nio.channels.NonWritableChannelException;
48+
import java.nio.file.AccessDeniedException;
49+
import java.nio.file.DirectoryNotEmptyException;
50+
import java.nio.file.FileAlreadyExistsException;
51+
import java.nio.file.FileSystemException;
52+
import java.nio.file.FileSystemLoopException;
53+
import java.nio.file.NoSuchFileException;
54+
import java.nio.file.NotDirectoryException;
55+
import java.nio.file.NotLinkException;
56+
import java.util.regex.Matcher;
57+
import java.util.regex.Pattern;
58+
4359
import com.oracle.graal.python.PythonLanguage;
4460
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
4561
import com.oracle.graal.python.builtins.objects.PNone;
@@ -64,11 +80,9 @@
6480
@ImportStatic(PGuards.class)
6581
public abstract class PRaiseOSErrorNode extends Node {
6682

67-
public abstract PException execute(Frame frame, Object[] arguments);
83+
private static final Pattern ERRNO_PATTERN = Pattern.compile("error=(\\d+)");
6884

69-
public final PException raiseOSError(Frame frame, int errno) {
70-
return execute(frame, new Object[]{errno});
71-
}
85+
public abstract PException execute(Frame frame, Object[] arguments);
7286

7387
public final PException raiseOSError(Frame frame, OSErrorEnum oserror) {
7488
return execute(frame, new Object[]{oserror.getNumber(), oserror.getMessage()});
@@ -79,10 +93,24 @@ public final PException raiseOSError(Frame frame, OSErrorEnum oserror, Exception
7993
}
8094

8195
@TruffleBoundary
82-
private static final String getMessage(Exception e) {
96+
private static String getMessage(Exception e) {
8397
return e.getMessage();
8498
}
8599

100+
@TruffleBoundary
101+
private static String getReason(FileSystemException e) {
102+
return e.getReason();
103+
}
104+
105+
@TruffleBoundary
106+
private static OSErrorEnum tryFindErrnoFromMessage(Exception e) {
107+
Matcher m = ERRNO_PATTERN.matcher(e.getMessage());
108+
if (m.find()) {
109+
return OSErrorEnum.fromNumber(Integer.parseInt(m.group(1)));
110+
}
111+
return null;
112+
}
113+
86114
public final PException raiseOSError(Frame frame, OSErrorEnum oserror, String filename) {
87115
return execute(frame, new Object[]{oserror.getNumber(), oserror.getMessage(), filename});
88116
}
@@ -91,6 +119,67 @@ public final PException raiseOSError(Frame frame, OSErrorEnum oserror, String fi
91119
return execute(frame, new Object[]{oserror.getNumber(), oserror.getMessage(), filename, PNone.NONE, filename2});
92120
}
93121

122+
public final PException raiseOSError(Frame frame, Exception e) {
123+
return raiseOSError(frame, e, null, null);
124+
}
125+
126+
public final PException raiseOSError(Frame frame, Exception e, String filename) {
127+
return raiseOSError(frame, e, filename, null);
128+
}
129+
130+
public final PException raiseOSError(Frame frame, Exception e, String filename, String filename2) {
131+
OSErrorEnum oserror;
132+
String message = null;
133+
if (e instanceof IOException) {
134+
if (e instanceof NoSuchFileException || e instanceof FileNotFoundException) {
135+
oserror = OSErrorEnum.ENOENT;
136+
} else if (e instanceof AccessDeniedException) {
137+
oserror = OSErrorEnum.EACCES;
138+
} else if (e instanceof FileAlreadyExistsException) {
139+
oserror = OSErrorEnum.EEXIST;
140+
} else if (e instanceof NotDirectoryException) {
141+
oserror = OSErrorEnum.ENOTDIR;
142+
} else if (e instanceof DirectoryNotEmptyException) {
143+
oserror = OSErrorEnum.ENOTEMPTY;
144+
} else if (e instanceof FileSystemLoopException) {
145+
oserror = OSErrorEnum.ELOOP;
146+
} else if (e instanceof NotLinkException) {
147+
oserror = OSErrorEnum.EINVAL;
148+
} else if (e instanceof ClosedChannelException) {
149+
oserror = OSErrorEnum.EPIPE;
150+
} else if (e instanceof FileSystemException) {
151+
String reason = getReason((FileSystemException) e);
152+
oserror = OSErrorEnum.fromMessage(reason);
153+
if (oserror == null) {
154+
oserror = OSErrorEnum.EIO;
155+
message = reason;
156+
}
157+
} else { // Generic IOException
158+
oserror = tryFindErrnoFromMessage(e);
159+
if (oserror == null) {
160+
oserror = OSErrorEnum.EIO;
161+
message = getMessage(e);
162+
}
163+
}
164+
} else if (e instanceof SecurityException) {
165+
oserror = OSErrorEnum.EPERM;
166+
} else if (e instanceof IllegalArgumentException) {
167+
oserror = OSErrorEnum.EINVAL;
168+
} else if (e instanceof UnsupportedOperationException) {
169+
oserror = OSErrorEnum.EOPNOTSUPP;
170+
} else if (e instanceof NonReadableChannelException || e instanceof NonWritableChannelException) {
171+
oserror = OSErrorEnum.EBADF;
172+
} else if (e instanceof RuntimeException) {
173+
throw (RuntimeException) e;
174+
} else {
175+
throw new RuntimeException(getMessage(e), e);
176+
}
177+
if (message == null) {
178+
message = oserror.getMessage();
179+
}
180+
return execute(frame, new Object[]{oserror.getNumber(), message, (filename != null) ? filename : PNone.NONE, PNone.NONE, (filename2 != null) ? filename2 : PNone.NONE});
181+
}
182+
94183
@Specialization
95184
PException raiseOSError(VirtualFrame frame, Object[] arguments,
96185
@Cached CallVarargsMethodNode callNode,

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/PythonBuiltinBaseNode.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -178,10 +178,6 @@ public final PException raise(PythonBuiltinClassType type, Exception e) {
178178
return getRaiseNode().raise(type, e);
179179
}
180180

181-
public final PException raiseOSError(VirtualFrame frame, int num) {
182-
return getRaiseOSNode().raiseOSError(frame, num);
183-
}
184-
185181
public final PException raiseOSError(VirtualFrame frame, OSErrorEnum num) {
186182
return getRaiseOSNode().raiseOSError(frame, num);
187183
}
@@ -193,4 +189,16 @@ public final PException raiseOSError(VirtualFrame frame, OSErrorEnum oserror, Ex
193189
public final PException raiseOSError(VirtualFrame frame, OSErrorEnum oserror, String filename) {
194190
return getRaiseOSNode().raiseOSError(frame, oserror, filename);
195191
}
192+
193+
public final PException raiseOSError(VirtualFrame frame, Exception e) {
194+
return getRaiseOSNode().raiseOSError(frame, e);
195+
}
196+
197+
public final PException raiseOSError(VirtualFrame frame, Exception e, String filename) {
198+
return getRaiseOSNode().raiseOSError(frame, e, filename);
199+
}
200+
201+
public final PException raiseOSError(VirtualFrame frame, Exception e, String filename, String filename2) {
202+
return getRaiseOSNode().raiseOSError(frame, e, filename, filename2);
203+
}
196204
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/CastToPathNode.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@
5959
import com.oracle.truffle.api.dsl.Specialization;
6060
import com.oracle.truffle.api.frame.VirtualFrame;
6161
import com.oracle.truffle.api.nodes.Node;
62-
import com.oracle.truffle.api.profiles.ValueProfile;
6362

6463
/**
6564
* Converts a Python object to a Path string
@@ -105,22 +104,22 @@ String doString(String x) {
105104
}
106105

107106
@Specialization
108-
String doPString(PString x) {
109-
return x.getValue();
107+
String doPString(PString x,
108+
@Cached CastToJavaStringNode castToJavaStringNode) {
109+
return castToJavaStringNode.execute(x);
110110
}
111111

112112
@Specialization(guards = {"!isString(object)", "!isBytes(object)", "!isMemoryView(object)"})
113113
String doObject(VirtualFrame frame, Object object,
114-
@Cached("createClassProfile()") ValueProfile resultTypeProfile,
115114
@Cached PRaiseNode raise,
116-
@Cached("createFsPathCall()") LookupAndCallUnaryNode callFsPath) {
117-
Object profiled = resultTypeProfile.profile(callFsPath.executeObject(frame, object));
118-
if (profiled instanceof String) {
119-
return (String) profiled;
120-
} else if (profiled instanceof PString) {
121-
return doPString((PString) profiled);
115+
@Cached("createFsPathCall()") LookupAndCallUnaryNode callFsPath,
116+
@Cached CastToJavaStringNode castToJavaStringNode) {
117+
Object pathObject = callFsPath.executeObject(frame, object);
118+
String path = castToJavaStringNode.execute(pathObject);
119+
if (path == null) {
120+
throw raise.raise(PythonBuiltinClassType.TypeError, "invalid type %p return from path-like object", pathObject);
122121
}
123-
throw raise.raise(PythonBuiltinClassType.TypeError, "invalid type %p return from path-like object", profiled);
122+
return path;
124123
}
125124

126125
protected LookupAndCallUnaryNode createFsPathCall() {

mx.graalpython/copyrights/oracle.copyright.regex.star

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/\*\s*
2-
\* Copyright \(c\) (?:20[0-9][0-9], )*(20[0-9][0-9]), Oracle and/or its affiliates. All rights reserved\.\s*
2+
\* Copyright \(c\) (20[0-9][0-9], )*(20[0-9][0-9]), Oracle and/or its affiliates. All rights reserved\.\s*
33
\* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER\.\s*
44
\*\s*
55
\* The Universal Permissive License \(UPL\), Version 1\.0\s*

0 commit comments

Comments
 (0)