| Patch Notes: |
| ============ |
| [Bug 546045] MQTT Decoding of remaining length (https://bugs.eclipse.org/bugs/show_bug.cgi?id=546045) |
| |
| Issue: |
| In the MQTT v3.1.1 specification section 2.2.3 [1] the description of the variable length encoding states, that the remaining length can be encoded with up to 4 bytes. However, the shown decoding algorithm (non-normative comment) fails to decode all remaining lengths which are encoded with 4 bytes (all above 2097151B respectively 0xFF 0xFF 0x7F). |
| |
| |
| Example: |
| ======== |
| For example, the smallest remaining length which is encoded with 4 bytes according to Table 2.4 in [1] is 2097152. Let's examine this case with the given algorithm. |
| |
| >> Pre condition: |
| let input_encoded_bytes[4] = [0x80, 0x80, 0x80, 0x01] // -> as ui32 = 2097152 |
| let multiplier = 1 |
| let value = 0 |
| |
| >> Iteration 1: |
| let encoded_byte = 0x80 |
| value = 0 + (encoded_byte AND 0x7F) * 1 // => value = 0 |
| multiplier = 1 * 128 |
| if (multiplier > 128 * 128 * 128) { throw Error } // no Error |
| |
| >> Iteration 2: [(encoded_byte AND 0x80) != 0] |
| let encoded_byte = 0x80 |
| value = 0 + (encoded_byte AND 0x7F) * 128 // => value = 0 |
| multiplier = 128 * 128 |
| if (multiplier > 128 * 128 * 128) { throw Error } // no Error |
| |
| >> Iteration 3: [(encoded_byte AND 0x80) != 0] |
| let encoded_byte = 0x80 |
| value = 0 + (encoded_byte AND 0x7F) * 128 * 128 // => value = 0 |
| multiplier = 128 * 128 * 128 |
| if (multiplier > 128 * 128 * 128) { throw Error } // no Error |
| |
| >> Iteration 4: [(encoded_byte AND 0x80) != 0] |
| let encoded_byte = 0x01 |
| value = 0 + (encoded_byte AND 0x7F) * 128 * 128 * 128 // => value = 2097152 |
| multiplier = 128 * 128 * 128 * 128 |
| if (multiplier > 128 * 128 * 128) { throw Error } // Error! |
| |
| As one can see, although the value is correctly decoded, the algorithm throws an error after decoding the 4th byte. |
| |
| |
| Solution: |
| ========= |
| The MQTT v5 specification provides in [2] a small bugfix for this algorithm. This fix affects only the 4th iteration from the previous example. |
| |
| >> Iteration 4 (fixed): [(encoded_byte AND 0x80) != 0] |
| let encoded_byte = 0x01 |
| value = 0 + (encoded_byte AND 0x7F) * 128 * 128 * 128 // => value = 2097152 |
| if (multiplier > 128 * 128 * 128) { throw Error } // no Error |
| multiplier = 128 * 128 * 128 * 128 |
| if ((encoded_byte AND 0x80) != 0) { end of do-while loop } // correctly terminated decoding with value = 2097152 |
| |
| |
| [1] http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718023 |
| [2] http://docs.oasis-open.org/mqtt/mqtt/v5.0/csprd01/mqtt-v5.0-csprd01.html#_Toc489530042 |