Uploaded image for project: 'Minecraft: Java Edition'
  1. Minecraft: Java Edition
  2. MC-134892

PacketBuffer.writeString's max length is in bytes, while readString is in characters

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • 1.19 Pre-release 1
    • Minecraft 1.13, Minecraft 18w30a, Minecraft 18w30b, Minecraft 18w31a, Minecraft 1.13.1, Minecraft 1.13.2, 1.14.4, 19w39a, 1.15 Pre-release 6, 1.15.2
    • Confirmed
    • Networking

      This was already partially reported by marcono1234 in this comment, but due to how messy that ticket got it has been separated.

      PacketBuffer.readString performs some special checks to compare against the buffer length:

      public String readString(int maxLength) {
          int i = this.readVarInt();
      
          if (i > maxLength * 4) {
              throw new DecoderException("The received encoded string buffer length is longer than maximum allowed (" + i + " > " + maxLength * 4 + ")");
          } else if (i < 0) {
              throw new DecoderException("The received encoded string buffer length is less than zero! Weird string!");
          } else {
              String s = this.toString(this.readerIndex(), i, StandardCharsets.UTF_8);
              this.readerIndex(this.readerIndex() + i);
      
              if (s.length() > maxLength) {
                  throw new DecoderException("The received string length is longer than maximum allowed (" + i + " > " + maxLength + ")");
              } else {
                  return s;
              }
          }
      }
      

      However, the inverse method only checks the length of the byte array:

      public PacketBuffer writeString(String str, int maxLength) {
          byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
      
          if (bytes.length > maxLength) {
              throw new EncoderException("String too big (was " + bytes.length + " bytes encoded, max " + maxLength + ")");
          } else {
              this.writeVarInt(bytes.length);
              this.writeBytes(bytes);
              return this;
          }
      }
      

      As such, the game refuses to send some strings that would be fine to accept. The logic from the readString should be copied into writeString.

      This is more important in 18w30a, as writeString now takes a max length instead of always using 32767 and this parameter is used for the tab complete packet. Internally, though, it's already caused weird changes as writeChatComponent and readChatComponent now use a max length of 262144; this is 4 times as long as intended for reading. This will also cause more issues in the future if writeString with a length is used in more places (such as serverbound chat), as thus multi-byte strings that were valid before will no longer be valid (for instance, 255 characters of ಠ_ಠ).

            gegy1000 [Mojang] Gegy
            pokechu22 [Mod] Pokechu22
            Votes:
            5 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved:
              CHK: