Reputation: 26652
#include <stdio.h>
int main() {
char *str = "11111111-22222222 r-xp 00000000 00:0e 1843624 /lib/libdl.so.0";
unsigned long long start_addr, stop_addr, offset;
char* access = NULL;
char* filename = NULL;
sscanf(str, "%llx-%llx %m[-rwxp] %llx %*[:0-9a-f] %*d %ms",
&start_addr, &stop_addr, &access, &offset, &filename);
printf("\n start : %x, stop : %x, offset : %x\n",start_addr,stop_addr,offset);
printf("\n Permission : %s\n",access);
printf("\n Filename : %s\n",filename);
return 0;
}
On Linux this gives the correct output but on Solaris the file is called libdl.so (there is no libdl.so.0 on Solaris) so I wonder what makes this difference, there is not this file on Solaris and if I change to the filename of the Solaris installation (libdl.so) then it generates a segmentation fault.
$ cc Cperm.c ;./a.out
Cperm.c: I funktion "main":
Cperm.c:11:3: varning: format "%x" förväntar sig argument av typen "unsigned int", men argument 2 har typen "long long unsigned int" [-Wformat]
Cperm.c:11:3: varning: format "%x" förväntar sig argument av typen "unsigned int", men argument 3 har typen "long long unsigned int" [-Wformat]
Cperm.c:11:3: varning: format "%x" förväntar sig argument av typen "unsigned int", men argument 4 har typen "long long unsigned int" [-Wformat]
start : 11111111, stop : 22222222, offset : 0
Permission : r-xp
Filename : /lib/libdl.so.0
The above is on ubuntu and here is on Solaris where it compiles without warnings but generates a segmentation fault:
uname -a
SunOS 5.10 Generic_148888-03 sun4u sparc SUNW,Ultra-4
my:~>cc Cperm.c;./a.out
start : 0, stop : 11111111, offset : 0
Segmentation fault
my:~>uname -a;gcc -Wall Cperm.c
SunOS 5.10 Generic_148888-03 sun4u sparc SUNW,Ultra-4
Cperm.c: In function `main':
Cperm.c:9: warning: unknown conversion type character `m' in format
Cperm.c:9: warning: long long unsigned int format, pointer arg (arg 5)
Cperm.c:9: warning: unknown conversion type character `m' in format
Cperm.c:9: warning: too many arguments for format
Cperm.c:11: warning: unsigned int format, different type arg (arg 2)
Cperm.c:11: warning: unsigned int format, different type arg (arg 3)
Cperm.c:11: warning: unsigned int format, different type arg (arg 4)
my:~>gcc Cperm.c
my:~>
Upvotes: 2
Views: 758
Reputation: 43487
It's actually much simpler than it might look. Your code has never allocated space to store the string results into. This shorter code has the same defect:
#include <stdio.h>
int main() {
char *word = NULL;
sscanf("hello world", "%s", &word);
printf("%s\n", *word);
return 0;
}
The reason it may "work" on one compiler but not another may have to do with how storage is allocated. Here is the error generated by that code:
cperm.c:5:5: error: format ‘%s’ expects argument of type ‘char *’,
but argument 3 has type ‘char **’
Which doesn't seem horrible, but it's actually fatal. Running gcc with the -Werror option would make that warning stop compilation and not create an a.out
. Defining and using word
properly
char word[64];
sscanf("hello world", "%63s", word);
printf("%s\n", word);
compiles without error and works.
Upvotes: 4
Reputation: 51137
Your compiler (on Ubuntu, and probably Solaris if you enabled the warning) told you what is wrong:
Cperm.c:11:3: varning: format "%x" förväntar sig argument av typen "unsigned int", men argument 2 har typen "long long unsigned int" [-Wformat]
⋮
You need to use %llx
in your printf
, just like you did in your sscanf
.
Passing the wrong type of argument is undefined behavior. On Linux, it happened to work (this time); on Solaris, it didn't.
[You're really asking a question about the C language and libraries, you'd probably have better luck searching Stack Overflow for answers, rather than here.]
edit: see also msw's answer, which points out another problem, at least as important as this one.
Upvotes: 4
Reputation: 6239
Check the man page for Solaris 10 sscanf
. The %m
modifier is not supported there.
You should also check the return value of sscanf
.
Upvotes: 11