Skip to content

Commit 93c9f7e

Browse files
committed
refactor(LlamaBatch): enhance safety checks and fix indexing logic
- Add boundary validation and overflow protection to `__init__`, `set_batch`, and `add_sequence`. - Introduce `capacity()` and `space_left()` for state monitoring and consistency checks. - Fix incorrect logits index calculation in `add_sequence` (using absolute position). - Update error handling (MemoryError) and add docstrings.
1 parent 3716d0a commit 93c9f7e

1 file changed

Lines changed: 59 additions & 8 deletions

File tree

llama_cpp/_internals.py

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -636,18 +636,31 @@ def default_params():
636636

637637
class LlamaBatch:
638638
def __init__(
639-
self, *, n_tokens: int, embd: int, n_seq_max: int, verbose: bool = True
639+
self,
640+
*,
641+
n_tokens: int,
642+
embd: int,
643+
n_seq_max: int,
644+
verbose: bool = True
640645
):
641-
self._n_tokens = n_tokens
646+
# logical validity of parameters
647+
if n_tokens <= 0:
648+
raise ValueError(f"n_tokens must be positive, got {n_tokens}")
649+
if n_seq_max <= 0:
650+
raise ValueError(f"n_seq_max must be positive, got {n_seq_max}")
651+
652+
self.n_tokens_capacity = n_tokens
642653
self.embd = embd
643654
self.n_seq_max = n_seq_max
644655
self.verbose = verbose
645656
self._exit_stack = ExitStack()
646657

647-
batch = llama_cpp.llama_batch_init(self._n_tokens, self.embd, self.n_seq_max)
658+
batch = llama_cpp.llama_batch_init(self.n_tokens_capacity, self.embd, self.n_seq_max)
648659

649660
if batch is None:
650-
raise ValueError("Failed to create llama_batch")
661+
raise MemoryError(
662+
f"Failed to allocate memory for llama_batch via llama_batch_init({n_tokens},{embd},{n_seq_max})"
663+
)
651664

652665
self.batch = batch
653666

@@ -660,18 +673,51 @@ def free_batch():
660673
self._exit_stack.callback(free_batch)
661674

662675
def close(self):
676+
"""Manually free resources."""
663677
self._exit_stack.close()
664678

665679
def __del__(self):
666680
self.close()
667681

668682
def n_tokens(self) -> int:
683+
"""
684+
Current number of tokens stored in the batch.
685+
"""
686+
if self.batch is None: return 0
669687
return self.batch.n_tokens
670688

689+
def capacity(self) -> int:
690+
"""
691+
Total capacity of the batch.
692+
"""
693+
return self.n_tokens_capacity
694+
695+
def space_left(self) -> int:
696+
"""
697+
Returns the number of empty slots remaining in the batch.
698+
Throws a RuntimeError if internal state implies an overflow.
699+
"""
700+
if self.batch is None: return 0
701+
elif self.n_tokens_capacity >= self.batch.n_tokens:
702+
return self.n_tokens_capacity - self.batch.n_tokens
703+
else:
704+
raise RuntimeError(
705+
f"LlamaBatch Critical Error: n_tokens ({self.batch.n_tokens}) exceeds capacity ({self.n_tokens_capacity}). "
706+
"This implies a buffer overflow or corrupted internal state."
707+
)
708+
671709
def reset(self):
672-
self.batch.n_tokens = 0
710+
"""
711+
Resets the batch counter to 0. Does not free memory, just resets the index.
712+
Call this before starting a new decoding step.
713+
"""
714+
if self.batch is not None:
715+
self.batch.n_tokens = 0
673716

674717
def set_batch(self, batch: Sequence[int], n_past: llama_cpp.llama_pos, logits_all: bool):
718+
if len(batch) > self.n_tokens_capacity:
719+
raise IndexError(f"Input batch size {len(batch)} exceeds capacity {self.n_tokens_capacity}")
720+
675721
n_tokens = len(batch)
676722
self.batch.n_tokens = n_tokens
677723
for i in range(n_tokens):
@@ -684,16 +730,21 @@ def set_batch(self, batch: Sequence[int], n_past: llama_cpp.llama_pos, logits_al
684730

685731
def add_sequence(self, batch: Sequence[int], seq_id: int, logits_all: bool):
686732
n_tokens = len(batch)
687-
n_tokens0 = self.batch.n_tokens
733+
current_count = self.batch.n_tokens
734+
if current_count + n_tokens > self.n_tokens_capacity:
735+
raise IndexError(
736+
f"LlamaBatch overflow: Cannot add {n_tokens} tokens. "
737+
f"Space left: {self.n_tokens_capacity - current_count}"
738+
)
688739
self.batch.n_tokens += n_tokens
689740
for i in range(n_tokens):
690-
j = n_tokens0 + i
741+
j = current_count + i
691742
self.batch.token[j] = batch[i]
692743
self.batch.pos[j] = i
693744
self.batch.seq_id[j][0] = seq_id
694745
self.batch.n_seq_id[j] = 1
695746
self.batch.logits[j] = logits_all
696-
self.batch.logits[n_tokens - 1] = True
747+
self.batch.logits[current_count + n_tokens - 1] = True
697748

698749

699750
class LlamaTokenDataArray:

0 commit comments

Comments
 (0)