| Summary: | The function sprintf in libc copies more characters than the format specification dictates | ||||||
|---|---|---|---|---|---|---|---|
| Product: | Red Hat Enterprise Linux 5 | Reporter: | james.lemma | ||||
| Component: | glibc | Assignee: | Carlos O'Donell <codonell> | ||||
| Status: | CLOSED NOTABUG | QA Contact: | qe-baseos-tools-bugs | ||||
| Severity: | medium | Docs Contact: | |||||
| Priority: | unspecified | ||||||
| Version: | 5.2 | CC: | ashankar, fweimer, james.lemma, mnewsome, mpolacek, msebor, ohudlick, pfrankli | ||||
| Target Milestone: | rc | ||||||
| Target Release: | --- | ||||||
| Hardware: | i386 | ||||||
| OS: | Linux | ||||||
| Whiteboard: | |||||||
| Fixed In Version: | Doc Type: | If docs needed, set a value | |||||
| Doc Text: | Story Points: | --- | |||||
| Clone Of: | Environment: | ||||||
| Last Closed: | 2016-11-22 16:28:34 UTC | Type: | Bug | ||||
| Regression: | --- | Mount Type: | --- | ||||
| Documentation: | --- | CRM: | |||||
| Verified Versions: | Category: | --- | |||||
| oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |||||
| Cloudforms Team: | --- | Target Upstream Version: | |||||
| Attachments: |
|
||||||
The current version of the sprintf manual page is very explicit, explaining why this is expected behavior: “ In no case does a nonexistent or small field width cause truncation of a field; if the result of a conversion is wider than the field width, the field is expanded to contain the conversion result. ” If you want truncation and have only a single field, you can use snprintf instead. GCC 7.0 points out the problem in the test case the with a -Wformat-length warning:
$ cat rhbz-1394329.c && gcc -O2 -S -Wall rhbz-1394329.c
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
long longNum = 123456;
char longNumStr[4];
memset(longNumStr, 0, sizeof(char) * 4);
/* Should only copy over 3 digits from longNum, but will copy over 6 digits,
ignoring length of format specification */
sprintf(longNumStr, "%3ld", longNum);
/* Output for longNumStr will be 123456, but it should be only 123.
Side effect of this is that longNumStr is no longer null terminated
and memory has been overwritten beyond the length of the string,
this causes memory issues (segmentation faults in bigger, more
complicated programs). */
printf("The contents of longNumStr is %s\n", longNumStr);
return 0;
}
rhbz-1394329.c: In function ‘main’:
rhbz-1394329.c:13:24: warning: ‘%3ld’ directive writing 6 bytes into a region of size 4 [-Wformat-length=]
sprintf(longNumStr, "%3ld", longNum);
^~~~
rhbz-1394329.c:13:3: note: format output 7 bytes into a destination of size 4
sprintf(longNumStr, "%3ld", longNum);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
Created attachment 1219832 [details] C file that gives an example of the bug Description of problem: The libc function sprintf does not honor the length of format specification for long variables (writes additional characters if present despite length of format specification limiting them). Version-Release number of selected component (if applicable): RHEL 5.2 2.6.18-92.el5 gcc version 4.1.2 20071124 (Red Hat 4.1.2-42) ldd (GNU libc) 2.5 How reproducible: Compile and run attached sprintf_bug.c Steps to Reproduce: 1. declare a long variable and set to a value that is longer than a character string variable (if converted using sprintf): long longNum = 123456; char longNumStr[4]; 2. call memset to zero out character string variable: memset(longNumStr, 0, sizeof(char) * 4); 3. call sprintf to convert long variable to character string variable, limiting number of characters to size of character string variable: sprintf(longNumStr, "%3ld", longNum); 4. call printf to print out character string variable, noting that the value printed is longer than it should be based on format specification in sprintf call above: printf("The contents of longNumStr is %s\n", longNumStr); Actual results: Prints string variable with additional characters beyond number specified in format specification in sprintf call (123456). Expected results: Prints string variable with number of characters as in format specification from sprintf call (123). Additional info: Output for longNumStr will be 123456, but it should be only 123. Side effect of this is that longNumStr is no longer null terminated and memory has been overwritten beyond the length of the string, this causes memory issues (segmentation faults in bigger, more complicated programs).