Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions cups/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ TESTOBJS = \
testoptions.o \
testpwg.o \
testraster.o \
teststring.o \
testtestpage.o \
testthreads.o \
tlscheck.o
Expand Down Expand Up @@ -169,6 +170,7 @@ UNITTARGETS = \
testoptions \
testpwg \
testraster \
teststring \
testtestpage \
testthreads \
tlscheck
Expand Down Expand Up @@ -241,6 +243,9 @@ test: $(UNITTARGETS)
echo Running raster API tests...
./testraster 2>>test.log
./testtestpage 2>>test.log
echo ""
echo Running string API tests...
./teststring 2>>test.log
rm -rf test.log test-debug.log .testssl

fuzz: $(UNITTARGETS)
Expand Down Expand Up @@ -644,6 +649,16 @@ testraster: testraster.o $(LIBCUPS_STATIC)
$(CODE_SIGN) $(CSFLAGS) $@


#
# teststring (dependency on static CUPS library is intentional)
#

teststring: teststring.o $(LIBCUPS_STATIC)
echo Linking $@...
$(CC) $(LDFLAGS) $(OPTIM) -o $@ teststring.o $(LIBCUPS_STATIC) $(LIBS)
$(CODE_SIGN) $(CSFLAGS) $@


#
# testtestpage (dependency on static CUPS library is intentional)
#
Expand Down
24 changes: 17 additions & 7 deletions cups/string.c
Original file line number Diff line number Diff line change
Expand Up @@ -371,18 +371,28 @@ cupsFormatStringv(
case 'c' : // Character or character array
bytes += width;

if (bufptr < bufend)
if (width <= 1)
{
if (width <= 1)
{
*bufptr++ = (char)va_arg(ap, int);
}
else
// Single character - consume the argument even when the buffer is
// full so the remaining arguments stay in sync...
int ch = va_arg(ap, int); // Character

if (bufptr < bufend)
*bufptr++ = (char)ch;
}
else
{
// Character array - consume the argument even when the buffer is
// full so the remaining arguments stay in sync...
const char *cptr = va_arg(ap, char *);
// Character array pointer

if (bufptr < bufend)
{
if ((bufptr + width) > bufend)
width = (int)(bufend - bufptr);

memcpy(bufptr, va_arg(ap, char *), (size_t)width);
memcpy(bufptr, cptr, (size_t)width);
bufptr += width;
}
}
Expand Down
44 changes: 44 additions & 0 deletions cups/teststring.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//
// String API unit test program for CUPS.
//
// Copyright © 2026 by OpenPrinting.
//
// Licensed under Apache License v2.0. See the file "LICENSE" for more
// information.
//

#include "string-private.h"
#include "test-internal.h"
#include "cups.h"


//
// 'main()' - Main entry.
//

int // O - Exit status
main(void)
{
char buffer[64], // Large output buffer
small[2]; // Buffer too small to hold output
ssize_t large_len, // Required length with a large buffer
small_len; // Required length with a small buffer


// Basic formatting...
testBegin("cupsFormatString('%%s %%d')");
large_len = cupsFormatString(buffer, sizeof(buffer), "%s %d", "test", 42);
testEndMessage(large_len == 7 && !strcmp(buffer, "test 42"), "\"%s\"", buffer);

// The returned "bytes needed" value must not depend on the output buffer
// size. A "%c" conversion followed by more arguments used to drop its
// argument when the buffer was already full, so every later argument was
// read from the wrong place (and a following "%s"/"%p" dereferenced a
// non-pointer value).
testBegin("cupsFormatString('%%c') argument sync");
large_len = cupsFormatString(buffer, sizeof(buffer), "X%c%d", 'A', 999999);
small_len = cupsFormatString(small, sizeof(small), "X%c%d", 'A', 999999);
testEndMessage(large_len == small_len, "large=%d small=%d", (int)large_len, (int)small_len);

return (testsPassed ? 0 : 1);
}
Loading