* Fixed the semantics of [v]snprintf(): If the buffer is not large enough,

the function shall nevertheless return the length of the string that would
  be written, if the buffer were large enough.
  Added a touch of C++ while doing that. :-)
* Fixed the instances in boot loader, kernel, and kernel modules where the
  wrong semantics were expected. The majority of uses actually.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34826 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2009-12-30 15:17:09 +00:00
parent 3069ca963e
commit 3ce2634533
12 changed files with 199 additions and 180 deletions

View File

@ -7,6 +7,8 @@
#include <stdarg.h>
#include <algorithm>
static char sTraceBuffer[256];
static uint32 sTraceBufferOffset = 0;
@ -15,11 +17,15 @@ static uint32 sTraceBufferOffset = 0;
void
ata_trace_printf(uint32 flags, const char *format, ...)
{
va_list arguments;
va_start(arguments, format);
sTraceBufferOffset += vsnprintf(sTraceBuffer + sTraceBufferOffset,
sizeof(sTraceBuffer) - sTraceBufferOffset, format, arguments);
va_end(arguments);
if (sTraceBufferOffset < sizeof(sTraceBuffer)) {
va_list arguments;
va_start(arguments, format);
size_t totalBytes = vsnprintf(sTraceBuffer + sTraceBufferOffset,
sizeof(sTraceBuffer) - sTraceBufferOffset, format, arguments);
sTraceBufferOffset += std::min(totalBytes,
sizeof(sTraceBuffer) - sTraceBufferOffset - 1);
va_end(arguments);
}
if (flags & ATA_TRACE_FLUSH) {
#if ATA_TRACING

View File

@ -7,9 +7,13 @@
* Niels S. Reedijk
*/
#include "usb_p.h"
#include <stdio.h>
#include <algorithm>
Hub::Hub(Object *parent, int8 hubAddress, uint8 hubPort,
usb_device_descriptor &desc, int8 deviceAddress, usb_speed speed,
@ -386,18 +390,30 @@ Hub::BuildDeviceName(char *string, uint32 *index, size_t bufferSize,
status_t result = Device::BuildDeviceName(string, index, bufferSize, device);
if (result < B_OK) {
// recursion to parent failed, we're at the root(hub)
int32 managerIndex = GetStack()->IndexOfBusManager(GetBusManager());
*index += snprintf(string + *index, bufferSize - *index, "%ld", managerIndex);
if (*index < bufferSize) {
int32 managerIndex = GetStack()->IndexOfBusManager(GetBusManager());
size_t totalBytes = snprintf(string + *index, bufferSize - *index,
"%ld", managerIndex);
*index += std::min(totalBytes, bufferSize - *index - 1);
}
}
if (!device) {
// no device was specified - report the hub
*index += snprintf(string + *index, bufferSize - *index, "/hub");
if (*index < bufferSize) {
size_t totalBytes = snprintf(string + *index, bufferSize - *index,
"/hub");
*index += std::min(totalBytes, bufferSize - *index - 1);
}
} else {
// find out where the requested device sitts
for (int32 i = 0; i < fHubDescriptor.num_ports; i++) {
if (fChildren[i] == device) {
*index += snprintf(string + *index, bufferSize - *index, "/%ld", i);
if (*index < bufferSize) {
size_t totalBytes = snprintf(string + *index,
bufferSize - *index, "/%ld", i);
*index += std::min(totalBytes, bufferSize - *index - 1);
}
break;
}
}

View File

@ -276,6 +276,7 @@ log_writer_daemon(void *arg, int /*iteration*/)
log->team, log->timestamp, log->team_name,
log->device, log->parent, log->launch.parent,
log->launch.args[0]);
length = std::min(length, (ssize_t)sizeof(line) - 1);
for (int32 j = 1; j < log->launch.arg_count; j++) {
// write argument list one by one, so that we can deal
@ -302,12 +303,14 @@ log_writer_daemon(void *arg, int /*iteration*/)
length = snprintf(line, sizeof(line), "%ld: %Ld \"%s\" c%d %ld:%Ld %ld\n",
log->team, log->timestamp, log->team_name, log->type,
log->device, log->node, log->access_type);
length = std::min(length, (ssize_t)sizeof(line) - 1);
break;
default: // open, ?
length = snprintf(line, sizeof(line), "%ld: %Ld \"%s\" %c%d %ld:%Ld:%Ld:\"%s\"\n",
log->team, log->timestamp, log->team_name, log->action, log->type, log->device,
log->parent, log->node, log->file_name);
length = std::min(length, (ssize_t)sizeof(line) - 1);
break;
}

View File

@ -9,6 +9,8 @@
#include "RootFileSystem.h"
#include "load_driver_settings.h"
#include <algorithm>
#include <OS.h>
#include <util/kernel_cpp.h>
@ -503,8 +505,9 @@ apply_safe_mode_options(Menu *menu)
|| item->Data() == NULL || (uint32)pos > sizeof(buffer))
continue;
pos += snprintf(buffer + pos, sizeof(buffer) - pos, "%s true\n",
(const char *)item->Data());
size_t totalBytes = snprintf(buffer + pos, sizeof(buffer) - pos,
"%s true\n", (const char *)item->Data());
pos += std::min(totalBytes, sizeof(buffer) - pos - 1);
}
add_safe_mode_settings(buffer);

View File

@ -11,6 +11,9 @@
#include <stdarg.h>
#include <string.h>
#include <algorithm>
//#undef stdout
//#undef stdin
//extern FILE *stdout;
@ -28,6 +31,7 @@ vfprintf(FILE *file, const char *format, va_list list)
// the buffer handling could (or should) be done better...
int length = vsnprintf(buffer, sizeof(buffer), format, list);
length = std::min(length, (int)sizeof(buffer) - 1);
if (length > 0)
node->Write(buffer, length);
@ -77,7 +81,7 @@ fputc(int c, FILE *file)
status_t status;
char character = (char)c;
// we only support direct console output right now...
// we only support direct console output right now...
status = ((ConsoleNode *)file)->Write(&character, 1);
if (status > 0)

View File

@ -21,7 +21,6 @@ panic(const char *format, ...)
const char greetings[] = "\n*** PANIC ***";
char buffer[512];
va_list list;
int length;
//platform_switch_to_text_mode();
@ -31,7 +30,7 @@ panic(const char *format, ...)
nat_feat_debugprintf("\n");
va_start(list, format);
length = vsnprintf(buffer, sizeof(buffer), format, list);
vsnprintf(buffer, sizeof(buffer), format, list);
va_end(list);
Bconputs(DEV_CONSOLE, buffer);
@ -52,10 +51,9 @@ dprintf(const char *format, ...)
{
char buffer[512];
va_list list;
int length;
va_start(list, format);
length = vsnprintf(buffer, sizeof(buffer), format, list);
vsnprintf(buffer, sizeof(buffer), format, list);
va_end(list);
Bconput(DEV_AUX, buffer);

View File

@ -46,6 +46,9 @@ dprintf(const char *format, ...)
length = vsnprintf(buffer, sizeof(buffer), format, list);
va_end(list);
if (length >= (int)sizeof(buffer))
length = sizeof(buffer) - 1;
serial_puts(buffer, length);
if (platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT)

View File

@ -46,6 +46,9 @@ dprintf(const char *format, ...)
length = vsnprintf(buffer, sizeof(buffer), format, list);
va_end(list);
if (length >= (int)sizeof(buffer))
length = sizeof(buffer) - 1;
serial_puts(buffer, length);
if (platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT)

View File

@ -1169,7 +1169,8 @@ syslog_init(struct kernel_args* args)
length = snprintf(revisionBuffer, sizeof(revisionBuffer),
"Welcome to syslog debug output!\nHaiku revision: %lu\n",
get_haiku_revision());
syslog_write(revisionBuffer, length);
syslog_write(revisionBuffer,
std::min(length, (ssize_t)sizeof(revisionBuffer) - 1));
add_debugger_command_etc("syslog", &cmd_dump_syslog,
"Dumps the syslog buffer.",
@ -1267,6 +1268,7 @@ flush_pending_repeats(bool syslogOutput)
static char temp[40];
size_t length = snprintf(temp, sizeof(temp),
"Last message repeated %ld times.\n", sMessageRepeatCount);
length = std::min(length, sizeof(temp) - 1);
if (sSerialDebugEnabled)
arch_debug_serial_puts(temp);
@ -1328,8 +1330,9 @@ dprintf_args(const char* format, va_list args, bool syslogOutput)
if (are_interrupts_enabled()) {
MutexLocker locker(sOutputLock);
int32 length = vsnprintf(sOutputBuffer, OUTPUT_BUFFER_SIZE,
format, args);
int32 length = vsnprintf(sOutputBuffer, OUTPUT_BUFFER_SIZE, format,
args);
length = std::min(length, (int32)OUTPUT_BUFFER_SIZE - 1);
InterruptsSpinLocker _(sSpinlock);
debug_output(sOutputBuffer, length, syslogOutput);
@ -1338,6 +1341,7 @@ dprintf_args(const char* format, va_list args, bool syslogOutput)
int32 length = vsnprintf(sInterruptOutputBuffer, OUTPUT_BUFFER_SIZE,
format, args);
length = std::min(length, (int32)OUTPUT_BUFFER_SIZE - 1);
debug_output(sInterruptOutputBuffer, length, syslogOutput);
}

View File

@ -7,12 +7,15 @@
* Distributed under the terms of the NewOS License.
*/
#include "debug_commands.h"
#include <setjmp.h>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <KernelExport.h>
#include <debug.h>
@ -111,8 +114,12 @@ public:
return;
// print directly into the buffer
fBufferSize += vsnprintf(fBuffer + fBufferSize,
fBufferCapacity - fBufferSize, format, args);
if (fBufferSize < fBufferCapacity) {
size_t totalBytes = vsnprintf(fBuffer + fBufferSize,
fBufferCapacity - fBufferSize, format, args);
fBufferSize += std::min(totalBytes,
fBufferCapacity - fBufferSize - 1);
}
// execute every complete line
fBuffer[fBufferSize] = '\0';

View File

@ -10,6 +10,8 @@
#include <stdarg.h>
#include <stdlib.h>
#include <algorithm>
#include <arch/debug.h>
#include <debug.h>
#include <elf.h>
@ -596,10 +598,14 @@ TraceOutput::Print(const char* format,...)
if (IsFull())
return;
va_list args;
va_start(args, format);
fSize += vsnprintf(fBuffer + fSize, fCapacity - fSize, format, args);
va_end(args);
if (fSize < fCapacity) {
va_list args;
va_start(args, format);
size_t length = vsnprintf(fBuffer + fSize, fCapacity - fSize, format,
args);
fSize += std::min(length, fCapacity - fSize - 1);
va_end(args);
}
#endif
}

View File

@ -1,4 +1,5 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2003-2008, Axel Dörfler. All rights reserved.
* Distributed under the terms of the MIT license.
*
@ -9,10 +10,12 @@
#include <SupportDefs.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define ZEROPAD 1 /* pad with zero */
@ -26,6 +29,73 @@
#define FLOATING_SUPPORT
struct Buffer {
Buffer(char* buffer, size_t size)
:
fCurrent(buffer),
fSize(size),
fBytesWritten(0)
{
}
size_t BytesWritten() const
{
return fBytesWritten;
}
void PutCharacter(char c)
{
if (fBytesWritten < fSize) {
*fCurrent = c;
fCurrent++;
}
fBytesWritten++;
}
void PutPadding(int32 count)
{
if (count <= 0)
return;
if (fBytesWritten < fSize) {
int32 toWrite = std::min(fSize - fBytesWritten, (size_t)count);
while (--toWrite >= 0)
*fCurrent++ = ' ';
}
fBytesWritten += count;
}
void PutString(const char *source, int32 length)
{
if (length <= 0)
return;
if (fBytesWritten < fSize) {
int32 toWrite = std::min(fSize - fBytesWritten, (size_t)length);
memcpy(fCurrent, source, toWrite);
fCurrent += toWrite;
}
fBytesWritten += length;
}
void NullTerminate()
{
if (fBytesWritten < fSize)
*fCurrent = '\0';
else if (fSize > 0)
fCurrent[-1] = '\0';
}
private:
char* fCurrent;
size_t fSize;
size_t fBytesWritten;
};
static int
skip_atoi(const char **s)
{
@ -48,88 +118,6 @@ do_div(uint64 *_number, uint32 base)
}
static bool
put_padding(char **_buffer, int32 *_bytesLeft, int32 count)
{
int32 left = *_bytesLeft;
char *string = *_buffer;
int32 written;
bool allWritten;
if (count <= 0)
return true;
if (left == 0)
return false;
if (left < count) {
count = left;
allWritten = false;
} else
allWritten = true;
written = count;
while (count-- > 0)
*string++ = ' ';
*_buffer = string;
*_bytesLeft = left - written;
return allWritten;
}
static inline bool
put_string(char **_buffer, int32 *_bytesLeft, const char *source, int32 length)
{
int32 left = *_bytesLeft;
char *target = *_buffer;
bool allWritten;
if (length == 0)
return true;
if (left == 0)
return false;
if (left < length) {
length = left;
allWritten = false;
} else
allWritten = true;
#if 0
// take care of string arguments in user space
if (CHECK_USER_ADDRESS(source)) {
if (user_memcpy(target, source, length) < B_OK)
return put_string(_buffer, _bytesLeft, "<FAULT>", 7);
} else
#endif
memcpy(target, source, length);
*_bytesLeft = left - length;
*_buffer = target + length;
return allWritten;
}
static inline bool
put_character(char **_buffer, int32 *_bytesLeft, char c)
{
int32 left = *_bytesLeft;
char *string = *_buffer;
if (left > 0) {
*string++ = c;
*_buffer = string;
*_bytesLeft = left - 1;
return true;
}
return false;
}
static char
sign_symbol(int flags, bool negative)
{
@ -148,7 +136,7 @@ sign_symbol(int flags, bool negative)
static void
number(char **_string, int32 *_bytesLeft, uint64 num, uint32 base, int size,
number(Buffer& outBuffer, uint64 num, uint32 base, int size,
int precision, int flags)
{
const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz";
@ -191,31 +179,31 @@ number(char **_string, int32 *_bytesLeft, uint64 num, uint32 base, int size,
size -= precision;
if (!(flags & (ZEROPAD + LEFT))) {
put_padding(_string, _bytesLeft, size);
outBuffer.PutPadding(size);
size = 0;
}
if (sign)
put_character(_string, _bytesLeft, sign);
outBuffer.PutCharacter(sign);
if ((flags & SPECIAL) != 0) {
if (base == 8)
put_character(_string, _bytesLeft, '0');
outBuffer.PutCharacter('0');
else if (base == 16) {
put_character(_string, _bytesLeft, '0');
put_character(_string, _bytesLeft, digits[33]);
outBuffer.PutCharacter('0');
outBuffer.PutCharacter(digits[33]);
}
}
if (!(flags & LEFT)) {
while (size-- > 0)
put_character(_string, _bytesLeft, c);
outBuffer.PutCharacter(c);
}
while (i < precision--)
put_character(_string, _bytesLeft, '0');
outBuffer.PutCharacter('0');
while (i-- > 0)
put_character(_string, _bytesLeft, tmp[i]);
outBuffer.PutCharacter(tmp[i]);
put_padding(_string, _bytesLeft, size);
outBuffer.PutPadding(size);
}
@ -225,9 +213,8 @@ number(char **_string, int32 *_bytesLeft, uint64 num, uint32 base, int size,
It prints up to 3 fraction digits, and doesn't support any precision arguments.
It's just here for your convenience so that you can use it for debug output.
*/
static bool
floating(char **_string, int32 *_bytesLeft, double value, int fieldWidth,
int flags)
static void
floating(Buffer& outBuffer, double value, int fieldWidth, int flags)
{
char buffer[66];
uint64 fraction;
@ -259,29 +246,26 @@ floating(char **_string, int32 *_bytesLeft, double value, int fieldWidth,
// put integer part
if (integer == 0)
if (integer == 0) {
buffer[length++] = '0';
else while (integer != 0) {
buffer[length++] = '0' + do_div(&integer, 10);
} else {
while (integer != 0)
buffer[length++] = '0' + do_div(&integer, 10);
}
// write back to string
if (!(flags & LEFT) && !put_padding(_string, _bytesLeft, fieldWidth))
return false;
if (!(flags & LEFT))
outBuffer.PutPadding(fieldWidth);
if (sign && !put_character(_string, _bytesLeft, sign))
return false;
if (sign)
outBuffer.PutCharacter(sign);
while (length-- > 0) {
if (!put_character(_string, _bytesLeft, buffer[length]))
return false;
}
while (length-- > 0)
outBuffer.PutCharacter(buffer[length]);
if ((flags & LEFT) != 0 && !put_padding(_string, _bytesLeft, fieldWidth))
return false;
return true;
if ((flags & LEFT) != 0)
outBuffer.PutPadding(fieldWidth);
}
#endif // FLOATING_SUPPORT
@ -289,28 +273,19 @@ floating(char **_string, int32 *_bytesLeft, double value, int fieldWidth,
int
vsnprintf(char *buffer, size_t bufferSize, const char *format, va_list args)
{
int32 bytesLeft;
uint64 num;
int base;
char *string;
int flags; /* flags to number() */
int fieldWidth; /* width of output field */
int precision;
/* min. # of digits for integers; max number of chars for from string */
int qualifier; /* 'h', 'l', or 'L' for integer fields */
if (bufferSize == 0)
return 0;
Buffer outBuffer(buffer, bufferSize);
bytesLeft = ((int32)bufferSize - 1) & 0x7fffffff;
// make space for the terminating '\0' byte, and we
// only allow 2G characters :)
for (string = buffer; format[0] && bytesLeft > 0; format++) {
for (; format[0]; format++) {
if (format[0] != '%') {
if (!put_character(&string, &bytesLeft, format[0]))
break;
outBuffer.PutCharacter(format[0]);
continue;
}
@ -329,8 +304,7 @@ vsnprintf(char *buffer, size_t bufferSize, const char *format, va_list args)
case '0': flags |= ZEROPAD; goto repeat;
case '%':
if (!put_character(&string, &bytesLeft, format[0]))
break;
outBuffer.PutCharacter(format[0]);
continue;
}
@ -384,15 +358,13 @@ vsnprintf(char *buffer, size_t bufferSize, const char *format, va_list args)
switch (format[0]) {
case 'c':
if (!(flags & LEFT) && !put_padding(&string, &bytesLeft,
fieldWidth - 1))
goto out;
if (!(flags & LEFT))
outBuffer.PutPadding(fieldWidth - 1);
put_character(&string, &bytesLeft, (char)va_arg(args, int));
outBuffer.PutCharacter((char)va_arg(args, int));
if ((flags & LEFT) != 0 && !put_padding(&string, &bytesLeft,
fieldWidth - 1))
goto out;
if ((flags & LEFT) != 0)
outBuffer.PutPadding(fieldWidth - 1);
continue;
case 's':
@ -406,16 +378,13 @@ vsnprintf(char *buffer, size_t bufferSize, const char *format, va_list args)
length = strnlen(argument, precision);
fieldWidth -= length;
if (!(flags & LEFT) && !put_padding(&string, &bytesLeft,
fieldWidth))
goto out;
if (!(flags & LEFT))
outBuffer.PutPadding(fieldWidth);
if (!put_string(&string, &bytesLeft, argument, length))
goto out;
outBuffer.PutString(argument, length);
if ((flags & LEFT) != 0 && !put_padding(&string, &bytesLeft,
fieldWidth))
goto out;
if ((flags & LEFT) != 0)
outBuffer.PutPadding(fieldWidth);
continue;
}
@ -426,9 +395,7 @@ vsnprintf(char *buffer, size_t bufferSize, const char *format, va_list args)
case 'G':
{
double value = va_arg(args, double);
if (!floating(&string, &bytesLeft, value, fieldWidth,
flags | SIGN))
goto out;
floating(outBuffer, value, fieldWidth, flags | SIGN);
continue;
}
#endif // FLOATING_SUPPORT
@ -439,19 +406,18 @@ vsnprintf(char *buffer, size_t bufferSize, const char *format, va_list args)
flags |= ZEROPAD;
}
if (!put_string(&string, &bytesLeft, "0x", 2))
goto out;
number(&string, &bytesLeft, (uint32)va_arg(args, void *), 16,
fieldWidth, precision, flags);
outBuffer.PutString("0x", 2);
number(outBuffer, (uint32)va_arg(args, void *), 16, fieldWidth,
precision, flags);
continue;
case 'n':
if (qualifier == 'l') {
long *ip = va_arg(args, long *);
*ip = (string - buffer);
*ip = outBuffer.BytesWritten();
} else {
int *ip = va_arg(args, int *);
*ip = (string - buffer);
*ip = outBuffer.BytesWritten();
}
continue;
@ -474,12 +440,12 @@ vsnprintf(char *buffer, size_t bufferSize, const char *format, va_list args)
default:
if (format[0] != '%')
put_character(&string, &bytesLeft, '%');
outBuffer.PutCharacter('%');
if (!format[0])
goto out;
put_character(&string, &bytesLeft, format[0]);
outBuffer.PutCharacter(format[0]);
continue;
}
@ -498,12 +464,12 @@ vsnprintf(char *buffer, size_t bufferSize, const char *format, va_list args)
else
num = va_arg(args, unsigned int);
number(&string, &bytesLeft, num, base, fieldWidth, precision, flags);
number(outBuffer, num, base, fieldWidth, precision, flags);
}
out:
*string = '\0';
return string - buffer;
outBuffer.NullTerminate();
return outBuffer.BytesWritten();
}