You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@lucene.apache.org by "gsmiller (via GitHub)" <gi...@apache.org> on 2023/07/24 19:41:08 UTC

[GitHub] [lucene] gsmiller opened a new issue, #12458: UTF32toUTF8 can produce automata that produce invalid unicode

gsmiller opened a new issue, #12458:
URL: https://github.com/apache/lucene/issues/12458

   ### Description
   
   When converting a unicode (UTF32) automaton down to a UTF8 representation, UTF32toUTF8 can create an automaton that produces/accepts invalid UTF8. This happens when a transition in the input automaton contains a code-point range that spans different UTF8 byte counts.
   
   As an example/repro, create an automaton that accepts the two single-character terms: `U+65535` and `U+65536` (sample code for this in the repro test case below). Before compiling, the UTF32 representation is:
   ![out](https://github.com/apache/lucene/assets/16479560/de67f83e-0463-47f6-882b-470493c6492f)
   
   This range correctly covers `65535 - 65536` (`0xffff - 0x10000`). Note that the min value (65535) is the largest value that can be represented in three UTF8 bytes (it's representation is `11101111 10111111 10111111` in UTF8), and the max value (65536) is the smallest valid UTF8 representation that uses four bytes (`11110000 10010000 10000000 10000000`).
   
   After converting with `UTF32toUTF8#convert`, the resulting automaton looks like this:
   ![out](https://github.com/apache/lucene/assets/16479560/60035b56-a6ea-4653-97f5-68d1d97197de)
   
   This automaton incorrectly accepts/produces everything in the range `0xf0 0x80 0x80 0x80` - `0xf0 0x8f 0xbf 0xbf`. These are four byte UTF8 sequences encoding all code points from `0x00 - 0xffff` (`0 - 65535`). So this automaton now incorrectly accepts/produces everything between `0 - 65534` (`65535` is valid of course). Because it's representing these values as four UTF8 bytes, I believe these are actually invalid UTF8 since my understanding is that code points should be represented with the minimal number of bytes, but I might be mistaken.
   
   The bug lies in the `UTF32toUTF8#end` logic.
   
   Here is a full test case that demonstrates the bug:
   ```
     public void testFoo() throws Exception {
       Automaton.Builder b = new Automaton.Builder();
       // start state:
       int s1 = b.createState();
   
       // single end accept state:
       int s2 = b.createState();
       b.setAccept(s2, true);
   
       // add two single-code-point terms: U+65535 and U+65536
       b.addTransition(s1, s2, 65535);
       b.addTransition(s1, s2, 65536);
   
       Automaton a = b.finish();
   
       CompiledAutomaton c = new CompiledAutomaton(a);
       FiniteStringsIterator it = new FiniteStringsIterator(c.automaton);
       int termCount = 0;
       for (IntsRef r = it.next(); r != null; r = it.next()) {
         termCount++;
       }
       assertEquals(2, termCount);
     }
   ```
   
   The assertion fails as:
   ```
   expected:<2> but was:<65538>
   ```
   
   
   ### Version and environment details
   
   _No response_


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org
For additional commands, e-mail: issues-help@lucene.apache.org


[GitHub] [lucene] mikemccand commented on issue #12458: UTF32toUTF8 can create automata that produce/accept invalid unicode

Posted by "mikemccand (via GitHub)" <gi...@apache.org>.
mikemccand commented on issue #12458:
URL: https://github.com/apache/lucene/issues/12458#issuecomment-1653658734

   The code does in fact seem to try to handle this case, when the start/end UTF-8 have different numbers of bytes, in the final `else` clause in the confusing `build` method:
   
   ```
       } else {
   
         // start
         start(start, end, startUTF8, upto, true);
   
         // possibly middle, spanning multiple num bytes
         int byteCount = 1 + startUTF8.len - upto;
         final int limit = endUTF8.len - upto;
         while (byteCount < limit) {
           // wasteful: we only need first byte, and, we should
           // statically encode this first byte:
           tmpUTF8a.set(startCodes[byteCount - 1]);
           tmpUTF8b.set(endCodes[byteCount - 1]);
           all(start, end, tmpUTF8a.byteAt(0), tmpUTF8b.byteAt(0), tmpUTF8a.len - 1);
           byteCount++;
         }
   ```
   
   Here the bug must lurk!
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org
For additional commands, e-mail: issues-help@lucene.apache.org


[GitHub] [lucene] gsmiller commented on issue #12458: UTF32toUTF8 can create automata that produce/accept invalid unicode

Posted by "gsmiller (via GitHub)" <gi...@apache.org>.
gsmiller commented on issue #12458:
URL: https://github.com/apache/lucene/issues/12458#issuecomment-1681354136

   Fixed by @tang-hi in GH#12472. Thanks!!!


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org
For additional commands, e-mail: issues-help@lucene.apache.org


[GitHub] [lucene] mikemccand commented on issue #12458: UTF32toUTF8 can create automata that produce/accept invalid unicode

Posted by "mikemccand (via GitHub)" <gi...@apache.org>.
mikemccand commented on issue #12458:
URL: https://github.com/apache/lucene/issues/12458#issuecomment-1653651762

   And ... 2 -> 3 bytes DOES fail, fun :)
   
   ```
     public void testUTF8TwoToThreeBytes() throws Exception {
       Automaton.Builder b = new Automaton.Builder();
       // start state:
       int s1 = b.createState();
   
       // single end accept state:
       int s2 = b.createState();
       b.setAccept(s2, true);
   
       // add two single-code-point terms
       b.addTransition(s1, s2, 0x7FF);
       b.addTransition(s1, s2, 0x800);
   
       Automaton a = b.finish();
   
       CompiledAutomaton c = new CompiledAutomaton(a);
       FiniteStringsIterator it = new FiniteStringsIterator(c.automaton);
       int termCount = 0;
       for (IntsRef r = it.next(); r != null; r = it.next()) {
         termCount++;
       }
       assertEquals(2, termCount);
     }
   ```
   
   ```
      >     java.lang.AssertionError: expected:<2> but was:<2050>
      >         at __randomizedtesting.SeedInfo.seed([E20E213BD5F7763C:1E8F5BB354E27C83]:0)
      >         at org.junit.Assert.fail(Assert.java:89)
      >         at org.junit.Assert.failNotEquals(Assert.java:835)
      >         at org.junit.Assert.assertEquals(Assert.java:647)
      >         at org.junit.Assert.assertEquals(Assert.java:633)
      >         at org.apache.lucene.util.automaton.TestUTF32ToUTF8.testUTF8TwoToThreeBytes(TestUTF32ToUTF8.java:335)
   ```


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org
For additional commands, e-mail: issues-help@lucene.apache.org


[GitHub] [lucene] mikemccand commented on issue #12458: UTF32toUTF8 can create automata that produce/accept invalid unicode

Posted by "mikemccand (via GitHub)" <gi...@apache.org>.
mikemccand commented on issue #12458:
URL: https://github.com/apache/lucene/issues/12458#issuecomment-1657101258

   Whoa, great find!  T hanks @tang-hi -- I'll try to review the PR soon.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org
For additional commands, e-mail: issues-help@lucene.apache.org


[GitHub] [lucene] gsmiller closed issue #12458: UTF32toUTF8 can create automata that produce/accept invalid unicode

Posted by "gsmiller (via GitHub)" <gi...@apache.org>.
gsmiller closed issue #12458: UTF32toUTF8 can create automata that produce/accept invalid unicode
URL: https://github.com/apache/lucene/issues/12458


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org
For additional commands, e-mail: issues-help@lucene.apache.org


[GitHub] [lucene] tang-hi commented on issue #12458: UTF32toUTF8 can create automata that produce/accept invalid unicode

Posted by "tang-hi (via GitHub)" <gi...@apache.org>.
tang-hi commented on issue #12458:
URL: https://github.com/apache/lucene/issues/12458#issuecomment-1656725544

    I have discovered the bug. 
   ```Java
   if (endUTF8.numBits(upto) == 5) {
           // special case -- avoid created unused edges (endUTF8
           // doesn't accept certain byte sequences) -- there
           // are other cases we could optimize too:
           startCode = 194;
         } else {
           startCode = endUTF8.byteAt(upto) & (~MASKS[endUTF8.numBits(upto) - 1]);
    }
   ```
   In the provided Java code snippet, there is an assumption that the codepoint will start at 0x80 when the number of bits is 6. However, this assumption is incorrect. In reality, when the length of the codepoint is 3 and the first byte is 0xE0, it will start from 0xA0. Similarly, when the length of the codepoint is 4 and the first byte is 0xF0, it will start from 0x90. You can verify this information on the following website: https://www.utf8-chartable.de/unicode-utf8-table.pl
   Here is the PR to fix that #12472 
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org
For additional commands, e-mail: issues-help@lucene.apache.org


[GitHub] [lucene] mikemccand commented on issue #12458: UTF32toUTF8 can create automata that produce/accept invalid unicode

Posted by "mikemccand (via GitHub)" <gi...@apache.org>.
mikemccand commented on issue #12458:
URL: https://github.com/apache/lucene/issues/12458#issuecomment-1653642809

   Hmm curiously the 1 -> 2 byte test case passes:
   
   ```
     public void testUTF8OneToTwoBytes() throws Exception {
       Automaton.Builder b = new Automaton.Builder();
       // start state:
       int s1 = b.createState();
   
       // single end accept state:
       int s2 = b.createState();
       b.setAccept(s2, true);
   
       // add two single-code-point terms: U+65535 and U+65536
       b.addTransition(s1, s2, 127);
       b.addTransition(s1, s2, 128);
   
       Automaton a = b.finish();
   
       CompiledAutomaton c = new CompiledAutomaton(a);
       FiniteStringsIterator it = new FiniteStringsIterator(c.automaton);
       int termCount = 0;
       for (IntsRef r = it.next(); r != null; r = it.next()) {
         termCount++;
       }
       assertEquals(2, termCount);
     }
   ```


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org
For additional commands, e-mail: issues-help@lucene.apache.org


[GitHub] [lucene] mikemccand commented on issue #12458: UTF32toUTF8 can create automata that produce/accept invalid unicode

Posted by "mikemccand (via GitHub)" <gi...@apache.org>.
mikemccand commented on issue #12458:
URL: https://github.com/apache/lucene/issues/12458#issuecomment-1653547413

   Thanks @gsmiller!  What a scary/crazy failure, and it has been lurking for soooo long, I suspect since `UTF32toUTF8` was created.  And thank you randomized testing for finally uncovering this corner case bug.
   
   This likely also occurs for the other UTF-8 byte transitions (1->2, 2->3, 3->4, 1->3, etc.), when they appear in a single UTF-32 transition, hrmph.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org
For additional commands, e-mail: issues-help@lucene.apache.org