patterncMinor
Space to allocate before sprintf
Viewed 0 times
sprintfbeforespaceallocate
Problem
I just finished chasing a Heisenbug that was entirely my fault. I'd like to avoid it happening again.
I have a function which formats a date to a certain preset format. Turns out I was not allocating enough space:
And yes, the calling function has the duty to free the response.
What I'd like to know is how to avoid having the hardcoded
I have a function which formats a date to a certain preset format. Turns out I was not allocating enough space:
char* FormatDate(DT dateTime)
{
char* formattedDate;
formattedDate = (char*)malloc(
6 //That was my bug, I had 5. For the record, I forgot a comma, not the terminal null...
+ numlen(dateTime.Year)
+ numlen(dateTime.Month)
+ numlen(dateTime.Day)
+ numlen(dateTime.Hour)
+ numlen(dateTime.Minute)
+ numlen(dateTime.Second)
);
sprintf(formattedDate,"%d,%d,%d,%d,%d,%d", dateTime.Year, dateTime.Month, dateTime.Day, dateTime.Hour, dateTime.Minute, dateTime.Second);
return formattedDate;
}numlen calculates the number of characters the number would take if printed in "%d" format.And yes, the calling function has the duty to free the response.
What I'd like to know is how to avoid having the hardcoded
6, which arguably could change. sprintf does return the numbers of characters written, but that's a lot like the chicken and the egg... Is there another approach with pre-allocating that's safe? And not, say allocate a space of 250 just to make sure anything fits.Solution
It appears that if have access to the standard library version of snprintf you can do this:
Original source obtained from StackOverflow
Copied from https://stackoverflow.com/questions/1775403/using-snprintf-to-avoid-buffer-overruns but duplicated to make finding answers quicker.
char* FormatDate(DT dateTime)
{
size_t needed = snprintf(NULL, 0,"%d,%d,%d,%d,%d,%d", dateTime.Year, dateTime.Month, dateTime.Day, dateTime.Hour, dateTime.Minute, dateTime.Second);
char* formattedDate = (char*)malloc(needed);
snprintf(formattedDate, needed,"%d,%d,%d,%d,%d,%d", dateTime.Year, dateTime.Month, dateTime.Day, dateTime.Hour, dateTime.Minute, dateTime.Second);
return formattedDate;
}Original source obtained from StackOverflow
char* get_error_message(char const *msg) {
size_t needed = snprintf(NULL, 0, "%s: %s (%d)", msg, strerror(errno), errno);
char *buffer = malloc(needed);
snprintf(buffer, needed, "%s: %s (%d)", msg, strerror(errno), errno);
return buffer;
}Copied from https://stackoverflow.com/questions/1775403/using-snprintf-to-avoid-buffer-overruns but duplicated to make finding answers quicker.
Code Snippets
char* FormatDate(DT dateTime)
{
size_t needed = snprintf(NULL, 0,"%d,%d,%d,%d,%d,%d", dateTime.Year, dateTime.Month, dateTime.Day, dateTime.Hour, dateTime.Minute, dateTime.Second);
char* formattedDate = (char*)malloc(needed);
snprintf(formattedDate, needed,"%d,%d,%d,%d,%d,%d", dateTime.Year, dateTime.Month, dateTime.Day, dateTime.Hour, dateTime.Minute, dateTime.Second);
return formattedDate;
}char* get_error_message(char const *msg) {
size_t needed = snprintf(NULL, 0, "%s: %s (%d)", msg, strerror(errno), errno);
char *buffer = malloc(needed);
snprintf(buffer, needed, "%s: %s (%d)", msg, strerror(errno), errno);
return buffer;
}Context
StackExchange Code Review Q#8341, answer score: 3
Revisions (0)
No revisions yet.