Tcl Source Code

View Ticket
Login
Ticket UUID: 13d3c0d764fa4cf1c0cf0577924d7a0be5a3fd2b
Title: lset on empty list is allowed when index argument is large
Type: Bug Created on: 2023-08-13 15:47:58
Submitter: apnadkarni Assigned to: jan.nijtmans
Subsystem: - New Builtin Commands Severity: Minor
Priority: 5 Medium Last modified: 2026-11-01 16:58:39
Status: Closed Closed by: dkf
Resolution: Fixed Closed on: 2026-11-01 16:58:39
Version: 9.0.5, 9.1.0
Description:

lset is supposed to only allow setting of elements for out of bounds indices when the specified index is just after the last valid index (i.e. equal to list length). However consider

% set L {}
% lset L 0x7ffffffffffffffe X
index "0x7ffffffffffffffe" out of range
% lset L 0x7fffffffffffffff X
X
% lset L 0x7fffffffffffffff X
index "0x7fffffffffffffff" out of range

When the list is empty, the index 0x7fffffffffffffff (or higher) is incorrectly treated as index 0 (i.e. just beyond last valid index). As the first line shows, smaller out of bounds indices are treated correctly. As the last line shows, this bug only occurs when the list is empty.

Like bug bc076f4f0e, this bug was also introduced by commit 0b05b5c750df intended to fix TIP 577 issues in Tk.

While this issue may be considered relatively minor, it points to what I think is a fundamental flaw in internal index encoding in Tcl: the number of values that need to be represented in an "index" are greater than the range of the index type, no matter whether 32- or 64-bits. This is due to non-negative integers being valid (for obvious reasons), negative integers being valid (as end-N) representation, which together occupy the entire domain. Then there is a need for additional values representing "end" and "one beyond end" for which there is no room necessitating hacks like this which is the cause of the above bug. Removing that hack will cause lset to fail on

set L {} ; lset L 0 X

which should be allowed. Changing the core indexing routines to fix this breaks Tk indexing for negative (in the C API) and end relative indices.

Given the above limitation in range of values I see no way around this other than living with the above bug for 9.0. If I am wrong and anyone has a solution, please verify it works with both Tk and the bigdata tests for large indices.

User Comments:
serhiy.storchaka added on 2026-10-17 16:03:05:

The ambiguity can be resolved locally in TclLsetFlat(), without changing the index encoding (so Tk is not affected): when the list is empty and the index comes back as TCL_SIZE_MAX, evaluate it again as if the list had one element, and accept it only if this gives 1 (end+1 and similar forms). Proposed fix in branch lset-empty-huge-index, tests lset-18.1 to lset-18.5. 8.6 is not affected.