Thread: Finding nasty bugs

  1. #1
    Registered User
    Join Date
    Feb 2014
    Posts
    2

    Finding nasty bugs

    I am writing firmware for a PIC microcontroller in C. It is about 1000 lines and I am losing hair fast, with bugs that make absolutely no sense. It is difficult to debug because Microchip's simulator is buggy. So I need another way. I need a way of finding bugs such as array OOB and so on.

    Are there any thorough resources on how to look for mistakes in C code?

    For example:

    Code:
    unsigned char c;
    c = 0x55;
    if( ~c == 0xAA){
        // counter-intuitively, this will not get executed!
        // (the result is 0xFFAA on PIC, 0xFFFFFFAA on windows)
    }
    
    I tried using a static analyser, but because the code is for an embedded system, it is a nightmare getting it to parse, there must be an easier way.

    I am considering re-writing it to run on a PC so at least I can run automated tests on the code before porting it for the embedded system. However, the embedded system compiler (XC8) will no doubt have implementation-specifics different to that of a PC (windows) so I may miss some bugs, or even create some extra ones.

    Any advice welcome, even if it's just moral support!!
    Last edited by Jodes; 03-06-2014 at 06:05 AM.

  2. #2
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Well, the first thing I'd ask is if CHAR_BIT == 8. If it's, say, 12 or 16 then I'm not sure your code would work. If ~c == 0xFFAA then I assume that CHAR_BIT must be 16. You can either mask the result
    Code:
    (e.g. if (~c & ~((1 << 8) - 1) == 0xAA) {}  i.e. if (~c & 0xFF == 0xAA) {})
    or... I dunno Out of interest can you #include <limits.h> and printf("%d\n", CHAR_BIT);?

  3. #3
    Registered User
    Join Date
    Feb 2014
    Posts
    2
    Thank you. It's definitely 8. Apparently the reason is due to "Integral Promotion", a standard feature of ANSI C. Basically, ~c gets converted to an int. (Which with the XC 8 compiler is 2 bytes, and on my setup in windows is 4 bytes). I dread to think how many errors like this I'm facing in my code. And this is probably one of the easier bugs to detect if I create automated tests for all my functions!

  4. #4
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Quote Originally Posted by Jodes View Post
    Thank you. It's definitely 8. Apparently the reason is due to "Integral Promotion", a standard feature of ANSI C. Basically, ~c gets converted to an int. (Which with the XC 8 compiler is 2 bytes, and on my setup in windows is 4 bytes). I dread to think how many errors like this I'm facing in my code. And this is probably one of the easier bugs to detect if I create automated tests for all my functions!
    Hmm ok, good point.

    Code:
    #include <stdio.h>
    #include <limits.h>
    
    int main(void)
    {
        unsigned char v = 0xAA;
        printf("bits: %d\n", CHAR_BIT);
        printf("v = %x\n", v);
        printf("~v = %x\n", ~v);
        if (~v == 0x55)
            printf("ok 1\n");
        if (v == ~0x55)
            printf("ok 2\n");
        if ((unsigned char)~v == 0x55)
            printf("ok 3\n");
        
        v = ~v;
        if (v == 0x55)
            printf("ok 4\n");
        
        return 0;
    }
    Code:
    bits: 8
    v = aa
    ~v = ffffff55
    ok 3
    ok 4
    Err, ok...

    Code:
    #include <stdio.h>
    #include <limits.h>
    
    #define CHARMASK ((1 << CHAR_BIT) - 1)
    
    int main(void)
    {
        unsigned char v = 0xAA;
        printf("bits: %d\n", CHAR_BIT);
        printf("v = %x\n", v);
        printf("~v = %x\n", ~v);
        if (~v == 0x55)
            printf("ok 1\n");
        if (v == ~0x55)
            printf("ok 2\n");
        if ((unsigned char)~v == 0x55)
            printf("ok 3\n");
        
    
        printf("Mask is %x\n", CHARMASK);
        if ((~v & CHARMASK) == 0x55)
            printf("Mask ok\n");
        else
            printf("hmm: %x\n", ~v & CHARMASK);
    
        v = ~v;
        if (v == 0x55)
            printf("ok 4\n");
        
        return 0;
    }
    Code:
    bits: 8
    v = aa
    ~v = ffffff55
    ok 3
    Mask is ff
    Mask ok
    ok 4
    I think I'll look at this a bit (hahahah, a "bit"... get it?) tomorrow.
    Last edited by Hodor; 03-06-2014 at 06:36 AM.

  5. #5
    Registered User
    Join Date
    Jun 2011
    Posts
    4,513
    Section 5.6.1 of the XC8 User's Guide talks about integral promotion. The exact behavior of your example in the first post is described there (with an almost identical example) as well as how to work around it:

    Another problem that frequently occurs is with the bitwise compliment operator, ~. This
    operator toggles each bit within a value. Consider the following code.

    Code:
    unsigned char count, c;
    c = 0x55;
    if( ~c == 0xAA)
      count++;
    If c contains the value 0x55, it often assumed that ~c will produce 0xAA; however, the
    result is 0xFFAA and so the comparison in the above example would fail. The compiler
    may be able to issue a mismatched comparison error to this effect in some circumstances.
    Again, a cast could be used to change this behavior.


    It sounds like you might benefit from a complete code re-write. You don't necessarily have to start from scratch - save the code into a text file, start a new project, and begin rebuilding the code piece by piece. Test each piece as much as you can before starting to add more. This might sound like a lot of work, but it would probably be easier than trying to fix 1000+ lines of buggy code.

    If you do a re-write, strive for clear logic and plan the structure of the code carefully. For instance, you mentioned checking for array out-of-bounds conditions. As the programmer, you should ensure that this will not happen. It is always possible that things like this might slip through, but careful coding should reduce the chance of this occurring to a minimum.



    Since you're also willing to accept moral support - you're obviously not alone with issues like this. I recently starting programming with a new device (Silicon Labs) and, after 2000 or so lines of code, starting seeing very strange behavior. The code was interacting with peripheral hardware (EEPROM chip to load and read a LUT). Every other call to the function to read from an EEPROM address yielded incorrect results - in addition, the result of each of those "bad" calls incremented systematically each time it happened. The culprit? I had switched compilers partially through, the first had char unsigned by default, the newer one signed by default, so my masks weren't working correctly. It seemed obvious once I figured it out, but it took many days to isolate the problem. I was not able to step through the debugger during the hardware interaction (since I had to maintain timing for the hardware), so I was not able to find this problem directly. I had to look around "outside" of where the problem was with the debugger, to eventually hone in on the troublesome code.

    I had another problem with the EEPROM - the first call would never work correctly, but all subsequent calls did. Again, it took a day or two of debugging to find the cause of that problem. The "CS~" line had to be brought logic low to initiate a read, then logic high to end the command. When calling my read function, the code cleared this bit, did the read, then set it again. The problem was in my initialization! I accidentally initialized that output to logic low instead of logic high. Therefore, the first call, there was no high-to-low transition on "CS~", and the read failed. But at the end of that first call, "CS~" was set high again, and all subsequent calls worked just fine.

    These two frustrating issues could have been avoided with more careful coding. But they were found by perseverance.
    Last edited by Matticus; 03-06-2014 at 08:21 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Something Nasty
    By string in forum C Programming
    Replies: 4
    Last Post: 06-01-2008, 01:28 PM
  2. Nasty looking thing
    By richard_hooper in forum C Programming
    Replies: 3
    Last Post: 05-27-2005, 09:40 AM
  3. Need help finding bugs
    By Shakti in forum Game Programming
    Replies: 16
    Last Post: 02-13-2005, 01:42 AM
  4. someone who is good at finding and fixing bugs?
    By elfjuice in forum C++ Programming
    Replies: 8
    Last Post: 06-07-2002, 03:59 PM