diff --git a/lightmotif/src/dense.rs b/lightmotif/src/dense.rs
index c3ab0bf78a3c92f95b99a43516fe7db7e8dff5ec..4fe699c9b0490ba0a7e98c6aab4e9d7d64af70a8 100644
--- a/lightmotif/src/dense.rs
+++ b/lightmotif/src/dense.rs
@@ -216,6 +216,7 @@ impl<T: Default + Copy, C: Unsigned, A: Unsigned + PowerOfTwo> Index<usize>
     fn index(&self, index: usize) -> &Self::Output {
         let c = self.stride();
         let row = self.offset + c * index;
+        debug_assert!(row + C::USIZE <= self.data.len());
         &self.data[row..row + C::USIZE]
     }
 }
@@ -227,6 +228,7 @@ impl<T: Default + Copy, C: Unsigned, A: Unsigned + PowerOfTwo> IndexMut<usize>
     fn index_mut(&mut self, index: usize) -> &mut Self::Output {
         let c = self.stride();
         let row = self.offset + c * index;
+        debug_assert!(row + C::USIZE <= self.data.len());
         &mut self.data[row..row + C::USIZE]
     }
 }
@@ -239,6 +241,7 @@ impl<T: Default + Copy, C: Unsigned, A: Unsigned + PowerOfTwo> Index<MatrixCoord
     fn index(&self, index: MatrixCoordinates) -> &Self::Output {
         let c = self.stride();
         let i = self.offset + c * index.row + index.col;
+        debug_assert!(i < self.data.len());
         &self.data[i]
     }
 }
diff --git a/lightmotif/src/pli/mod.rs b/lightmotif/src/pli/mod.rs
index 40685b299dd4730d99d080dd4484079c772c0cfd..297c60a6d940d67d827f3c3f8f2ccaebe3f6121d 100644
--- a/lightmotif/src/pli/mod.rs
+++ b/lightmotif/src/pli/mod.rs
@@ -81,13 +81,13 @@ pub trait Score<A: Alphabet, C: StrictlyPositive> {
         let seq = seq.as_ref();
         let pssm = pssm.as_ref();
 
-        if seq.len() < pssm.len() {
+        if seq.len() < pssm.len() || rows.len() == 0 {
             scores.resize(0, 0);
             return;
         }
 
         // FIXME?
-        scores.resize(rows.len(), seq.len() - pssm.len() + 1);
+        scores.resize(rows.len(), (seq.len() + 1).saturating_sub(pssm.len()));
 
         let result = scores.matrix_mut();
         let matrix = pssm.matrix();
@@ -471,3 +471,38 @@ where
     C: StrictlyPositive + MultipleOf<U16>,
 {
 }
+
+// -- Tests --------------------------------------------------------------------
+
+#[cfg(test)]
+mod test {
+    use std::str::FromStr;
+    use typenum::consts::U4;
+
+    use super::*;
+
+    use crate::abc::Dna;
+    use crate::pwm::CountMatrix;
+
+    #[test]
+    fn test_score_rows_into_empty() {
+        let pli = Pipeline::generic();
+
+        let seq = EncodedSequence::<Dna>::from_str("ATGCA").unwrap();
+        let mut striped = <Pipeline<_, _> as Stripe<Dna, U4>>::stripe(&pli, seq);
+
+        let cm = CountMatrix::<Dna>::from_sequences(
+            ["ATTA", "ATTC"]
+                .iter()
+                .map(|x| EncodedSequence::encode(x).unwrap()),
+        )
+        .unwrap();
+        let pbm = cm.to_freq(0.1);
+        let pwm = pbm.to_weight(None);
+        let pssm = pwm.to_scoring();
+
+        striped.configure(&pssm);
+        let mut scores = StripedScores::empty();
+        pli.score_rows_into(pssm, striped, 1..1, &mut scores);
+    }
+}
diff --git a/lightmotif/src/pli/platform/avx2.rs b/lightmotif/src/pli/platform/avx2.rs
index b8f262cc3056ca5883e310f96c6e312b07c5df16..367c50209273283ef76bf19096fa75db53ce74f1 100644
--- a/lightmotif/src/pli/platform/avx2.rs
+++ b/lightmotif/src/pli/platform/avx2.rs
@@ -105,6 +105,8 @@ unsafe fn score_avx2_permute<A>(
     <<A as Alphabet>::K as IsLessOrEqual<U5>>::Output: NonZero,
 {
     let data = scores.matrix_mut();
+    debug_assert!(data.rows() > 0);
+
     let mut rowptr = data[0].as_mut_ptr();
     // constant vector for comparing unknown bases
     let n = _mm256_set1_epi32(<A as Alphabet>::K::I32 - 1);
@@ -406,7 +408,7 @@ unsafe fn stripe_avx2<A>(
     let mut matrix = std::mem::take(striped).into_matrix();
     matrix.resize(src_stride);
 
-    // Early exit if sequence is too empty (no allocated matrix).
+    // Early exit if sequence is empty (no allocated matrix).
     if length == 0 {
         return;
     }
@@ -637,12 +639,12 @@ impl Avx2 {
             );
         }
 
-        if seq.len() < pssm.len() {
+        if seq.len() < pssm.len() || rows.len() == 0 {
             scores.resize(0, 0);
             return;
         }
 
-        scores.resize(rows.len(), seq.len() - pssm.len() + 1);
+        scores.resize(rows.len(), (seq.len() + 1).saturating_sub(pssm.len()));
         #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
         unsafe {
             score_avx2_permute(pssm, seq, rows, scores)
@@ -672,12 +674,12 @@ impl Avx2 {
             );
         }
 
-        if seq.len() < pssm.len() {
+        if seq.len() < pssm.len() || rows.len() == 0 {
             scores.resize(0, 0);
             return;
         }
 
-        scores.resize(rows.len(), seq.len() - pssm.len() + 1);
+        scores.resize(rows.len(), (seq.len() + 1).saturating_sub(pssm.len()));
         #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
         unsafe {
             score_avx2_gather(pssm, seq, rows, scores)
diff --git a/lightmotif/src/pli/platform/neon.rs b/lightmotif/src/pli/platform/neon.rs
index c7751a152aa6acf96777e2a30641d0756f390314..bc1eb3aba8ac32e225db9b886c364bc8f943e4a9 100644
--- a/lightmotif/src/pli/platform/neon.rs
+++ b/lightmotif/src/pli/platform/neon.rs
@@ -215,12 +215,12 @@ impl Neon {
             );
         }
 
-        if seq.len() < pssm.len() {
+        if seq.len() < pssm.len() || rows.len() == 0 {
             scores.resize(0, 0);
             return;
         }
 
-        scores.resize(rows.len(), seq.len() - pssm.len() + 1);
+        scores.resize(rows.len(), (seq.len() + 1).saturating_sub(pssm.len()));
         #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
         unsafe {
             score_neon(pssm, seq, rows, scores);
diff --git a/lightmotif/src/pli/platform/sse2.rs b/lightmotif/src/pli/platform/sse2.rs
index aca5c3eac26bd0073198be9a7eb497d36bd8890f..92339d50ead2bd4dfea5d38f44f17b57fafdeaac 100644
--- a/lightmotif/src/pli/platform/sse2.rs
+++ b/lightmotif/src/pli/platform/sse2.rs
@@ -205,12 +205,12 @@ impl Sse2 {
             );
         }
 
-        if seq.len() < pssm.len() {
+        if seq.len() < pssm.len() || rows.len() == 0 {
             scores.resize(0, 0);
             return;
         }
 
-        scores.resize(rows.len(), seq.len() - pssm.len() + 1);
+        scores.resize(rows.len(), (seq.len() + 1).saturating_sub(pssm.len()));
         #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
         unsafe {
             score_sse2(pssm, seq, rows, scores);
diff --git a/lightmotif/src/scan.rs b/lightmotif/src/scan.rs
index adb2fe3cd904a33b70ba350c1c20a4be226b97fa..ce4444ea2e45210efa595162d72d307d00286454 100644
--- a/lightmotif/src/scan.rs
+++ b/lightmotif/src/scan.rs
@@ -4,6 +4,8 @@ use super::pli::dispatch::Dispatch;
 use super::pli::platform::Backend;
 use super::pwm::ScoringMatrix;
 use super::seq::StripedSequence;
+use crate::dense::DenseMatrix;
+use crate::num::Unsigned;
 use crate::pli::Maximum;
 use crate::pli::Pipeline;
 use crate::pli::Score;
@@ -141,7 +143,8 @@ where
     fn next(&mut self) -> Option<Self::Item> {
         while self.hits.is_empty() && self.row < self.seq.matrix().rows() {
             let pli = Pipeline::dispatch();
-            let end = (self.row + self.block_size).min(self.seq.matrix().rows() - self.seq.wrap());
+            let end = (self.row + self.block_size)
+                .min(self.seq.matrix().rows().saturating_sub(self.seq.wrap()));
             pli.score_rows_into(&self.pssm, &self.seq, self.row..end, &mut self.scores);
             let matrix = self.scores.matrix();
             for c in pli.threshold(&self.scores, self.threshold) {
diff --git a/lightmotif/src/seq.rs b/lightmotif/src/seq.rs
index 023a1d12b3d1b5392e3f2e6749122b4088ea4c7f..1880de4ba5cd9e6fd9fbefdebe4b4e1de11be495 100644
--- a/lightmotif/src/seq.rs
+++ b/lightmotif/src/seq.rs
@@ -337,6 +337,8 @@ impl<A: Alphabet, C: StrictlyPositive> SymbolCount<A> for &StripedSequence<A, C>
     }
 }
 
+// -- Tests --------------------------------------------------------------------
+
 #[cfg(test)]
 mod test {
     use typenum::consts::U2;