Format specifier %u used with sprintf is creating crash - c

When I used %u in sprintf() application gets crashed, it's working fine with %d
See the code:
#include <stdio.h>
#include <string.h>
main()
{
unsigned char dAddr[4];
unsigned char sMask[4];
unsigned char nHop[4];
memset(dAddr,0,sizeof(dAddr));
memset(sMask,0,sizeof(sMask));
memset(nHop,0,sizeof(nHop));
unsigned int u4IpDAddr = 0x01020304;
unsigned int u4IpSNetMask = 0xffff01ff;
unsigned int u4NHopGt = 0x01020304;
char *dip = (char *)&u4IpDAddr;
char *smk = (char *)&u4IpSNetMask;
char *nhp = (char *)&u4NHopGt;
sprintf(dAddr, "%u.%u.%u.%u", dip[3], dip[2], dip[1], dip[0]); //if I used %d.%d.%d.%d its working fine
sprintf(sMask, "%u.%u.%u.%u", smk[3], smk[2], smk[1], smk[0]); //if I used %d.%d.%d.%d its working fine
sprintf(nHop, "%u.%u.%u.%u", nhp[3], nhp[2], nhp[1], nhp[0]); //if I used %d.%d.%d.%d its working fine
printf("SAM: func %s line %d IpDAddr %s Mask %s NHop %s\n",__func__,__LINE__,dAddr,sMask,nHop);
}
when I declared a pointer's with following manner its working fine for %u.%u.%u.%u format
unsigned char *dip = (unsigned char *)&u4IpDAddr;
unsigned char *smk = (unsigned char *)&u4IpSNetMask;
unsigned char *nhp = (unsigned char *)&u4NHopGt;
Can any one explain what is happening when I used char pointers?

In your case
unsigned char dAddr[4];
unsigned char sMask[4];
unsigned char nHop[4];
are not sufficient to hold the lexicographical output.
When you're using those arrays as the destination string in sprintf(), essentially, you're overrunning the allocated memory, creating undefined behaviour.
You need to allocate more memory to use those arrays as the destination of sprintf().

If char is signed on your platform, then char value that you "hack out" of your u4IpSNetMask are more than likely to be negative, since you have bytes that begin with 0xF... in u4IpSNetMask. When you send such char values to sprintf they get converted to negative int values and then reinterpreted as unsigned values by your %u specifier. The behavior is actually undefined - it is illegal to sprintf negative int values with %u. However, in practice you usually end up with a huge positive values that require many characters to represent. These representations easily overflow your destination buffers, destroy the program stack and cause your program to crash.
You can see for yourself what your sprintf calls generate on a typical platform: http://coliru.stacked-crooked.com/a/6aec03cfdf28f8b2
The middle sprintf produces 4294967295.4294967295.1.4294967295. And you expected this monster to fit into buffer sMask of only 4 characters long?
Moreover, the same kind of overflow happens with %d as well, but the string representation produced by %d is shorter (-1 in place of 4294967295) an the damage is smaller, which is probably why the program sort of limps to the end without crashing. But that does not change the fact that string 1.2.3.4 requires a char buffer of at least 8 characters long. You provided only 4.
In other words, your program is as broken with %d as it is broken with %u. If it did not crash with %d, it is just out of random luck.

Related

Function is returning a different value every time?

I'm trying to convert a hexadecimal INT to a char so I could convert it into a binary to count the number of ones in it. Here's my function to convert it into char:
#include <stdio.h>
#include <stdlib.h>
#define shift(a) a=a<<5
#define parity_even(a) a = a+0x11
#define add_msb(a) a = a + 8000
void count_ones(int hex){
char *s = malloc(2);
sprintf(s, "0x%x", hex);
free(s);
printf("%x", s);
};
int main() {
int a = 0x01B9;
shift(a);
parity_even(a);
count_ones(a);
return 0;
}
Every time I run this, i always get different outputs but the first three hex number are always the same. Example of outputs:
8c0ba2a0
fc3b92a0
4500a2a0
d27e82a0
c15d62a0
What exactly is happening here? I allocated 2 bytes for the char since my hex int is 2 bytes.
It's too long to write a comment so here goes:
I'm trying to convert a hexadecimal INT
int are stored as a group of value, padding (possible empty) and sign bits, so is there no such thing as a hexadecimal INT but you can represent (print) a given number in the hexadecimal format.
convert a ... INT to a char
That would be lossy conversion as an int might have 4 bytes of data that you are trying to cram into a 1 byte. char specifically may be signed or unsigned. You probably mean string (generic term) or char [] (standard way to represent a string in C).
binary to count the number of ones
That's the real issue you are trying to solve and this is a duplicate of:
How to count the number of set bits in a 32-bit integer?
count number of ones in a given integer using only << >> + | & ^ ~ ! =
To address the question you ask:
Need to allocate more than 2 bytes. Specifically ceil(log16(hex)) + 2 (for 0x) + 1 (for trailing '\0').
One way to get the size is to just ask snprintf(s, 0, ...)
then allocate a suitable array via malloc (see first implementation below) or use stack allocated variable length array (VLA).
You can use INT_MAX instead of hex to get an upper
bound. log16(INT_MAX) <= CHAR_BIT * sizeof(int) / 4 and the
latter is a compile time constant. This means you can allocate your string on stack (see 2nd implementation below).
It's undefined behavior to use a variable after it's deallocated. Move free() to after the last use.
Here is one of the dynamic versions mentioned above:
void count_ones(unsigned hex) {
char *s = NULL;
size_t n = snprintf(s, 0, "0x%x", hex) + 1;
s = malloc(n);
if(!s) return; // memory could not be allocated
snprintf(s, n, "0x%x", hex);
printf("%s (size = %zu)", s, n);
free(s);
};
Note, I initialized s to NULL which would cause the first call to snprintf() to return an undefined value on SUSv2 (legacy). It's well defined on c99 and later. The output is:
0x3731 (size = 7)
And the compile-time version using a fixed upper bound:
#include <limits.h>
// compile-time
void count_ones(unsigned hex) {
char s[BIT_CHAR * sizeof(int) / 4 + 3];
sprintf(s, "0x%x", hex);
printf("%s (size = %zu)", s, n);
};
and the output is:
0x3731 (size = 11)
Your biggest problem is that malloc isn't allocating enough. As Barmar said, you need at least 7 bytes to store it or you could calculate the amount needed. Another problem is that you are freeing it and then using it. It is only one line after the free that you use it again, which shouldn't have anything bad happen like 99.9% of the time, but you should always free after you know you are done using it.

Using sprintf to convert an unsigned long to char array producing 0

I am trying to convert an unsigned long using the sprintf function in c. Code goes like:
char ID[6];
sprintf(ID,"%lu",a.id);
a.id is a number that is passed in that can range from 0 > but I only want the first 6 regardless. Using printf("%lu",a.id); prior to conversion prints the right number but once I try print the string from the char the outcome is 0. Not too sure why this is happening any advice would be much appreciated.
... once I try print the string from the char the outcome is 0
Code is risking undefined behavior (UB): buffer overrun, potential wrong specifier.
but I only want the first 6 regardless.
Insure the buffer is big enough for 6 characters and a terminating null character.
//char ID[6];
char ID[6+1];
Handle a.id outside the expected range of 0...999999 with % some_unsigned_constant. This does print the last 6.
// sprintf(ID,"%lu",a.id);
sprintf(ID,"%lu",a.id % 1000000u);
As type of a.id, not posted, 2 steps may be useful to make sure a matching print specifier is used.
// sprintf(ID,"%lu",a.id % 1000000u);
unsigned long ul = a.id
sprintf(ID,"%lu", ul % 1000000u);
To print the first six, even if outside the 0...999999 range, use snprintf() which will print only up to the first 6.
char ID[6+1];
snprintf(ID, sizeof ID, "%lu", (unsigned long) a.id);
And the correct way to do what the OP wants is to
#include <stdio.h>
int main()
{
char ID[6];
unsigned long x = 3453342432;
int r = snprintf(ID, sizeof(ID), "%lu",x);
printf("%d %s\n", r, ID);
return 0;
}
Note that the snprintf result is a number of characters that would had been written. It was noted by others that you must reserve one character extra space for terminating NULL.

Getting gibberish instead of numbers using memcpy and strtoul

I have the following piece of code compiling under gcc:
int parseMsg(const char *msg_to_parse, unsigned long *exp_input, unsigned long *sysTicks )
{
int l_msg_size = strlen(msg_to_parse);
if(l_msg_size <10)
return -1;
char l_exp_input_arr[10];
char l_sys_ticks_arr[10];
memcpy(l_sys_ticks_arr,msg_to_parse+12,10);
memcpy(l_exp_input_arr,msg_to_parse,10);
//l_msg_size = strlen(msg_to_parse);
*sysTicks = strtoul(l_sys_ticks_arr,NULL,10);
*exp_input = strtoul(l_exp_input_arr,NULL,10);
return 0;
}
And I'm trying to test it in the following manner:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int parseMsg(const char *msg_to_parse, unsigned long *exp_input, unsigned long *sysTicks );
int main(void) {
char msg[] = "1234567890 59876543213";
unsigned long along1, along2;
along1 =0;
along2=0;
parseMsg(msg,&along1, &along2 );
printf("result of parsing: \n \t Along 1 is %lu \n \t Along 2 is %lu \n",along1, along2);
return 0;
}
But, I'm getting the following result:
result of parsing:
Along 1 is 1234567890
Along 2 is 4294967295
Why is the second unsigned long wrong?
Thanks
The second integer you provide is too big to be represented in memory on your architecture. So, according to its API, strtoul is just returning you ULONG_MAX (=4294967295 on your architecture), along with setting errno to ERANGE
strtoul API is here : http://www.cplusplus.com/reference/clibrary/cstdlib/strtoul/
BUT it may also fail if you gave a smaller integer, because strtoul only stops parsing when it encounters a non-numerical character. Since you didn't ensure that, you cannot be sure that strtoul will not try to parse whatever is in memory just after your strings. (So assuming random, you have 10 chance out of 256 to have a conversion error)
Terminate your strings with \0, it will be ok then :
char l_exp_input_arr[11]; // +1 for \0
char l_sys_ticks_arr[11];
memcpy(l_sys_ticks_arr, msg_to_parse+12, 10);
l_sys_ticks_arr[10] = '\0';
memcpy(l_exp_input_arr, msg_to_parse, 10);
l_exp_input_arr[10] = '\0';
You need to make your two temporary char[] variables one char longer and then make the last character NULL.

How to convert an Unsigned Character array into a hexadecimal string in C

Is it possible to represent an unsigned character array as a string?
When I searched for it, I found out that only memset() was able to do this (But character by character).
Assuming that is not the correct way, is there a way to do the conversion?
Context: I am trying to store the output of a cryptographic hash function which happens to be an array of unsigned characters.
eg:
unsigned char data[N]; ...
for(i=0;i<N;i++) printf("%x",data[i]);
My goal is to represent the data as a String (%s) rather than access it by each element. Since I need the output of the hash as a String for further processing.
Thanks!
So, based on your update, are you talking about trying to convert a unsigned char buffer into a hexadecimal interpretation, something like this:
#define bufferSize 10
int main() {
unsigned char buffer[bufferSize]={1,2,3,4,5,6,7,8,9,10};
char converted[bufferSize*2 + 1];
int i;
for(i=0;i<bufferSize;i++) {
sprintf(&converted[i*2], "%02X", buffer[i]);
/* equivalent using snprintf, notice len field keeps reducing
with each pass, to prevent overruns
snprintf(&converted[i*2], sizeof(converted)-(i*2),"%02X", buffer[i]);
*/
}
printf("%s\n", converted);
return 0;
}
Which outputs:
0102030405060708090A
In C, a string is an array of char, terminated with a character whose value is 0.
Whether or not char is a signed or unsigned type is not specified by the language, you have to be explicit and use unsigned char or signed char if you really care.
It's not clear what you mean by "representing" an unsigned character array as string. It's easy enough to cast away the sign, if you want to do something like:
const unsigned char abc[] = { 65, 66,67, 0 }; // ASCII values for 'A', 'B', 'C'.
printf("The English alphabet starts out with '%s'\n", (const char *) abc);
This will work, to printf() there isn't much difference, it will see a pointer to an array of characters and interpret them as a string.
Of course, if you're on a system that doesn't use ASCII, there might creep in cases where doing this won't work. Again, your question isn't very clear.
Well a string in C is nothing else than a few chars one after another. If they are unsigned or signed is not much of a problem, you can easily cast them.
So to get a string out of a unsigned char array all you have to do is to make sure that the last byte is a terminating byte '\0' and then cast this array to char * (or copy it into a array of char)
I successfully use this to convert unsigned char array to std:string
unsigned char array[128];
std::stringstream buffer;
for (int i = 0; i < 128; i++)
{
buffer << std::hex << std::setfill('0');
buffer << std::setw(2) << static_cast<unsigned>(array[i]);
}
std::string hexString = buffer.str();
An example as you've asked:
unsigned char arr [SIZE];

C/C++ casting problems, unsigned char to char

i have an unsigned char which i need to convert to char before printf. So the example code goes like this:
unsigned char y = sample.result;
char x = (char)y;
printf("%c \n", x);
However, printf does not print x but if i use cout, x prints correctly.I have no idea why so. How to i convert a unsigned char variable to a char? Am i doing it wrong? reinterpret_casting is only for pointer and mine are not pointers. Thanks in advance.
EDIT: Command prompt returns me a smiley face "☺" for the value of sample.result which corresponds to unsigned char 1. And apparently netbeans is unable to print this smiley face. I have no idea how it got translated into a smiley face. Any help?
EDIT 2: I just realized you can't print char x = 1; in netbeans, and printing it in command prompt yields the smiley face. Reasons? :(
If char x = 1 and you want a 1 to be printed out, you need to use %d instead of %c in your format specifier. %c prints the ASCII representation of the number, which for 1 is an unprintable character called "start of heading."
Try making x an int instead of char and see if that works. C rules required all char parameters to be converted to int, and printf is a C function.
The %c conversion for printf is only for characters in the basic character set. It seems you have an extended character that you want to print, so you'd have to use the appropriate tool for that. The type for that would be wchar_t and the print format %lc. But beware this depends a lot of your execution environment, locale settings and stuff like that.
And BTW in many circumstances narrow types like char are just converted to int or unsigned, so there is no need to cast it, and in fact other than your title suggests your problem has not much to do with casting.
I'm not confident in this answer, but I just wrote a simple test program that compiles and prints the letter A without casting the unsigned char back to a char.
#include <stdio.h>
int main()
{
unsigned char c = 'A';
printf("%c\n",c);
return 0;
}
Casting directly also worked:
#include <stdio.h>
int main()
{
unsigned char c = 'A';
printf("%c\n",(char)c);
return 0;
}
Doing it your way ALSO worked...
#include <stdio.h>
int main()
{
unsigned char c = 'A';
char d = (char)c;
printf("%c\n",d);
return 0;
}
So I assume I'm doing something wrong, now. Or maybe something else is your problem?
Here the equation of conversion
the algorithm for char c to unsigned char uc.
return (c>127) ? (unsigned char)(-(256 + c)) : (unsigned char)c;
the algorithm for unsigned uc to char c.
return (uc < 0) ? (char)(256-(char)abs(uc)) : (char)uc;

Resources