Why does sscanf result in 0 in this case? - c

I am trying to convert a series of decimal numbers to their hex representation in string format and then back from string to decimal. This might sound strange but is a simplified representation of a more complex situation.
So, either way, I have the following piece of code which almost works fine. For some reason my variable a is still equal to 0 at the end while it should equal 43, all the other variables seem to be alright:
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
/********************* A *******************/
uint16_t a = 43; //0x002b
int16_t b = -43; //0xffd5
uint32_t c = 234; //0x000000ea
int32_t d = -234; //0xffffff16
char aStr[10]={0};
char bStr[10]={0};
char cStr[10]={0};
char dStr[10]={0};
snprintf(aStr, sizeof(aStr), "%04hhx", a);
snprintf(bStr, sizeof(bStr), "%04x", b & 0xFFFF);
snprintf(cStr, sizeof(cStr), "%08hhx", c);
snprintf(dStr, sizeof(aStr), "%08x", d & 0xFFFFFFFF);
fprintf(stdout, "TX a = %s.\n", aStr);
fprintf(stdout, "TX b = %s.\n", bStr);
fprintf(stdout, "TX c = %s.\n", cStr);
fprintf(stdout, "TX d = %s.\n", dStr);
/********************* B *******************/
uint16_t aOut = 0;
int16_t bOut = 0;
uint32_t cOut = 0;
int32_t dOut = 0;
sscanf(aStr, "%04hhx", &aOut);
sscanf(bStr, "%04x", &bOut);
sscanf(cStr, "%08hhx", &cOut);
sscanf(dStr, "%08x", &dOut);
fprintf(stdout, "rx a = %d\n", aOut); //<---- this line prints 0 for a. Why?
fprintf(stdout, "rx b = %d\n", bOut);
fprintf(stdout, "rx c = %d\n", cOut);
fprintf(stdout, "rx d = %d\n", dOut);
return 0;
}
Does anybody know why or what I am missing?

The line
sscanf(aStr, "%04hhx", &aOut);
is wrong. The %hhx conversion format specifier requires an argument of type unsigned char *, but you are instead passing it an argument of type uint16_t *. This invokes undefined behavior.
I suggest that you change that line to the following:
sscanf(aStr, "%04"SCNx16, &aOut);
On most platforms, the macro SCNx16 will simply expand to "hx", but it is generally safer to use the macro, in case you code happens to be running on a (future) platform on which uint16_t is not equivalent to an unsigned short.
The lines
sscanf(bStr, "%04x", &bOut);
sscanf(cStr, "%08hhx", &cOut);
sscanf(dStr, "%08x", &dOut);
are also using the wrong conversion format specifiers. I recommend that you use the following code instead:
sscanf(bStr, "%04"SCNx16, &bOut);
sscanf(cStr, "%08"SCNx32, &cOut);
sscanf(dStr, "%08"SCNx32, &dOut);
Strictly speaking, the above code also invokes undefined behavior, because the %x conversion format specifier requires a pointer to an unsigned type instead of to a signed type. However, this should not be a problem in practice, provided that the converted value can be represented both in the signed type and in the unsigned type.

Related

how to write a uint64_t to a char* buffer in C

So I am trying to write a uint64_t return address to a buffer and then verify that the correct return address got written to the correct spot. Here is my code.
uint64_t new_ret = ret - 8 - 32 - 32 - 1001 + (ret_buffer_offset + sizeof(shellcode));
printf("new_ret :%lu\n", new_ret);
snprintf(&buffer[ret_buffer_offset], 8, "%s", new_ret);
// debug code
char buffer_debug[10];
uint64_t* buffer_uint = (uint64_t*)buffer_debug;
bzero(buffer_debug, 10);
strncpy(buffer_debug, &buffer[ret_buffer_offset], 8);
uint64_t ret_debug = *buffer_uint;
printf("ret debug: %lu\n", ret_debug);
the two printfs should output the same thing, but the bottom printf outputs a very different number. I'm not sure if the way I'm writing to the buffer is wrong or if the way I'm getting the value back is wrong. What is the issue here?
Thanks
snprintf(&buffer[ret_buffer_offset], 8, "%s", new_ret);
buffer now contains the string representation of your original value (or at least the first 8 bytes of the string representation). Your code then takes the first 8 bytes of this string and interprets that binary sequence as if it was a uint64_t. Step through this chunk of code in a debugger and you'll see exactly where the value changes.
I'm not sure exactly what this code is trying to do, but it seems like it's doing more copying and conversion than necessary. If you have a pointer to where you want the value to go, you should be able to either do memcpy(ptr, &new_ret, sizeof(new_ret)) or possibly even *(uint64_t*)ptr = new_ret if your platform allows potentially-misaligned writes. To print out the value for debugging, you'd use printf("%"PRIu64, *(uint64_t*)ptr).
I like to use union, but if you make a char pointer (char*) to point to the address of uint64_t it will work.
Using pointer will be:
uint64_t new_ret = ret - 8 - 32 - 32 - 1001 + (ret_buffer_offset + sizeof(shellcode));
buffer = (char*) &new_ret;
Test the code below to use union and pointer:
#include <stdio.h>
#include <stdint.h>
int main(){
union {
uint64_t u64;
char str[8];
} handler;
handler.u64 = 65;
printf("Using union:\n");
printf(" uint64: %ld\n", handler.u64);
printf(" char*: %s\n", handler.str);
uint64_t u64 = 65;
char *str = (char*)&u64;
printf("Using pointer:\n");
printf(" uint64: %ld\n", u64);
printf(" char*: %s\n", str);
return 0;
}

variable is losing its value in c program

This is written in 'c' and compiled with gcc. I'm not sure what else you need to know.
The smallest complete example I could put together is shown here. The variable 'numatoms' loses its value when it gets to line 23 (after the scanf()).
I'm stumped. Maybe it has something to do with scanf() overwritting the space for numatoms?
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
/*
*
*/
int main(int argc, char** argv) {
uint8_t numatoms;
uint8_t r;
char a[20];
do {
printf("NO. OF ATOMS?");
fflush(stdout);
scanf("%d", &numatoms);
printf("\r\n");
for(;;){
printf("value of numatoms is %u\r\n", numatoms);
printf("RAY?");
fflush(stdout);
scanf("%u", &r);
printf("value of numatoms is %u\r\n", numatoms);
if(r < 1)
break;
else {
printf("value of numatoms is %u\r\n", numatoms);
}
}
printf("CARE TO TRY AGAIN?");
fflush(stdout);
scanf("%s", a);
printf("\r\n");
} while (a[0] == 'y' || a[0] == 'Y');
return (EXIT_SUCCESS);
}
uint8_t is 8 bits long %u reads an unsigned int (probably 32 bits long).
You either need to make numatoms "bigger" (i.e. unsigned int) or read the correct size (see scanf can't scan into inttypes (uint8_t))
You should use macros for format specifiers for integer types defined in the header <inttypes.h>.
From the C Standard (7.8.1 Macros for format specifiers)
1 Each of the following object-like macros expands to a character
string literal containing a conversion specifier, possibly modified by
a length modifier, suitable for use within the format argument of a
formatted input/output function when converting the corresponding
integer type. These macro names have the general form of PRI
(character string literals for the fprintf and fwprintf family) or SCN
(character string literals for the fscanf and fwscanf family),217)
followed by the conversion specifier, followed by a name corresponding
to a similar type name in 7.20.1. In these names, N represents the
width of the type as described in 7.20.1.
The general form of the macro used for unsigned integer types with the conversion specifier u looks like
SCNuN
Here is a demonstrative program
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main(void)
{
uint8_t x;
scanf( "%" SCNu8, &x );
printf( "x = %u\n", x );
return 0;
}

Convert usigned integer( uint16_t) to string. Standard itoa base 10 is giving negative values

I need to convert uint16_t value to a string. I want the string to be a decimal respresentation of the number.
Example: uint16_t i=256 string: 256
I tried with itoa(i,string, 10) but when i value increases starts printing negative values.
I send the string via the Serial Port.(UART)
It is there some alternative?
Use sprintf with %u format for unsigned int:
uint16_t i = 33000;
sprintf(str, "%u", i);
You can try to use sprintf() for common "to string" conversions. For example:
#include <stdio.h>
#include <math.h>
int main() {
uint16_t i = 256;
char str[80];
int str_len = sprintf(str, "%d", i);
return(0);
}
For more info look at this article.

C: fscanf() on a hexadecimal giving me incorrect values

I've looked everywhere trying to figure out what I'm doing wrong and can't seem to figure out WHY this block of code isn't handling hexadecimal numbers correctly.
FILE *listFile = fopen(argv[1], "r");
unsigned int hexIndex;
if(listFile == NULL){
printf("error\n");
return 0;
}
while(!feof(listFile))
{
fscanf(listFile, "%x\n", &hexIndex);
printf("hexindex %d\n", hexIndex);
if(hashInsert(hexIndex) == 0)
{
printf("uniques: %d\n", uniques);
uniques++;
}
}
For example, given a file with the following 3 hexadecimal addresses:
0xFFFFFFFFFF
0x7f1a91026b00
0x7f1a91026b03
The program prints out:
hexindex -1
hexindex -1862112512
hexindex -1862112509
which I'm 100% sure is incorrect. I've spent hours trying to figure out what I've done wrong, and I feel that I might be overlooking something simple. I've tried using different integer types like size_t, longs, etc. but run into the same exact output every time.
Can anybody give me some insight as to what I might be doing wrong?
You should use %u or %x to printf an unsigned int. Currently you are using %d which causes undefined behaviour.
A second thing to check is that the intended values will fit into unsigned int. Some of your sample values are 48 bits long. If your system has 32-bit unsigned int then you cannot use unsigned int for this purpose.
The portable way to go here is to use uint64_t as the variable type, and the scanf hex specifier is SCNx64 and the printf specifier is PRIu64 or PRIx64. For example:
#include <inttypes.h>
uint64_t hexIndex;
// ...
while( 1 == fscanf(listFile, "%" SCNx64, &hexIndex) )
{
printf("hexindex %" PRIu64 "\n", hexIndex);
if(hashInsert(hexIndex) == 0)
{
printf("uniques: %d\n", uniques);
uniques++;
}
}
(note: don't use while...feof)

Converting an int to a string in C, securely

According to a top answer on SO this is what I should do to convert an integer to a string in C:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <math.h>
#define digits(x) ((int)((ceil(log10(abs(x)))+1)*sizeof(char)))
int main () {
int a = 345908220;
long b = 23094809284358;
unsigned int c = 3456789234;
uint8_t d = 242;
int64_t e = -840958202029834;
int dstr_len = digits(a) + digits(b) + digits(c) +
digits(d) + digits(e) + 5;
char dstr[dstr_len];
sprintf(dstr, "%d %ld %u %u %" PRIu64, a, b, c, d, e);
printf("%s\n", dstr);
return 0;
}
However, this seems ridiculously inefficient. I have to link my program to libmath, and make three math calls for every integer that I want to print. Also note that I had to add 5 to my buffer and not just 1 for the NUL terminator, by counting the number of spaces in my format string. This also seems error-prone, and could lead to a buffer overflow.
So, is there any nice, standard function, that will compute the size of my buffer for me?
I'm trying to write secure C.
If your compiler has snprintf() available, you can request the formatted buffer length and then allocate accordingly:
int dstr_len = snprintf(NULL, 0, "%d %ld %u %u %" PRIu64, a, b, c, d, e) + 1;
char dstr[dstr_len];
//
// NOTE: variable-length arrays are NOT supported in all compilers!
// A more portable solution is:
//
// char *dstr = malloc(sizeof(char) * dstr_len);
snprintf(dstr, dstr_len, "%d %ld %u %u %" PRIu64, a, b, c, d, e);
// free(dstr);
You can use snprintf for this. From the manpage:
The functions snprintf() and vsnprintf() do not write more than size bytes (including the teriitminating null byte ('\0')). If the output was truncated due to this limit then the return
value is the number of characters (excluding the terminating null byte) which would have been
written to the final string if enough space had been available. Thus, a return value of size
or more means that the output was truncated.
Thus you can call it with 0 for the size and capture the return value then allocate based on that.
You can use asprintf, which allocates a large enough output string for you.
Don't forget to free the output string, because it is dynamically allocated.
asprintf is available on Mac OSX, Linux, and BSD. The source code is available from Apple if you wish to use it on other platforms.
Example:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
int main () {
int a = 345908220;
long b = 23094809284358;
unsigned int c = 3456789234;
uint8_t d = 242;
int64_t e = -840958202029834;
char *dstr;
asprintf(&dstr, "%d %ld %u %u %" PRIu64, a, b, c, d, e);
if (dstr == NULL) {perror(NULL), exit(1);}
printf("%s\n", dstr);
free(dstr);
return 0;
}
Most C "runtime environments" are at most 64 bits. You could test that int is at most 64 bits (with <stdint.h> and <limits.h>) then use snprintf (not sprintf which is unsafe and deprecated) on a large enough buffer (32 bytes is more than enough for 264 in decimal).
See Posix spec on limits.h which define WORD_BIT so
#if WORD_BIT > 64
#error cannot compile on this machine
#endif
char buf[32];
snprintf(buf, sizeof(buf), "%d", a);
BTW, <stdint.h> defines several types. You might want intmax_t

Resources