Thread: Problem with reading/writing in "classic" unix

  1. #1
    Registered User
    Join Date
    Dec 2010
    Posts
    12

    Problem with reading/writing in "classic" unix

    I have some c code that works fine on a unix server (which I have come to understand is based on "System V" unix), but it blows up on my local macbook (which I have come to understand is "classic" unix).

    The purpose of the code is to take a ascii file and form it into a series of structures, then rewrite it to a separate file in binary.

    Code:
    int main( void )
    {
        char filename[10];
        FILE *from, *to;
        char buff[100];
        Class buf;
    
        printf("\nEnter the name of your file: ");
        scanf("%s", filename);
    
        from = fopen(filename, "r");
        if (!from)
            printf("Error opening file\n");
        else
        {
            sprintf(filename, "%s.bn", filename);
            printf("\nCreated File\n");
            to = fopen(filename, "wb");
            if (!to)
                printf("Error opening to file\n");
            else
            {
                while(fgets(buff, sizeof(buff), from) != NULL)
                {
                    if (sscanf(buff, "*format of Class struct*****, etc, etc, etc)) == 21)
                    {
                        fwrite (&buf, 1, sizeof(buf), to);
                    }
                }
                fclose (to);
            }
            fclose (from);
        }
        return 0;
    }
    When I run the program, I get a Bus error.

    When I run the debugger, it says the problem is in the fgets function.

    Code:
    Program received signal EXC_BAD_ACCESS, Could not access memory.
    Reason: KERN_PROTECTION_FAILURE at address: 0x00000038
    0x9008b0e9 in fgets ()

  2. #2
    Registered User
    Join Date
    May 2010
    Location
    Naypyidaw
    Posts
    1,314
    C99 and POSIX.1-2001 specify that the results are undefined if a call
    to sprintf(), snprintf(), vsprintf(), or vsnprintf() would cause to
    copying to take place between objects that overlap (e.g., if the target
    string array and one of the supplied input arguments refer to the same
    buffer). See NOTES.
    Code:
                        fwrite (&buf, 1, sizeof(buf), to); // drop the &
    I'm not quite clear what you're trying to do. Question 2.11
    Have you tried to use debugger???

  3. #3
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Mac is based on BSD, which I don't see how that makes it any more "classic" than System V.

    Anyway, if you're going to use the debugger, then save everybody a lot of pain by compiling your program with the -g flag, so that you get 75000% more information about what's going on, and you can see what the values of the variables are when your program dies, etc.

  4. #4
    Registered User
    Join Date
    Dec 2010
    Posts
    12
    Anyway, if you're going to use the debugger, then save everybody a lot of pain by compiling your program with the -g flag, so that you get 75000% more information about what's going on, and you can see what the values of the variables are when your program dies, etc.
    I'm not too familiar with the debugger. I was using gdb. When I attempted to compile the program using the -g flag, it had the same results (which I pasted before). I'm probably just unfamiliar with the commands to use in gdb.

  5. #5
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    GDB stands for GNU DeBugger, so using gdb is using the debugger, with gdb being the specific debugging tool and debugger being the general term for such a tool. tabstop was saying that using the -g flag when you compile will put file name, line number and symbol names in the file so when it crashes, you can find out exactly what line number and function you were in, and in what file. As a matter of fact, you can see the whole sequence of function calls leading to your crash with the "backtrace" command. It will also allow you to examine the name of some variables at the time it crashed, by doing something like "print foo".

  6. #6
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Once you've compiled with -g, you can type "bt" in the debugger to see the call stack, with line numbers, of where you were in the program and what was what. For instance, if I do a silly little fgets into a NULL pointer, I get something like:
    Code:
    Program received signal SIGSEGV, Segmentation fault.
    _IO_getline_info (fp=0x804b008, buf=0x0, n=98, delim=10, extract_delim=1, 
        eof=0x0) at iogetline.c:91
    91	iogetline.c: No such file or directory.
    	in iogetline.c
    (gdb) bt
    #0  _IO_getline_info (fp=0x804b008, buf=0x0, n=98, delim=10, extract_delim=1, 
        eof=0x0) at iogetline.c:91
    #1  0x0018cf91 in _IO_getline (fp=0x804b008, buf=0x0, n=99, delim=10, 
        extract_delim=1) at iogetline.c:42
    #2  0x0018bf9a in _IO_fgets (buf=0x0, n=100, fp=0x804b008) at iofgets.c:58
    #3  0x0804847b in main () at segfault.c:8
    and you can see at the bottom that we're at line 8 in my program, and that I called fgets with 0, 100, and <some weird file pointer> as the parameters (the next line up) which in turn called other things internally. You can also type "up" to go back through the list and print out variables.

    Also: 0x38 is '8' so it would seem you passed a character where an address was expected.

  7. #7
    Registered User
    Join Date
    Dec 2010
    Posts
    12
    Code:
    (gdb) bt
    #0  0x9008b0e9 in fgets ()
    #1  0x00001f3b in main () at ClassRPG.c:77
    Only two lines it shows...

    How do I do the backtrace?

  8. #8
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    With the "backtrace" command I mentioned, or "bt" for short, as tabstop showed. You just did it.

  9. #9
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Since your sample code only has 35 lines, clearly we can't help you locate the problem on line 77, but you certainly know where to start looking now. Post up that line with any relevant variable declarations. If you call fgets(buf, sizeof(buf), fp), let's see the definition of buf and fp.

  10. #10
    Registered User
    Join Date
    Feb 2003
    Posts
    596
    Sorry if this is too simple, but are you sure that "from" and "to" are actually different files?

    Before knocking yourself out with the debugger, have you checked the result of your sprintf statement, e.g.:
    Code:
    sprintf(filename, "%s.bn", filename);
    printf("\nCreated File %s\n", filename);

  11. #11
    Registered User
    Join Date
    Dec 2010
    Posts
    12
    Line 77 is this:
    Code:
                 while(fgets(buff, sizeof(buff), from) != NULL)
    The file I am using is called "Classes". It is a series of numbers and letters like this:

    Code:
    1  5  5  1  5  8  5  8  5  9  5  15 10 0  0  7  1  0  7  8  Squire
    2  7  10 2  6  12 8  9  8  10 8  20 16 0  0  7  1  0  9  10 Warrior
    After running my program, it is supposed to convert this text file to a series of structures of type "Class". When I run it on the unix server, it works appropriately and creates a file called "Classes.bn" that can then be used by a different program of mine. When I run it on the macbook, it does create the "Classes.bn" file, but blows up with the error as I show above. The Classes.bn file is empty.

  12. #12
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    R.Stiltskin's has a point, the problem is with your sprintf. filename is too short for "Classes.bn" since you have 10 plus the null. Thus, your sprintf is overflowing one byte into your from FILE pointer, trampling on it and causing your problem. Aside from that, the standard says (section 7.19.6.6, paragraph 2), that behavior is undefined when copying takes place between objects that overlap, as in your case where you copy from and to the same buffer. Create a second buffer for to_filename, and make sure it's big enough for your whole filename plus a null.

  13. #13
    Registered User
    Join Date
    Dec 2010
    Posts
    12
    Thanks! By having a second buffer with to_filename and having it be long enough for the whole filename plus a null, it works!

    I'm not sure why it worked the other way on the unix server, but I'm going to update the code so it works on both.

  14. #14
    Registered User
    Join Date
    Sep 2010
    Posts
    25

    Kernel Protection Failure

    That type of error, Bad Access, is part of the protections built into your MacBook to keep you from over-riding the programs which keep the Mac running.

    You could otherwise write over the top of essential parts of the memory.

    Without Bad Access built into the system, how would you keep a user from programming the computer into breaking itself?

    For example, if you have XCode installed, you can poke around in the library that comes with XCode, calling the individual files and reading them, and see how some areas of the memory are cordoned off. The comments in those files explained several examples of this to me, but I cannot honestly remember the path to lookup. I did see it as a trend, occurring in several places.

    A common place for those kinds of files to be would be in the "Developer" path; SDK, usr, include: I list the common names instead of the file paths because the .h files will not be strictly stored in one place, but in those general areas. I also don't remember the exact wording of the default path.

    Well, in C, you could over-write a bunch of stuff if the computer let you on the first pass. As in, you could write to memory in such a way as to squelch or jam an important file on the system.

    That error, Bad Access, and some of its cousins, is apparently about preventing that activity.

    There's a similar form of protection in Python for the GUI (it's often got to run in IDLE); and, Perl-related protections for the on-board web server that works with the directory (I forget the specifics, but remember encountering some scripting trouble with where to put certain files in Apache-related programs). If the Mac needs it to keep the OS stable or user side of things appearing in a consistent way, they've probably built a limit on that part of the memory.

    An OS would use a lot of C. The programs which come with the computer would be written in C (or one of its daughter languages). The GUI would be done up in Python. The networking and directory items would rely heavily on Perl. All of the tools which would seem to be good choices are probably the tools which would be used in the Mac for that task. As a supporting constraint, those places in memory would all need to be protected.

    If there's no barrier, then a beginning programmer could just write right over the top of the storage of an important program, just as he would write to that spot on a naked computer with little or nothing in its memories. I generalize, but notice that there are who knows how many subdivisions of the memory chips (and many chips of different kinds); each kind of memory would have its own uses and constraints; next thing you know, it's time to build a file or program that'll keep later users from undoing the work that it took to build the system.

    Voila! Bad Access Errors and their supporting plans.

    Effectively, you've got a great computer with so many possibilities that they have to put some limits up, or a programmer can step all over the system he's using.

    It's there so that you don't break the system. There's nothing inherently wrong with your program as a stand-alone item; it's also not likely to be specific to POSIX or System V differences. POSIX/System V differences are more likely to be related to syntax or available commands or common file structures. I suspect that you received this kind of error on one computer and not another because the limiting Access plan might be specific to the hardware of the machine. The other computer may have just such a file or program, but have it built differently; as a result of the differences, I'd deduce that maybe that's why you didn't encounter it before.

    Well, this is what I concluded after running into some similar Bad Access errors some time ago; between those errors and reading the header files and libraries, that was the answer I came up with. At least that might hold for why you can or cannot access certain parts of the memory.

    The Kern Protections: you can see those ideas explained, above. Kern means "cut". A Kerning is a cutting or trimming: a Kern Protection Error would be an error that prevents or regulates the method of cutting: as described above, one of the last values was getting cut off by having it stored in memory in the wrong kind of way.

    Well, I don't know much about it, but those were some of the ideas I concluded about memory protection from some problems I had before.
    Last edited by agxphoto; 01-02-2011 at 08:55 AM. Reason: Bad Access/Kern description

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. WS_POPUP, continuation of old problem
    By blurrymadness in forum Windows Programming
    Replies: 1
    Last Post: 04-20-2007, 06:54 PM
  2. Datagram Unix socket problem
    By karas in forum C Programming
    Replies: 9
    Last Post: 07-27-2006, 10:08 AM
  3. Laptop Problem
    By Boomba in forum Tech Board
    Replies: 1
    Last Post: 03-07-2006, 06:24 PM
  4. Replies: 5
    Last Post: 11-07-2005, 11:34 PM
  5. half ADT (nested struct) problem...
    By CyC|OpS in forum C Programming
    Replies: 1
    Last Post: 10-26-2002, 08:37 AM