@@ -188,18 +188,26 @@ void unpack_width(const uint8_t* in, UnpackedUInt* out, int batch_size, int bit_
188188 return unpack_full (in, out, batch_size);
189189 } else {
190190 using UnpackerForWidth = Unpacker<UnpackedUInt, kPackedBitWidth >;
191+ // Number of values extracted by one iteration of the kernel
191192 constexpr auto kValuesUnpacked = UnpackerForWidth::kValuesUnpacked ;
193+ // Number of bytes read, but not necessarily unpacked, by one iteration of the
194+ // kernel. This constant prevent reading past buffer end.
192195 constexpr auto kBytesRead = UnpackerForWidth::kBytesRead ;
193196
194197 if constexpr (kValuesUnpacked > 0 ) {
195- const uint8_t * last_in =
196- in + bit_util::CeilDiv (batch_size * kPackedBitWidth , 8 ) - kBytesRead ;
198+ const uint8_t * in_end = in + bit_util::CeilDiv (batch_size * kPackedBitWidth , 8 );
199+ const uint8_t * in_last = in_end - kBytesRead ;
197200 // Running the optimized kernel for batch extraction
198- while ((batch_size > kValuesUnpacked ) && (in <= last_in )) {
201+ while ((batch_size >= kValuesUnpacked ) && (in <= in_last )) {
199202 in = UnpackerForWidth::unpack (in, out);
200203 out += kValuesUnpacked ;
201204 batch_size -= kValuesUnpacked ;
202205 }
206+
207+ // Performance check aking sure we ran the kernel loop as much as possible:
208+ // Either we ran out because we could not pack enough values, or because we would
209+ // overread.
210+ ARROW_DCHECK ((batch_size < kValuesUnpacked ) || (in_end - in) < kBytesRead );
203211 }
204212
205213 // Running the epilog for the remaining values that don't fit in a kernel
0 commit comments