worksheet: fix uint8_t counter overflow in validation list functions

_validation_list_length used uint8_t for its loop counter and exited
early once the running total hit LXW_VALIDATION_MAX_STRING_LENGTH (255).
For a list of 256 single-char items this caused the function to return 255
instead of the true total of 511, so the caller's "> 255" guard passed and
_validation_list_to_csv was invoked.

_validation_list_to_csv also used uint8_t for its counter.  After
processing 255 items the counter wrapped to 0, making the loop infinite
and overflowing the 1023-byte heap buffer allocated for the CSV string.

Fix both counters to size_t.  Remove the early-exit length guard from
_validation_list_length so it always returns the actual combined length;
this lets the existing caller check reject oversized lists before
_validation_list_to_csv is ever reached.

Add test validation_list_256_items_rejected: 256 single-char items have
a true CSV length of 511 chars, which must be rejected with
LXW_ERROR_255_STRING_LENGTH_EXCEEDED.  Without the fix the process hangs
or crashes due to the infinite loop and resulting heap overflow.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Bill Denney 2026-04-05 18:35:44 +00:00
parent 2894634d65
commit 88a44a9ffa
2 changed files with 54 additions and 3 deletions

View file

@ -1492,13 +1492,13 @@ lxw_basename(const char *path)
size_t
_validation_list_length(const char **list)
{
uint8_t i = 0;
size_t i = 0;
size_t length = 0;
if (!list || !list[0])
return 0;
while (list[i] && length < LXW_VALIDATION_MAX_STRING_LENGTH) {
while (list[i]) {
/* Include commas in the length. */
length += 1 + lxw_utf8_strlen(list[i]);
i++;
@ -1515,7 +1515,7 @@ _validation_list_length(const char **list)
char *
_validation_list_to_csv(const char **list)
{
uint8_t i = 0;
size_t i = 0;
char *str;
/* Create a buffer for the concatenated, and quoted, string. */

View file

@ -0,0 +1,51 @@
/*
* Tests for the lib_xlsx_writer library.
*
* SPDX-License-Identifier: BSD-2-Clause
* Copyright 2014-2026, John McNamara, jmcnamara@cpan.org.
*
*/
#include "../ctest.h"
#include "../helper.h"
#include "../../../include/xlsxwriter/worksheet.h"
/*
* Test that a validation list with 256 single-char items is rejected.
*
* The combined CSV string (items + commas) is 511 characters, which exceeds
* Excel's limit of 255. Before the fix, _validation_list_length used uint8_t
* for its loop counter and exited early once the running total reached 255,
* returning 255 for lists well beyond that limit. The caller accepted 255 as
* within bounds and called _validation_list_to_csv, which also used uint8_t.
* After processing 255 items the counter wrapped to 0, making the loop
* infinite and overflowing the 1023-byte heap buffer.
*/
CTEST(worksheet, validation_list_256_items_rejected) {
const char *list[257];
char items[256][2];
int i;
for (i = 0; i < 256; i++) {
items[i][0] = 'a' + (i % 26);
items[i][1] = '\0';
list[i] = items[i];
}
list[256] = NULL;
lxw_data_validation *data_validation = calloc(1, sizeof(lxw_data_validation));
data_validation->validate = LXW_VALIDATION_TYPE_LIST;
data_validation->value_list = (const char **) list;
lxw_worksheet *worksheet = lxw_worksheet_new(NULL);
FILE *testfile = lxw_tmpfile(NULL);
worksheet->file = testfile;
int err = worksheet_data_validation_cell(worksheet, 0, 0, data_validation);
ASSERT_EQUAL(LXW_ERROR_255_STRING_LENGTH_EXCEEDED, err);
free(data_validation);
lxw_worksheet_free(worksheet);
fclose(testfile);
}