why printf('c') cause Segmentation fault? - gcc-warning

This is my test code.
#include <stdio.h>
int main() {
printf('c');
return 0;
}
SO: ubuntu16.04
Compiler version: gcc5.3
Running the code above cause Segmentation fault error in "movdqu (%rdi),%xmm0 ".
I had google it, but I want to know why cause Segmentation fault

Because you are trying to pring a char, not a string. First argument of printf() function is a format string.
Strings are quoted in "", chars in ''.

I fond the error when use GDB debug the program.
image

SHORT:
This is prototype of printf function in C:
int printf ( const char * format, ... );
You should pass c-string (like "this is my message") instead of char.
DETAILED:
This is prototype of printf function in C:
int printf ( const char * format, ... );
This means that the first argument should be a pointer to a null-terminated array of char. In fact, printf reads value of first argument which is address of an c-string in memory, then go to that address and reads bytes by bytes to reach null character. In two condition this code causes segmentation fault:
The address is pointed by the first argument of printf is outbound of memory address of your program.
printf can't find any null characters beginning from the specified address before reaching end of memory boundary of your program.
Please be careful about using non-pointer variables in place of pointers. This cause your program to crash without a argumentive reason.

Related

How to get ioctl command value of the given driver?

How to get ioctl command value (integer value) of the given driver, which is not part of kernel source tree.
Example
#define ioctl_cmd _IOW('a', 1, struct example*)
I need an integer value of the command ioctl_cmd without actually modifying the driver.
The _IOW(type,nr,size) macro is defined for userspace code by #include <linux/ioctl.h>. The actual source of the macro is in "/usr/include/asm-generic/ioctl.h".
One way to get the integer value of the ioctl command value is to print it to the terminal in a C program:
#include <stdio.h>
#include <linux/ioctl.h>
#include "your_driver_ioctls.h" // defines `ioctl_cmd`
int main(void)
{
printf("ioctl_cmd = %u (0x%x)\n", ioctl_cmd, ioctl_cmd);
}
Alternatively, you can look at the definition of _IOW in the source to see how the ioctl command code is composed:
Bits 31 to 30 indicate the direction of transfer of the memory pointed to by the optional third argument of the ioctl() call:
_IOC_NONE = 0 (no direction)
_IOC_WRITE = 1 (userland is writing to kernel)
_IOC_READ = 2 (userland is reading from kernel)
_IOC_WRITE | _IOC_READ = 3 (userland is writing to and reading from kernel)
The _IOW(type,nr,size) macro sets the direction to _IOC_WRITE.
Bits 29 to 16 indicate the 14-bit size of the memory pointed to by the optional third argument of the ioctl() call. The _IOW(type,nr,size) macro sets this to the size of the type specified in the third parameter of the macro call (sizeof(size)).
Bits 15 to 8 indicate the 8-bit "type number" of the ioctl command code. Historically, a single ASCII character value was used for the type number, but any unsigned number up to 255 can actually be used. All the ioctl command codes defined for a device generally use the same type number. The _IOW(type,nr,size) macro sets this to the first parameter of the macro call (type).
Bits 7 to 0 indicate the 8-bit "function number" of the ioctl command code. The _IOW(type,nr,size) macro sets this to the second parameter of the macro call (nr).
Note that the above way of defining ioctl command codes is mostly just a convention. In particular, earlier subsystems such as TTY use a simpler scheme consisting of just a "type number" and a "function number").
Your #define ioctl_cmd _IOW('a', 1, struct example*) is unusual because it says that the optional third argument of the ioctl() call points to a struct example* and the size of that would be 4 or 8 (depending on the size of pointers in userspace). More conventionally, it would be defined as _IOW('a', 1, struct example).

sprintf expects argument of type char * - but type IS char

Thats code:
void bleAdvData(char *advData, uint8_t size){
char command[18+size];
uint8_t commandUint[18+size];
sprintf(command, "AT+BLEADVDATA=\"%s\"\r\n", *advData);
Warning in sprintf line:
Argument %s expects argument of type "char *", but argument 3 has type int
Why?
And what i have to do:
I want to trasfer a string(advData) wtich the length of "size" into a function for get a string command like:
AT+BLEADVDATA="advData"\r\n
Your variable advData is defined as char * in the argument list. This is a pointer to an address where character data is stored. However, in your sprintf() you use *advData, ie the actual place where advData points to, not the address itself.
Take the * off in the sprintf(), and all should be fine.
To clarify: char *advData on the first line makes advData a char *.
But then you added an asterisk to advData so you have * (char *advData).
So you want this:
sprintf(command, "AT+BLEADVDATA=\"%s\"\r\n", advData);
That extra asterisk "dereferences" the advData so you're now trying to pass in the first character of the string
sprintf then complains since that's not a valid string. If you ran this it'd either crash or on the ESP32 give you gibberish.
I recommend using the Warnings as Errors option on the ESP32. It's very rare that a warning won't be meaningful, and the ESP32 doesn't crash as easily as a program running on a modern PC OS.
That leads to really hard to find bugs where stuff randomly works or crashes with no clear pattern.

char array in c in overflowed scanf operation

I am new to C programming and i am really confused on below code:
#include <stdio.h>
#include <string.h>
int main(void)
{
char arrstr[6];
int i;
printf("Enter: ");
scanf("%s",arrstr);
printf("arrstr is %s\n",arrstr);
printf("length os arrstr is %d\n",strlen(arrstr));
for(i=0;i<20;i++)
{
printf("arrstr[%d] is %c, dec value is %d\n",i,arrstr[i],arrstr[i]);
}
return 0;
}
As from my understanding, after the declaration of arrstr[6], the compiler will allocate 6 bytes for this char array, and consider the last '\0' char, 5 valid chars can be stored in the char array.
But after i run this short code, i get below result:
The printf shows all chars i input, no matter how long is it. But when i using an index to check the array, seems i cannot find the extra chars in the array.
Can anyone helps to explain what happened?
Thanks.
Try changing your code by adding this line right after the scanf statement:
arrstr[5] = '\0';
What has happened is that the null character was overwritten by the user entry. Putting the null character back in manually gives you proper behavior for the next two lines, the printf statements.
The for loop is another matter. C does not have any kind of bounds checking so it's up to the programmer to not overrun the bounds of an array. The values you get after that could be anything at all, as you are just reading uninitialized RAM bytes at that point. A standard way of avoiding this is to use a const int variable to declare the array size:
const int SIZE = 6;
char arrstring[SIZE];
Then also use SIZE as the limit in the for loop.
P.S. There is still a problem here with the user entry as written, because a user could theoretically enter hundreds of characters, and that would get written out-of-bounds it seems, possibly causing weird bugs. There are ways to limit the amount of user entry, but it gets fairly involved, here are some stackoverflow posts on the topic. Keep in mind for future reference:
Limiting user entry with fgets instead of scanf
Cleaning up the stdin stream after using fgets

Program exited with error code 04

I'm trying to run a program with perl to print "A" 512 times through gdb. It returned with code 04. I started slowly going down to 511 then 510 and so on. But it still returned with code 04. Is this how it's supposed to be? If not, what am I doing wrong? Thanks for your answers.
Code:
#include <stdio.h>
int main(int argc, char * argv[])
{
char buf[256];
if(argc == 1)
{
printf("Usage: %s input\n", argv[0]);
exit(0);
}
strcpy(buf,argv[1]);
printf("%s", buf);
}
And I'm running from gdb:
run perl -e 'print "A" x 512'
There's no reason to involve either perl or gdb for this.
As of the 1989/1990 C standard, reaching the } at the end of main returns an undefined status to the environment. (The actual status of 4 in your case is probably the value returned by printf, which is the number of characters it printed. The way you invoked the program, argv[0] points to the string "perl", which is 4 characters long. But you absolutely should not count on that behavior.)
The 1999 standard introduced a new rule (inspired by C++): reaching the end of main does the equivalent of return 0;. But gcc by default uses the C90 standard plus GNU extensions (equivalent to -std=gnu90).
Add a return 0; to the end of your main function and/or compile your C program with an option that specifies a later standard, such as -std=c99 (or -std=gnu99 if you want to use GNU-specific extensions).
Finally, it looks like you were trying to print 512 'A' characters, but you were invoking your program with the arguments:
perl -e 'print "A" x 512'
That's three arguments, and your program ignores all but the first, the 4-character string "perl". The remaining arguments were meant to be passed to the Perl interpreter, but you didn't invoke the Perl interpreter.
One correct way to do this would be:
./foo $(perl -e 'print "A" x 512')
where foo is the name of your program. But that would cause undefined behavior (possibly a program crash, or it might appear to "work" if you're unlucky), because you copy the string pointed to by argv[1] into an array of only 256 characters. For this simple program, that's easily avoided by not copying the string.
And your program's output doesn't end with a newline, which can cause problems. On a UNIX-like system, the program's output will likely be printed on the same line as your next shell prompt -- or the output might not be visible at all.
To see the program's exit status, type:
echo $?
(This assumes you're using bash or a similar shell.)

Why does the filename requested from the server start with Unicode characters?

I use FTP to list the file attributes on the server. I request the name of file and put them into an array. I print the array directly like this:
NSLog(#"%#", array);
What I got is like this:
\U6587\U4ef6\U540d\Uff1afilename.txt
\U6587\U4ef6\U540d\Uff1afilename1.txt
......
When I want to print the Unicode "\U6587\U4ef6\U540d\Uff1a" to see what it is, I got the compiling error: "incomplete universal character name".
However, If I print the name instead of the whole array, I can get the name correctly without the Unicode. But I need to do something with the name in the array. I want to know why the Unicode is there, and is it proper to just remove the Unicode then to do something with the real file name?
In C99, and therefore presumably Objective C too, there are two Unicode escapes:
\uXXXX
\UXXXXXXXX
The lower-case u is followed by 4 hex digits; the upper-case U is followed by 8 hex digits (of which, the first two should be zeroes to be valid Unicode (and the third should be 0 or 1; the maximum Unicode code point is U+10FFFF).
I believe that if you replace the upper-case U's with lower-case u's, you should get the code to compile.
On my Mac OS 10.7.4 system, compiling with GCC 4.7.0 (home built), I compiled this code:
#include <stdio.h>
int main(void)
{
char array[] = "\u6587\u4ef6\u540d\uff1a";
puts(array);
return 0;
}
and got this output:
文件名:
I can't answer why the characters are there, but the colon-like character at the end suggests that the site might be preceding the actual file name with a tag of some sort (analogous to 'file:').
Adding to what Jonathan said, you might have to use stringWithUTF8String:, but I agree that the error is with the capital U rather than u.