From 56e458d33faaa22f2ad08456f05edd1b4457f428 Mon Sep 17 00:00:00 2001 From: Ilya Basin Date: Fri, 21 Oct 2011 17:00:39 +0400 Subject: [PATCH] fix bug 327193 CreateProcess error=87 on windows when classpath too long https://bugs.eclipse.org/bugs/show_bug.cgi?id=327193 --- .../launching/LongCommandLineLauncher.java | 45 ++++++++++++ .../jdt/internal/launching/StandardVMDebugger.java | 6 ++ .../jdt/internal/launching/StandardVMRunner.java | 76 ++++++++++++++++++++ 3 files changed, 127 insertions(+), 0 deletions(-) create mode 100644 launching/org/eclipse/jdt/internal/launching/LongCommandLineLauncher.java diff --git a/launching/org/eclipse/jdt/internal/launching/LongCommandLineLauncher.java b/launching/org/eclipse/jdt/internal/launching/LongCommandLineLauncher.java new file mode 100644 index 0000000..aa08d0d --- /dev/null +++ b/launching/org/eclipse/jdt/internal/launching/LongCommandLineLauncher.java @@ -0,0 +1,45 @@ +package org.eclipse.jdt.internal.launching; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.net.URL; +import java.net.URLClassLoader; + +public class LongCommandLineLauncher { + /** + * usage: LongCommandLineLauncher path/to/urls.lst realMainClass args... + */ + public static void main(String[] args) throws Exception { + URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); + Class clazz= URLClassLoader.class; + Method method= clazz.getDeclaredMethod("addURL", new Class[] { URL.class }); //$NON-NLS-1$ + method.setAccessible(true); + + String urlsfile = args[0]; + File f = new File(urlsfile); + BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(f), "UTF-8")); //$NON-NLS-1$ + String url; + while(null != (url = reader.readLine())) { + method.invoke(classLoader, new Object[] { new URL(url) }); + } + reader.close(); + f.delete(); + + String realMainClass = args[1]; + clazz = Class.forName(realMainClass); + method = clazz.getMethod("main", new Class[] { args.getClass() }); //$NON-NLS-1$ + method.setAccessible(true); + int mods = method.getModifiers(); + if (method.getReturnType() != void.class || !Modifier.isStatic(mods) + || !Modifier.isPublic(mods)) { + throw new NoSuchMethodException("main"); //$NON-NLS-1$ + } + String[] args2 = new String[args.length-2]; + System.arraycopy(args, 2, args2, 0, args2.length); + method.invoke(null, new Object[] { args2 }); + } +} diff --git a/launching/org/eclipse/jdt/internal/launching/StandardVMDebugger.java b/launching/org/eclipse/jdt/internal/launching/StandardVMDebugger.java index a2e6ed9..48f4bc6 100644 --- a/launching/org/eclipse/jdt/internal/launching/StandardVMDebugger.java +++ b/launching/org/eclipse/jdt/internal/launching/StandardVMDebugger.java @@ -203,15 +203,21 @@ public class StandardVMDebugger extends StandardVMRunner { addBootClassPathArguments(arguments, config); String[] cp= config.getClassPath(); + int classpathArgIndex = -1; if (cp.length > 0) { arguments.add("-classpath"); //$NON-NLS-1$ + classpathArgIndex = arguments.size(); arguments.add(convertClassPath(cp)); } arguments.add(config.getClassToLaunch()); + + shortenCommandLine(classpathArgIndex, arguments, cp, config); + addArguments(config.getProgramArguments(), arguments); + String[] cmdLine= new String[arguments.size()]; arguments.toArray(cmdLine); diff --git a/launching/org/eclipse/jdt/internal/launching/StandardVMRunner.java b/launching/org/eclipse/jdt/internal/launching/StandardVMRunner.java index 1ede69a..e51f0a7 100644 --- a/launching/org/eclipse/jdt/internal/launching/StandardVMRunner.java +++ b/launching/org/eclipse/jdt/internal/launching/StandardVMRunner.java @@ -12,6 +12,10 @@ package org.eclipse.jdt.internal.launching; import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; @@ -290,11 +294,15 @@ public class StandardVMRunner extends AbstractVMRunner { addBootClassPathArguments(arguments, config); String[] cp= config.getClassPath(); + int classpathArgIndex = -1; if (cp.length > 0) { arguments.add("-classpath"); //$NON-NLS-1$ + classpathArgIndex = arguments.size(); arguments.add(convertClassPath(cp)); } arguments.add(config.getClassToLaunch()); + + shortenCommandLine(classpathArgIndex, arguments, cp, config); String[] programArgs= config.getProgramArguments(); addArguments(programArgs, arguments); @@ -377,6 +385,74 @@ public class StandardVMRunner extends AbstractVMRunner { return env; } + protected void shortenCommandLine(int classpathArgIndex, List arguments, String[] cp, VMRunnerConfiguration config) { + if (classpathArgIndex > -1 + && ((String)arguments.get(classpathArgIndex)).length() > 256 // can be shortened + && File.separatorChar == '\\' // is Windows + ) + { + int cmdLen = 0; + for (int i = 0, sz = arguments.size(); i < sz; i++) { + cmdLen += ((String)arguments.get(i)).length() + 1; + } + if (cmdLen > 30000) { + File lclF; + ArrayList lclShortCp = new ArrayList(); + try { + lclF = File.createTempFile("eclipse", "tmp"); //$NON-NLS-1$//$NON-NLS-2$ + String lclTempDir = lclF.getAbsolutePath(); + lclF.delete(); + lclF.mkdir(); + Class lclClazz = LongCommandLineLauncher.class; + String lclClassName = lclClazz.getName().replace('.', '/'); + String lclClassFile = lclClassName.concat(".class"); //$NON-NLS-1$ + + String lclAbsClassFile = lclTempDir + '/' + lclClassFile; + new File(lclAbsClassFile).getParentFile().mkdirs(); + ClassLoader lclCL = lclClazz.getClassLoader(); + InputStream lclIS = lclCL.getResourceAsStream(lclClassFile); + OutputStream lclOS = new FileOutputStream(lclAbsClassFile); + byte[] lclBuf = new byte[1024]; + int lclNB; + while(-1 != (lclNB = lclIS.read(lclBuf, 0, lclBuf.length))) { + lclOS.write(lclBuf, 0, lclNB); + } + lclOS.close(); + lclIS.close(); + + lclF = File.createTempFile("urls", ".lst"); //$NON-NLS-1$//$NON-NLS-2$ + OutputStreamWriter lclExtractWriter = new OutputStreamWriter(new FileOutputStream(lclF), "UTF-8"); //$NON-NLS-1$ + String urlsfile = lclF.getAbsolutePath(); + File workingDir = getWorkingDir(config); + + for (int i = 0; i < cp.length; i++) { + String cpEntry = cp[i]; + lclF = new File(cpEntry); + if (workingDir != null && !lclF.isAbsolute()) + lclF = new File(new File(workingDir.getPath() + '/' + lclF.getPath()).getCanonicalPath()); + + lclExtractWriter.append(lclF.toURI().toString()); + lclExtractWriter.append('\n'); + } + lclExtractWriter.close(); + lclShortCp.add(lclTempDir); + String[] shortCpA = new String[lclShortCp.size()]; + lclShortCp.toArray(shortCpA); + arguments.set(classpathArgIndex, convertClassPath(shortCpA)); + String realMainClass = (String)arguments.get(classpathArgIndex+1); + arguments.set(classpathArgIndex+1, lclClassName); + ArrayList lclList = new ArrayList(2); + lclList.add(urlsfile); + lclList.add(realMainClass); + arguments.addAll(classpathArgIndex+2, lclList); + } catch(Exception e) { + e.printStackTrace(); + // falback to normal + } + } + } + } + /** * Adds arguments to the bootpath * @param arguments -- 1.7.5.1