Skip to content

Commit 1bf80cf

Browse files
committed
[GR-39689] Unexpected IOException in SourceBuilder.
PullRequest: graal/12417
2 parents 968a0e7 + 7d0ee0c commit 1bf80cf

File tree

2 files changed

+118
-6
lines changed
  • truffle/src
    • com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot
    • com.oracle.truffle.api/src/com/oracle/truffle/api/source

2 files changed

+118
-6
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.truffle.api.test.polyglot;
42+
43+
import java.io.IOException;
44+
import java.nio.file.AccessMode;
45+
import java.nio.file.LinkOption;
46+
import java.nio.file.Path;
47+
import java.util.Set;
48+
49+
import org.graalvm.polyglot.Context;
50+
import org.graalvm.polyglot.io.FileSystem;
51+
import org.junit.Assert;
52+
import org.junit.Before;
53+
import org.junit.BeforeClass;
54+
import org.junit.Test;
55+
56+
import com.oracle.truffle.api.TruffleFile;
57+
import com.oracle.truffle.api.source.Source;
58+
import com.oracle.truffle.api.test.OSUtils;
59+
import com.oracle.truffle.api.test.polyglot.FileSystemsTest.ForwardingFileSystem;
60+
import com.oracle.truffle.tck.tests.TruffleTestAssumptions;
61+
62+
public class GR39689Test extends AbstractPolyglotTest {
63+
64+
@BeforeClass
65+
public static void runWithWeakEncapsulationOnly() {
66+
TruffleTestAssumptions.assumeWeakEncapsulation();
67+
}
68+
69+
public GR39689Test() {
70+
needsLanguageEnv = true;
71+
}
72+
73+
@Before
74+
public void setUp() {
75+
setupEnv(Context.newBuilder().allowIO(true).fileSystem(new MockExistsFileSystem()).build());
76+
}
77+
78+
@Test
79+
public void testGetCanonicalFileOfNoLongerExistingFile() {
80+
TruffleFile file = languageEnv.getPublicTruffleFile(OSUtils.isUnix() ? "/non-existent/a/b" : "C:/non-existent/a/b");
81+
Assert.assertTrue(file.exists());
82+
83+
Source.newBuilder(ProxyLanguage.ID, file).content("irrelevant").build();
84+
}
85+
86+
private static final class MockExistsFileSystem extends ForwardingFileSystem {
87+
MockExistsFileSystem() {
88+
super(FileSystem.newDefaultFileSystem());
89+
}
90+
91+
@Override
92+
public void checkAccess(Path path, Set<? extends AccessMode> modes, LinkOption... linkOptions) throws IOException {
93+
if (modes.isEmpty()) { // exists
94+
return;
95+
}
96+
super.checkAccess(path, modes, linkOptions);
97+
}
98+
}
99+
}

truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2013, 2022, 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
@@ -52,6 +52,7 @@
5252
import java.net.URLConnection;
5353
import java.nio.charset.Charset;
5454
import java.nio.charset.StandardCharsets;
55+
import java.nio.file.NoSuchFileException;
5556
import java.security.MessageDigest;
5657
import java.security.NoSuchAlgorithmException;
5758
import java.util.Arrays;
@@ -1007,7 +1008,7 @@ static Source buildSource(String language, Object origin, String name, String pa
10071008
}
10081009
} else {
10091010
// Canonicalize the file if it exists
1010-
useTruffleFile = useTruffleFile.exists() ? useTruffleFile.getCanonicalFile() : useTruffleFile;
1011+
useTruffleFile = getCanonicalFileIfItExists(useTruffleFile);
10111012
}
10121013
useFileSystemContext = SourceAccessor.LANGUAGE.getFileSystemContext(useTruffleFile);
10131014
useName = useName == null ? useTruffleFile.getName() : useName;
@@ -1038,7 +1039,7 @@ static Source buildSource(String language, Object origin, String name, String pa
10381039
useFileSystemContext = useFileSystemContext == null ? SourceAccessor.ACCESSOR.engineSupport().getCurrentFileSystemContext() : useFileSystemContext;
10391040
try {
10401041
useTruffleFile = SourceAccessor.getTruffleFile(tmpUri, useFileSystemContext);
1041-
useTruffleFile = useTruffleFile.exists() ? useTruffleFile.getCanonicalFile() : useTruffleFile;
1042+
useTruffleFile = getCanonicalFileIfItExists(useTruffleFile);
10421043
if (useContent == CONTENT_UNSET) {
10431044
if (isCharacterBased(useFileSystemContext, language, useMimeType)) {
10441045
String fileMimeType = useMimeType == null ? SourceAccessor.detectMimeType(useTruffleFile, getValidMimeTypes(useFileSystemContext, language)) : useMimeType;
@@ -1102,6 +1103,18 @@ static Source buildSource(String language, Object origin, String name, String pa
11021103
return SOURCES.intern(key);
11031104
}
11041105

1106+
private static TruffleFile getCanonicalFileIfItExists(TruffleFile file) throws IOException {
1107+
if (file.exists()) {
1108+
try {
1109+
return file.getCanonicalFile();
1110+
} catch (NoSuchFileException ex) {
1111+
// The file may have been deleted between exists() and getCanonicalFile().
1112+
// We handle this race condition as if the file did not exist.
1113+
}
1114+
}
1115+
return file;
1116+
}
1117+
11051118
static byte[] readBytes(URLConnection connection) throws IOException {
11061119
long size = connection.getContentLengthLong();
11071120
if (size < 0) {
@@ -1413,13 +1426,13 @@ public LiteralBuilder content(ByteSequence bytes) {
14131426
* The MIME type can be guessed by the system based on {@link #findMimeType(TruffleFile)
14141427
* files} or {@link #findMimeType(URL) urls}.
14151428
*
1429+
* @param mimeType the new mime type to be assigned, or <code>null</code> if default MIME
1430+
* type should be used.
1431+
* @return instance of <code>this</code> builder ready to {@link #build() create new source}
14161432
* @see LanguageInfo#getDefaultMimeType()
14171433
* @see LanguageInfo#getMimeTypes()
14181434
* @see Source#findMimeType(TruffleFile)
14191435
* @see Source#findMimeType(URL)
1420-
* @param mimeType the new mime type to be assigned, or <code>null</code> if default MIME
1421-
* type should be used.
1422-
* @return instance of <code>this</code> builder ready to {@link #build() create new source}
14231436
* @since 19.0
14241437
*/
14251438
public SourceBuilder mimeType(@SuppressWarnings("hiding") String mimeType) {

0 commit comments

Comments
 (0)