Niklas Rosencrantz
Niklas Rosencrantz

Reputation: 26652

Why does this code work on Linux but not on SunOS?

#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

Update

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

Answers (3)

msw
msw

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

derobert
derobert

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

Stephane Chazelas
Stephane Chazelas

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

Related Questions