Author: xor
Date: 2007-12-29 09:36:50 +0000 (Sat, 29 Dec 2007)
New Revision: 16838

Modified:
   trunk/freenet/src/freenet/clients/http/filter/HTMLFilter.java
   trunk/freenet/src/freenet/node/Node.java
Log:
Add a workaround for a bug in GCJ InputStreamReader.refill(). This bug 
prevented many freesites from loading, the following exception was shown [it is 
commented in HTMLFilter.java]:

Internal error: please report
java.io.CharConversionException
   at java.io.InputStreamReader.refill(libgcj.so.70)
   at java.io.InputStreamReader.read(libgcj.so.70)
   at java.io.BufferedReader.fill(libgcj.so.70)
   at java.io.BufferedReader.read(libgcj.so.70)
   at 
freenet.clients.http.filter.HTMLFilter$HTMLParseContext.run(HTMLFilter.java:163)
   at freenet.clients.http.filter.HTMLFilter.getCharset(HTMLFilter.java:103)
   at 
freenet.clients.http.filter.ContentFilter.detectCharset(ContentFilter.java:222)
   at freenet.clients.http.filter.ContentFilter.filter(ContentFilter.java:169)
   at freenet.clients.http.FProxyToadlet.handleDownload(FProxyToadlet.java:105)
   at freenet.clients.http.FProxyToadlet.handleGet(FProxyToadlet.java:385)
   at 
freenet.clients.http.ToadletContextImpl.handle(ToadletContextImpl.java:322)
   at 
freenet.clients.http.SimpleToadletServer$SocketHandler.run(SimpleToadletServer.java:459)
   at freenet.support.PooledExecutor$MyThread.run(PooledExecutor.java:129)

Modified: trunk/freenet/src/freenet/clients/http/filter/HTMLFilter.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/filter/HTMLFilter.java       
2007-12-29 02:36:16 UTC (rev 16837)
+++ trunk/freenet/src/freenet/clients/http/filter/HTMLFilter.java       
2007-12-29 09:36:50 UTC (rev 16838)
@@ -160,7 +160,24 @@
                        mode = INTEXT;

                        while (true) {
-                               int x = r.read();
+                               int x;
+                               
+                               try {
+                                       x = r.read();
+                               }
+                               /** 
+                                * libgcj up to at least 4.2.2 has a bug: 
InputStreamReader.refill() throws this exception when 
BufferedInputReader.refill() returns false for EOF. See:
+                                * line 299 at InputStreamReader.java (in 
refill()): 
http://www.koders.com/java/fidD8F7E2EB1E4C22DA90EBE0130306AE30F876AB00.aspx?s=refill#L279
 
+                                * line 355 at BufferedInputStream.java (in 
refill()): 
http://www.koders.com/java/fid1949641524FAC0083432D79793F554CD85F46759.aspx?s=refill#L355
+                                * TODO: remove this when the gcj bug is fixed 
and the affected gcj versions are outdated. 
+                                */
+                               catch(java.io.CharConversionException cce) {
+                                       
if(freenet.node.Node.checkForGCJCharConversionBug()) /* only ignore the 
exception on affected libgcj */
+                                               x = -1; 
+                                       else
+                                               throw cce;
+                               }
+                               
                                if (x == -1) {
                                        switch (mode) {
                                                case INTEXT :

Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java    2007-12-29 02:36:16 UTC (rev 
16837)
+++ trunk/freenet/src/freenet/node/Node.java    2007-12-29 09:36:50 UTC (rev 
16838)
@@ -1490,7 +1490,13 @@
                if(testnetHandler != null)
                        testnetHandler.start();

-               checkForEvilJVMBug();
+               /* TODO: Make sure that this is called BEFORE any instances of 
HTTPFilter are created.
+                * HTTPFilter uses checkForGCJCharConversionBug() which returns 
the value of the static
+                * variable jvmHasGCJCharConversionBug - and this is 
initialized in the following function.
+                * If this is not possible then create a separate function to 
check for the GCJ bug and
+                * call this function earlier.
+                */ 
+               checkForEvilJVMBugs();

                // TODO: implement a "required" version if needed
                if(!nodeUpdater.isEnabled() && 
(NodeStarter.RECOMMENDED_EXT_BUILD_NUMBER > NodeStarter.extBuildNumber))
@@ -1518,7 +1524,9 @@
                hasStarted = true;
        }

-       private void checkForEvilJVMBug() {
+       private static boolean jvmHasGCJCharConversionBug=false;
+       
+       private void checkForEvilJVMBugs() {
                // Now check whether we are likely to get the EvilJVMBug.
                // If we are running a Sun or Blackdown JVM, on Linux, and 
LD_ASSUME_KERNEL is not set, then we are.

@@ -1594,6 +1602,20 @@
                } else if (jvmVendor.startsWith("Apple ") || 
jvmVendor.startsWith("\"Apple ")) {
                        //Note that Sun does not produce VMs for the Macintosh 
operating system, dont ask the user to find one...
                } else {
+                       if(jvmVendor.startsWith("Free Software Foundation")) {
+                               try {
+                                       jvmVersion = 
System.getProperty("java.vm.version").split(" ")[0].replace(".","");
+                                       int jvmVersionInt = 
Integer.parseInt(jvmVersion);
+                                               
+                                       if(jvmVersionInt <= 422 && 
jvmVersionInt >= 100) // make sure that no bogus values cause true
+                                               jvmHasGCJCharConversionBug=true;
+                               }
+                               
+                               catch(Throwable t) {
+                                       Logger.error(this, "GCJ version check 
is broken!", t);
+                               }
+                       }
+
                        clientCore.alerts.register(new SimpleUserAlert(true, 
l10n("notUsingSunVMTitle"), l10n("notUsingSunVM", new String[] { "vendor", 
"version" }, new String[] { jvmVendor, jvmVersion }), UserAlert.WARNING));
                }

@@ -1603,6 +1625,10 @@

        }

+       public static boolean checkForGCJCharConversionBug() {  
+               return jvmHasGCJCharConversionBug; // should be initialized on 
early startup
+       }
+
        private String l10n(String key) {
                return L10n.getString("Node."+key);
        }


Reply via email to