Bug 575641 - Text editor fails to open for very large text files

This change adds a catch for OutOfMemoryError to setDocumentContent() in
ResourceTextFileBuffer, FileStoreTextFileBuffer and
LastSaveReferenceProvider. The OOM is wrapped in an IOException and is
rethrown as a CoreException, relying on the CoreException handling
further up in the call stack trace.

Change-Id: I1ad32be1c1733106c3516c5914ab7784fcc57972
Signed-off-by: Simeon Andreev <simeon.danailov.andreev@gmail.com>
Reviewed-on: https://git.eclipse.org/r/c/platform/eclipse.platform.text/+/184513
Tested-by: Andrey Loskutov <loskutov@gmx.de>
Tested-by: Platform Bot <platform-bot@eclipse.org>
Reviewed-by: Jörg Kubitz <jkubitz-eclipse@gmx.de>
Reviewed-by: Andrey Loskutov <loskutov@gmx.de>
diff --git a/org.eclipse.core.filebuffers/src/org/eclipse/core/internal/filebuffers/FileBuffersMessages.java b/org.eclipse.core.filebuffers/src/org/eclipse/core/internal/filebuffers/FileBuffersMessages.java
index d64141f..0f834ab 100644
--- a/org.eclipse.core.filebuffers/src/org/eclipse/core/internal/filebuffers/FileBuffersMessages.java
+++ b/org.eclipse.core.filebuffers/src/org/eclipse/core/internal/filebuffers/FileBuffersMessages.java
@@ -41,6 +41,7 @@
 	public static String ResourceTextFileBuffer_error_unsupported_encoding_message_arg;
 	public static String ResourceTextFileBuffer_error_illegal_encoding_message_arg;
 	public static String ResourceTextFileBuffer_task_saving;
+	public static String ResourceTextFileBuffer_oom_on_file_read;
 	public static String ResourceFileBuffer_task_creatingFileBuffer;
 	public static String JavaTextFileBuffer_error_closeStream;
 	public static String TextFileBufferManager_error_documentSetupFailed;
diff --git a/org.eclipse.core.filebuffers/src/org/eclipse/core/internal/filebuffers/FileBuffersMessages.properties b/org.eclipse.core.filebuffers/src/org/eclipse/core/internal/filebuffers/FileBuffersMessages.properties
index 1f05f68..8e17fda 100644
--- a/org.eclipse.core.filebuffers/src/org/eclipse/core/internal/filebuffers/FileBuffersMessages.properties
+++ b/org.eclipse.core.filebuffers/src/org/eclipse/core/internal/filebuffers/FileBuffersMessages.properties
@@ -30,6 +30,7 @@
 ResourceTextFileBuffer_error_unsupported_encoding_message_arg= Character encoding "{0}" is not supported by this platform.
 ResourceTextFileBuffer_error_charset_mapping_failed_message_arg=Some characters cannot be mapped using "{0}" character encoding.\nEither change the encoding or remove the characters which are not supported by the "{0}" character encoding.
 ResourceTextFileBuffer_task_saving= Saving
+ResourceTextFileBuffer_oom_on_file_read=OutOfMemoryError occurred while reading file "{0}".
 
 ResourceFileBuffer_task_creatingFileBuffer=creating file buffer
 
diff --git a/org.eclipse.core.filebuffers/src/org/eclipse/core/internal/filebuffers/FileStoreTextFileBuffer.java b/org.eclipse.core.filebuffers/src/org/eclipse/core/internal/filebuffers/FileStoreTextFileBuffer.java
index 289de5d..acc254e 100644
--- a/org.eclipse.core.filebuffers/src/org/eclipse/core/internal/filebuffers/FileStoreTextFileBuffer.java
+++ b/org.eclipse.core.filebuffers/src/org/eclipse/core/internal/filebuffers/FileStoreTextFileBuffer.java
@@ -33,6 +33,8 @@
 import java.nio.charset.UnmappableCharacterException;
 import java.nio.charset.UnsupportedCharsetException;
 
+import org.eclipse.osgi.util.NLS;
+
 import org.eclipse.core.filesystem.EFS;
 import org.eclipse.core.filesystem.IFileInfo;
 import org.eclipse.core.filesystem.IFileStore;
@@ -532,9 +534,15 @@
 			StringBuilder buffer= new StringBuilder(BUFFER_SIZE);
 			char[] readBuffer= new char[READER_CHUNK_SIZE];
 			int n= in.read(readBuffer);
-			while (n > 0) {
-				buffer.append(readBuffer, 0, n);
-				n= in.read(readBuffer);
+			try {
+				while (n > 0) {
+					buffer.append(readBuffer, 0, n);
+					n= in.read(readBuffer);
+				}
+			} catch (OutOfMemoryError e) {
+				// give the JVM a hint that it can free the big buffer right away
+				buffer= null;
+				throw new IOException(NLS.bind(FileBuffersMessages.ResourceTextFileBuffer_oom_on_file_read, file.toURI()), e);
 			}
 
 			document.set(buffer.toString());
diff --git a/org.eclipse.core.filebuffers/src/org/eclipse/core/internal/filebuffers/ResourceTextFileBuffer.java b/org.eclipse.core.filebuffers/src/org/eclipse/core/internal/filebuffers/ResourceTextFileBuffer.java
index 69a3e4d..8b903e4 100644
--- a/org.eclipse.core.filebuffers/src/org/eclipse/core/internal/filebuffers/ResourceTextFileBuffer.java
+++ b/org.eclipse.core.filebuffers/src/org/eclipse/core/internal/filebuffers/ResourceTextFileBuffer.java
@@ -31,6 +31,8 @@
 import java.nio.charset.UnmappableCharacterException;
 import java.nio.charset.UnsupportedCharsetException;
 
+import org.eclipse.osgi.util.NLS;
+
 import org.eclipse.core.runtime.Assert;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
@@ -514,9 +516,15 @@
 			StringBuilder buffer= new StringBuilder(BUFFER_SIZE);
 			char[] readBuffer= new char[READER_CHUNK_SIZE];
 			int n= in.read(readBuffer);
-			while (n > 0) {
-				buffer.append(readBuffer, 0, n);
-				n= in.read(readBuffer);
+			try {
+				while (n > 0) {
+					buffer.append(readBuffer, 0, n);
+					n= in.read(readBuffer);
+				}
+			} catch (OutOfMemoryError e) {
+				// give the JVM a hint that it can free the big buffer right away
+				buffer= null;
+				throw new IOException(NLS.bind(FileBuffersMessages.ResourceTextFileBuffer_oom_on_file_read, file.getLocationURI()), e);
 			}
 
 			if (document instanceof IDocumentExtension4)
diff --git a/org.eclipse.ui.editors/src/org/eclipse/ui/internal/editors/quickdiff/LastSaveReferenceProvider.java b/org.eclipse.ui.editors/src/org/eclipse/ui/internal/editors/quickdiff/LastSaveReferenceProvider.java
index b8f9705..32e13b6 100644
--- a/org.eclipse.ui.editors/src/org/eclipse/ui/internal/editors/quickdiff/LastSaveReferenceProvider.java
+++ b/org.eclipse.ui.editors/src/org/eclipse/ui/internal/editors/quickdiff/LastSaveReferenceProvider.java
@@ -44,6 +44,7 @@
 import org.eclipse.ui.IStorageEditorInput;
 import org.eclipse.ui.IWorkbenchPartSite;
 import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.editors.text.EditorsPlugin;
 
 import org.eclipse.ui.texteditor.IDocumentProvider;
 import org.eclipse.ui.texteditor.IElementStateListener;
@@ -250,6 +251,7 @@
 				}
 
 			} catch (CoreException e) {
+				EditorsPlugin.log(e);
 				return;
 			}
 
@@ -375,18 +377,21 @@
 			StringBuilder buffer= new StringBuilder(DEFAULT_FILE_SIZE);
 			char[] readBuffer= new char[2048];
 			int n= in.read(readBuffer);
-			while (n > 0) {
-				if (monitor != null && monitor.isCanceled())
-					return;
+			try {
+				while (n > 0) {
+					if (monitor != null && monitor.isCanceled())
+						return;
 
-				buffer.append(readBuffer, 0, n);
-				n= in.read(readBuffer);
+					buffer.append(readBuffer, 0, n);
+					n= in.read(readBuffer);
+				}
+			} catch (OutOfMemoryError e) {
+				throw new IOException("OutOfMemoryError occurred while reading " + storage.getFullPath(), e); //$NON-NLS-1$
 			}
-
 			document.set(buffer.toString());
 
 		} catch (IOException x) {
-			throw new CoreException(new Status(IStatus.ERROR, EditorsUI.PLUGIN_ID, IStatus.OK, "Failed to access or read underlying storage", x)); //$NON-NLS-1$
+			throw new CoreException(Status.error("Failed to access or read " + storage.getFullPath(), x)); //$NON-NLS-1$
 		} finally {
 			try {
 				if (in != null)