cberner / raptorq

Rust implementation of RaptorQ (RFC6330)
Apache License 2.0
264 stars 47 forks source link

Division by zero #147

Closed rom1v closed 9 months ago

rom1v commented 1 year ago

If I pass a number lower than 64 to Encoder::with_defaults(), then a division by 0 occurs:

diff --git a/examples/main.rs b/examples/main.rs
index 8d5a4c7..75d2d83 100644
--- a/examples/main.rs
+++ b/examples/main.rs
@@ -16,7 +16,7 @@ fn main() {
     }

     // Create the Encoder, with an MTU of 1400 (common for Ethernet)
-    let encoder = Encoder::with_defaults(&data, 1400);
+    let encoder = Encoder::with_defaults(&data, 32);

     // Perform the encoding, and serialize to Vec<u8> for transmission
     let mut packets: Vec<Vec<u8>> = encoder
$ cargo run --example main
   Compiling raptorq v1.7.0 (/home/rom/clone/raptorq)
    Finished dev [unoptimized + debuginfo] target(s) in 0.73s
     Running `target/debug/examples/main`
thread 'main' panicked at 'attempt to calculate the remainder with a divisor of zero', src/util.rs:41:8
stack backtrace:
   0: rust_begin_unwind
             at /rustc/9eb3afe9ebe9c7d2b84b71002d44f4a0edac95e0/library/std/src/panicking.rs:575:5
   1: core::panicking::panic_fmt
             at /rustc/9eb3afe9ebe9c7d2b84b71002d44f4a0edac95e0/library/core/src/panicking.rs:64:14
   2: core::panicking::panic
             at /rustc/9eb3afe9ebe9c7d2b84b71002d44f4a0edac95e0/library/core/src/panicking.rs:114:5
   3: raptorq::util::int_div_ceil
             at ./src/util.rs:41:8
   4: raptorq::base::ObjectTransmissionInformation::generate_encoding_parameters::{{closure}}
             at ./src/base.rs:216:25
   5: raptorq::base::ObjectTransmissionInformation::generate_encoding_parameters
             at ./src/base.rs:224:57
   6: raptorq::base::ObjectTransmissionInformation::with_defaults
             at ./src/base.rs:247:9
   7: raptorq::encoder::Encoder::with_defaults
             at ./src/encoder.rs:144:22
   8: main::main
             at ./examples/main.rs:19:19
   9: core::ops::function::FnOnce::call_once
             at /rustc/9eb3afe9ebe9c7d2b84b71002d44f4a0edac95e0/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

A variable n_max is assigned from the integer division 32 / (8 * 8), which is 0:

https://github.com/cberner/raptorq/blob/92cd14ab12f6907226add0f4ea6bcfc9840c9985/src/base.rs#L212

This n_max is passed as parameter to a closure here:

https://github.com/cberner/raptorq/blob/92cd14ab12f6907226add0f4ea6bcfc9840c9985/src/base.rs#L224

The closure calls int_div_ceil(symbol_size as u64, alignment as u64 * n as u64), so the second parameter is 0:

https://github.com/cberner/raptorq/blob/92cd14ab12f6907226add0f4ea6bcfc9840c9985/src/base.rs#L216

I let you decide what to do to fix the problem (maybe force n_max to be at least 1?).

From a separate project with basically the same code as the example.rs but with Encoder::with_defaults(&data, an_integer_lower_than_64), I get an unreachable code error instead:

$ cargo run
thread 'main' panicked at 'internal error: entered unreachable code', /home/rom/.cargo/registry/src/github.com-1ecc6299db9ec823/raptorq-1.7.0/src/base.rs:205:13
stack backtrace:
   0: rust_begin_unwind
             at /rustc/9eb3afe9ebe9c7d2b84b71002d44f4a0edac95e0/library/std/src/panicking.rs:575:5
   1: core::panicking::panic_fmt
             at /rustc/9eb3afe9ebe9c7d2b84b71002d44f4a0edac95e0/library/core/src/panicking.rs:64:14
   2: core::panicking::panic
             at /rustc/9eb3afe9ebe9c7d2b84b71002d44f4a0edac95e0/library/core/src/panicking.rs:114:5
   3: raptorq::base::ObjectTransmissionInformation::generate_encoding_parameters::{{closure}}
             at /home/rom/.cargo/registry/src/github.com-1ecc6299db9ec823/raptorq-1.7.0/src/base.rs:205:13
   4: raptorq::base::ObjectTransmissionInformation::generate_encoding_parameters
             at /home/rom/.cargo/registry/src/github.com-1ecc6299db9ec823/raptorq-1.7.0/src/base.rs:208:39
   5: raptorq::base::ObjectTransmissionInformation::with_defaults
             at /home/rom/.cargo/registry/src/github.com-1ecc6299db9ec823/raptorq-1.7.0/src/base.rs:231:9
   6: raptorq::encoder::Encoder::with_defaults
             at /home/rom/.cargo/registry/src/github.com-1ecc6299db9ec823/raptorq-1.7.0/src/encoder.rs:136:22
   7: raptorq_sample::main
             at ./src/main.rs:13:19
   8: core::ops::function::FnOnce::call_once
             at /rustc/9eb3afe9ebe9c7d2b84b71002d44f4a0edac95e0/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

I don't know why I can't reproduce this error by running the example from the raptorq project directly.

rom1v commented 1 year ago

It seems the problem exists in the example algorithm from the RFC 6330 section 4.3:

   o  N_max = floor(T/(SS*Al))     // if T < SS*Al, then N_max = 0
   o  for all n=1, ..., N_max      // KL(n) is not defined for n=0
      *  KL(n) is the maximum K' value in Table 2 in Section 5.6 such
         that
            K' <= WS/(Al*(ceil(T/(Al*n))))
   o  Z = ceil(Kt/KL(N_max))       // calls KL(0) if T < SS*Al

In practice, this is not a real problem, since it does not make sense to take such a small value of T, but it should not cause a division by 0.